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