| 1 | [ |
| 2 | "autonomous agent", |
| 3 | { |
| 4 | "doc_url": "https://obyte.org/token-registry.json", |
| 5 | "init": "{ |
| 6 | $challenging_period = 30*24*3600; |
| 7 | $grace_period = 30*24*3600; |
| 8 | $overwhelming_multiplier = 5; |
| 9 | $min_amount = 1e8; |
| 10 | |
| 11 | $amount = trigger.output[[asset=base]]; |
| 12 | |
| 13 | $drawer = trigger.data.drawer OTHERWISE 0; |
| 14 | if (!is_integer($drawer)) |
| 15 | bounce("drawer must be integer"); |
| 16 | if ($drawer != 0 AND $drawer != 1 AND $drawer != 7 AND $drawer != 30 AND $drawer != 90 AND $drawer != 180 AND $drawer != 360) |
| 17 | bounce("bad drawer: " || $drawer); |
| 18 | |
| 19 | $symbol = trigger.data.symbol; |
| 20 | if ($symbol){ |
| 21 | if (typeof($symbol) != 'string') |
| 22 | bounce("symbol must be string"); |
| 23 | if ($symbol != to_upper($symbol)) |
| 24 | bounce("symbol must be uppercase"); |
| 25 | if (length($symbol) > 40) |
| 26 | bounce("symbol must be max 40 characters long"); |
| 27 | if ($symbol == 'GBYTE' OR $symbol == 'MBYTE' OR $symbol == 'KBYTE' OR $symbol == 'BYTE' OR $symbol == 'TBYTE') |
| 28 | bounce("reserved symbol"); |
| 29 | } |
| 30 | |
| 31 | $description = trigger.data.description; |
| 32 | if ($description){ |
| 33 | if (typeof($description) != 'string') |
| 34 | bounce("description must be string"); |
| 35 | if (length($description) > 140) |
| 36 | bounce("description must be max 140 characters long"); |
| 37 | } |
| 38 | |
| 39 | $decimals = trigger.data.decimals; |
| 40 | if (exists($decimals)){ |
| 41 | if (!is_integer($decimals)) |
| 42 | bounce("decimals must be integer"); |
| 43 | if ($decimals < 0 OR $decimals > 15) |
| 44 | bounce("decimals must be between 0 and 15"); |
| 45 | } |
| 46 | |
| 47 | $asset = trigger.data.asset; |
| 48 | if ($asset){ |
| 49 | if (typeof($asset) != 'string') |
| 50 | bounce("asset must be string"); |
| 51 | if (!asset[$asset].exists) |
| 52 | bounce("asset " || $asset || " does not exist"); |
| 53 | } |
| 54 | }", |
| 55 | "messages": { |
| 56 | "cases": [ |
| 57 | { |
| 58 | "if": "{ trigger.data.withdraw AND trigger.data.amount AND $asset AND $symbol }", |
| 59 | "init": "{ |
| 60 | $drawer_key = trigger.address || '_' || $drawer || '_' || $symbol || '_' || $asset; |
| 61 | if (var[$drawer_key] < trigger.data.amount) |
| 62 | bounce("not enough funds in this drawer"); |
| 63 | if ($drawer){ |
| 64 | $expiry_ts = var[$drawer_key || '_expiry_ts']; |
| 65 | if ($expiry_ts AND timestamp < $expiry_ts) |
| 66 | bounce("warm-up period has not expired yet"); |
| 67 | $allowed = !!$expiry_ts; |
| 68 | } |
| 69 | else |
| 70 | $allowed = true; |
| 71 | }", |
| 72 | "messages": [ |
| 73 | { |
| 74 | "if": "{$allowed}", |
| 75 | "app": "payment", |
| 76 | "payload": { |
| 77 | "outputs": [ |
| 78 | { |
| 79 | "address": "{trigger.address}", |
| 80 | "amount": "{trigger.data.amount}" |
| 81 | } |
| 82 | ] |
| 83 | } |
| 84 | }, |
| 85 | { |
| 86 | "app": "state", |
| 87 | "state": "{ |
| 88 | if ($allowed){ |
| 89 | var[$drawer_key] -= trigger.data.amount; |
| 90 | if ($drawer) |
| 91 | var[$drawer_key || '_expiry_ts'] = false; |
| 92 | var['support_' || $symbol || '_' || $asset] -= trigger.data.amount; |
| 93 | var['balance_' || trigger.address || '_' || $asset] -= trigger.data.amount; |
| 94 | $desc_hash = var['desc_choice_' || $asset || '_' || trigger.address]; |
| 95 | if ($desc_hash) |
| 96 | var['desc_support_' || $asset || '_' || $desc_hash] -= trigger.data.amount; |
| 97 | } |
| 98 | else if (!$expiry_ts) |
| 99 | var[$drawer_key || '_expiry_ts'] = timestamp + $drawer * 24 * 3600; |
| 100 | }" |
| 101 | } |
| 102 | ] |
| 103 | }, |
| 104 | { |
| 105 | "if": "{$description AND exists($decimals) AND ($asset OR $symbol) AND $amount < $min_amount}", |
| 106 | "init": "{ |
| 107 | if ($asset){ |
| 108 | $voted_asset = $asset; |
| 109 | $voted_symbol = var['a2s_' || $voted_asset]; |
| 110 | } |
| 111 | else { |
| 112 | $voted_asset = var['s2a_' || $symbol]; |
| 113 | if (!$voted_asset) |
| 114 | bounce("no asset found by symbol " || $symbol); |
| 115 | $voted_symbol = $symbol; |
| 116 | } |
| 117 | $balance = var['balance_' || trigger.address || '_' || $voted_asset]; |
| 118 | if (!$balance) |
| 119 | bounce("you have no balance in this asset"); |
| 120 | |
| 121 | $desc_hash = sha256($description || $decimals); |
| 122 | $current_my_desc_hash = var['desc_choice_' || $voted_asset || '_' || trigger.address]; |
| 123 | $current_desc_hash = var['current_desc_' || $voted_asset]; |
| 124 | $is_initial_desc = !$current_desc_hash; |
| 125 | if ($is_initial_desc) |
| 126 | $current_desc_changed = true; |
| 127 | else if ($desc_hash != $current_desc_hash){ |
| 128 | $new_desc_support = var['desc_support_' || $voted_asset || '_' || $desc_hash] + $balance; |
| 129 | $is_removed_support_from_current_desc = ($current_my_desc_hash AND $current_my_desc_hash == $current_desc_hash); |
| 130 | $current_desc_support = var['desc_support_' || $voted_asset || '_' || $current_desc_hash] - $is_removed_support_from_current_desc * $balance; |
| 131 | $current_desc_changed = ($new_desc_support > $current_desc_support); |
| 132 | } |
| 133 | if ($current_desc_changed AND !$is_initial_desc){ |
| 134 | $current_decimals = var['decimals_' || $current_desc_hash]; |
| 135 | $decimals_changed = ($decimals != $current_decimals); |
| 136 | } |
| 137 | }", |
| 138 | "messages": [ |
| 139 | { |
| 140 | "if": "{ ($is_initial_desc OR $decimals_changed) AND $voted_symbol }", |
| 141 | "app": "data", |
| 142 | "payload": { |
| 143 | "asset": "{$voted_asset}", |
| 144 | "name": "{$voted_symbol}", |
| 145 | "decimals": "{$decimals}" |
| 146 | } |
| 147 | }, |
| 148 | { |
| 149 | "app": "state", |
| 150 | "state": "{ |
| 151 | if (!var['desc_' || $desc_hash]){ |
| 152 | var['desc_' || $desc_hash] = $description; |
| 153 | var['decimals_' || $desc_hash] = $decimals; |
| 154 | } |
| 155 | if ($current_my_desc_hash) |
| 156 | var['desc_support_' || $voted_asset || '_' || $current_my_desc_hash] -= $balance; |
| 157 | var['desc_choice_' || $voted_asset || '_' || trigger.address] = $desc_hash; |
| 158 | var['desc_support_' || $voted_asset || '_' || $desc_hash] += $balance; |
| 159 | if ($current_desc_changed){ |
| 160 | var['current_desc_' || $voted_asset] = $desc_hash; |
| 161 | response['updated_support'] = var['desc_support_' || $voted_asset || '_' || $desc_hash]; |
| 162 | response['message'] = "Your description is now the current"; |
| 163 | } |
| 164 | }" |
| 165 | } |
| 166 | ] |
| 167 | }, |
| 168 | { |
| 169 | "if": "{trigger.data.move AND trigger.data.address AND $drawer AND $asset AND $symbol}", |
| 170 | "init": "{ |
| 171 | $drawer_key = trigger.data.address || '_' || $drawer || '_' || $symbol || '_' || $asset; |
| 172 | $balance = var[$drawer_key]; |
| 173 | if (!$balance) |
| 174 | bounce("nothing in this drawer"); |
| 175 | $expiry_ts = var[$drawer_key || '_expiry_ts']; |
| 176 | if (!$expiry_ts) |
| 177 | bounce("warm-up period has not started yet"); |
| 178 | if (timestamp < $expiry_ts) |
| 179 | bounce("warm-up period has not expired yet"); |
| 180 | $drawer_0_key = trigger.data.address || '_0_' || $symbol || '_' || $asset; |
| 181 | }", |
| 182 | "messages": [ |
| 183 | { |
| 184 | "app": "state", |
| 185 | "state": "{ |
| 186 | var[$drawer_key] = false; |
| 187 | var[$drawer_0_key] += $balance; |
| 188 | var[$drawer_key || '_expiry_ts'] = false; |
| 189 | response['message'] = "Moved " || $balance || " to drawer 0"; |
| 190 | }" |
| 191 | } |
| 192 | ] |
| 193 | }, |
| 194 | { |
| 195 | "if": "{$amount >= $min_amount AND $symbol AND $asset }", |
| 196 | "init": "{ |
| 197 | $support = var['support_' || $symbol || '_' || $asset] + $amount; |
| 198 | |
| 199 | $current_asset = var['s2a_' || $symbol]; |
| 200 | $current_symbol = var['a2s_' || $asset]; |
| 201 | $current_asset_with_largest_support = var['by_largest_s2a_' || $symbol]; |
| 202 | $current_symbol_with_largest_support = var['by_largest_a2s_' || $asset]; |
| 203 | if ($current_asset AND !$current_asset_with_largest_support) |
| 204 | bounce("no current asset by largest support?"); |
| 205 | if ($current_symbol AND !$current_symbol_with_largest_support) |
| 206 | bounce("no current symbol by largest support?"); |
| 207 | |
| 208 | |
| 209 | if (!$current_asset_with_largest_support OR $current_asset_with_largest_support != $asset AND var['support_' || $symbol || '_' || $current_asset_with_largest_support] < $support) |
| 210 | $update_by_largest_s2a = true; |
| 211 | $symbol_challenge_expiry_ts = var['expiry_ts_' || $symbol]; |
| 212 | if (!$current_asset){ |
| 213 | $s2a_ready = true; |
| 214 | } |
| 215 | else if ($current_asset != $asset AND var['support_' || $symbol || '_' || $current_asset] < $support){ |
| 216 | if (!$symbol_challenge_expiry_ts) |
| 217 | $schedule_symbol_expiry = true; |
| 218 | else if (timestamp > $symbol_challenge_expiry_ts AND var['by_largest_s2a_' || $symbol] == $asset){ |
| 219 | $s2a_ready = true; |
| 220 | } |
| 221 | } |
| 222 | else if ($current_asset == $asset AND var['by_largest_s2a_' || $symbol] == $asset AND $symbol_challenge_expiry_ts AND timestamp > $symbol_challenge_expiry_ts) |
| 223 | $end_symbol_expiry = true; |
| 224 | |
| 225 | |
| 226 | if (!$current_symbol_with_largest_support OR $current_symbol_with_largest_support != $symbol AND var['support_' || $current_symbol_with_largest_support || '_' || $asset] < $support) |
| 227 | $update_by_largest_a2s = true; |
| 228 | $asset_challenge_expiry_ts = var['expiry_ts_' || $asset]; |
| 229 | $current_symbol_support = var['support_' || $current_symbol || '_' || $asset]; |
| 230 | if (!$current_symbol){ |
| 231 | $a2s_ready = true; |
| 232 | } |
| 233 | else if ($current_symbol != $symbol AND $current_symbol_support < $support){ |
| 234 | $has_largest_support = ($current_symbol_with_largest_support == $symbol); |
| 235 | $will_have_largest_support = ($has_largest_support OR $update_by_largest_a2s); |
| 236 | $has_overwhelming_support = ($support > $overwhelming_multiplier * $current_symbol_support); |
| 237 | $immediate = $will_have_largest_support AND $has_overwhelming_support AND timestamp < var['grace_expiry_ts_' || $asset]; |
| 238 | if (!$asset_challenge_expiry_ts){ |
| 239 | if ($immediate){ |
| 240 | $a2s_ready = true; |
| 241 | } |
| 242 | else |
| 243 | $schedule_asset_expiry = true; |
| 244 | } |
| 245 | else if ((timestamp > $asset_challenge_expiry_ts OR $immediate) AND $has_largest_support){ |
| 246 | $a2s_ready = true; |
| 247 | } |
| 248 | } |
| 249 | else if ($current_symbol == $symbol AND $current_symbol_with_largest_support == $symbol AND $asset_challenge_expiry_ts AND timestamp > $asset_challenge_expiry_ts) |
| 250 | $end_asset_expiry = true; |
| 251 | |
| 252 | if ($s2a_ready AND $a2s_ready){ |
| 253 | if (!$current_asset AND !$current_symbol AND exists($decimals) AND $description){ |
| 254 | $initial_desc_hash = sha256($description || $decimals); |
| 255 | $current_decimals = $decimals; |
| 256 | } |
| 257 | else { |
| 258 | $current_desc_hash = var['current_desc_' || $asset]; |
| 259 | if ($current_desc_hash) |
| 260 | $current_decimals = var['decimals_' || $current_desc_hash]; |
| 261 | } |
| 262 | } |
| 263 | }", |
| 264 | "messages": [ |
| 265 | { |
| 266 | "if": "{$s2a_ready AND $a2s_ready AND exists($current_decimals)}", |
| 267 | "app": "data", |
| 268 | "payload": { |
| 269 | "asset": "{$asset}", |
| 270 | "name": "{$symbol}", |
| 271 | "decimals": "{$current_decimals}" |
| 272 | } |
| 273 | }, |
| 274 | { |
| 275 | "app": "state", |
| 276 | "state": "{ |
| 277 | var['support_' || $symbol || '_' || $asset] = $support; |
| 278 | |
| 279 | |
| 280 | if ($update_by_largest_s2a) |
| 281 | var['by_largest_s2a_' || $symbol] = $asset; |
| 282 | if ($schedule_symbol_expiry) |
| 283 | var['expiry_ts_' || $symbol] = timestamp + $challenging_period; |
| 284 | if ($end_symbol_expiry) |
| 285 | var['expiry_ts_' || $symbol] = false; |
| 286 | |
| 287 | |
| 288 | if ($update_by_largest_a2s) |
| 289 | var['by_largest_a2s_' || $asset] = $symbol; |
| 290 | if ($schedule_asset_expiry) |
| 291 | var['expiry_ts_' || $asset] = timestamp + $challenging_period; |
| 292 | if ($end_asset_expiry) |
| 293 | var['expiry_ts_' || $asset] = false; |
| 294 | |
| 295 | |
| 296 | if ($s2a_ready AND $a2s_ready){ |
| 297 | |
| 298 | if ($current_asset) |
| 299 | var['a2s_' || $current_asset] = false; |
| 300 | if ($current_symbol) |
| 301 | var['s2a_' || $current_symbol] = false; |
| 302 | |
| 303 | var['s2a_' || $symbol] = $asset; |
| 304 | var['a2s_' || $asset] = $symbol; |
| 305 | response[$symbol] = $asset; |
| 306 | response[$asset] = $symbol; |
| 307 | if ($symbol_challenge_expiry_ts) |
| 308 | var['expiry_ts_' || $symbol] = false; |
| 309 | if ($asset_challenge_expiry_ts) |
| 310 | var['expiry_ts_' || $asset] = false; |
| 311 | if (!var['grace_expiry_ts_' || $asset]) |
| 312 | var['grace_expiry_ts_' || $asset] = timestamp + $grace_period; |
| 313 | } |
| 314 | |
| 315 | $drawer_key = trigger.address || '_' || $drawer || '_' || $symbol || '_' || $asset; |
| 316 | var[$drawer_key] += $amount; |
| 317 | response[$drawer_key] = $amount; |
| 318 | if ($drawer) |
| 319 | var[$drawer_key || '_expiry_ts'] = false; |
| 320 | var['balance_' || trigger.address || '_' || $asset] += $amount; |
| 321 | |
| 322 | $desc_hash = var['desc_choice_' || $asset || '_' || trigger.address]; |
| 323 | if ($desc_hash) |
| 324 | var['desc_support_' || $asset || '_' || $desc_hash] += $amount; |
| 325 | |
| 326 | if ($initial_desc_hash){ |
| 327 | if (!var['desc_' || $initial_desc_hash]){ |
| 328 | var['desc_' || $initial_desc_hash] = $description; |
| 329 | var['decimals_' || $initial_desc_hash] = $decimals; |
| 330 | } |
| 331 | var['desc_choice_' || $asset || '_' || trigger.address] = $initial_desc_hash; |
| 332 | var['desc_support_' || $asset || '_' || $initial_desc_hash] = $amount; |
| 333 | var['current_desc_' || $asset] = $initial_desc_hash; |
| 334 | response['message'] = "Your description is now the current"; |
| 335 | } |
| 336 | }" |
| 337 | } |
| 338 | ] |
| 339 | } |
| 340 | ] |
| 341 | } |
| 342 | } |
| 343 | ] |