├── .gitignore ├── calc-apr.py ├── config.py ├── curvestats-averages.py ├── curvestats-monitor.py ├── curvestats ├── __init__.py ├── aave_pool.py ├── abi.py ├── ankr.py ├── btc.py ├── compound.py ├── icy.py ├── idle.py ├── meta.py ├── metaf.py ├── newpool.py ├── rai.py ├── reth.py ├── susd.py ├── y.py └── yv2.py ├── export-json.py ├── plot.py ├── requirements.txt ├── stats.py └── test_libstats.py /.gitignore: -------------------------------------------------------------------------------- 1 | /.venv 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /calc-apr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | 5 | data = [] 6 | 7 | with open('swap-stats.csv', 'r') as f: 8 | reader = csv.reader(f) 9 | next(reader) # Omit header 10 | for row in reader: 11 | data.append((int(row[0]), float(row[1]))) 12 | 13 | start, p0 = data[0] 14 | end, p1 = data[-1] 15 | 16 | APR = (p1 / p0) ** (86400 * 365 / (end - start)) - 1 17 | 18 | print(APR) 19 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | # SWAP_ADDRESS = "0xe5FdBab9Ad428bBB469Dee4CB6608C0a8895CbA5" 4 | # TOKEN_ADDRESS = "0xDBe281E17540Da5305Eb2AeFB8CeF70E6dB1A0A9" 5 | 6 | SWAP_ADDRESS = "0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56" 7 | TOKEN_ADDRESS = "0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2" 8 | 9 | SWAP_ABI = json.loads("""[ 10 | { 11 | "name": "TokenExchange", 12 | "inputs": [ 13 | { 14 | "type": "address", 15 | "name": "buyer", 16 | "indexed": true 17 | }, 18 | { 19 | "type": "int128", 20 | "name": "sold_id", 21 | "indexed": false 22 | }, 23 | { 24 | "type": "uint256", 25 | "name": "tokens_sold", 26 | "indexed": false 27 | }, 28 | { 29 | "type": "int128", 30 | "name": "bought_id", 31 | "indexed": false 32 | }, 33 | { 34 | "type": "uint256", 35 | "name": "tokens_bought", 36 | "indexed": false 37 | }, 38 | { 39 | "type": "uint256", 40 | "name": "fee", 41 | "indexed": false 42 | } 43 | ], 44 | "anonymous": false, 45 | "type": "event" 46 | }, 47 | { 48 | "name": "AddLiquidity", 49 | "inputs": [ 50 | { 51 | "type": "address", 52 | "name": "provider", 53 | "indexed": true 54 | }, 55 | { 56 | "type": "uint256[2]", 57 | "name": "token_amounts", 58 | "indexed": false 59 | } 60 | ], 61 | "anonymous": false, 62 | "type": "event" 63 | }, 64 | { 65 | "name": "RemoveLiquidity", 66 | "inputs": [ 67 | { 68 | "type": "address", 69 | "name": "provider", 70 | "indexed": true 71 | }, 72 | { 73 | "type": "uint256[2]", 74 | "name": "token_amounts", 75 | "indexed": false 76 | }, 77 | { 78 | "type": "uint256[2]", 79 | "name": "fees", 80 | "indexed": false 81 | } 82 | ], 83 | "anonymous": false, 84 | "type": "event" 85 | }, 86 | { 87 | "name": "CommitNewAdmin", 88 | "inputs": [ 89 | { 90 | "type": "uint256", 91 | "name": "deadline", 92 | "indexed": true, 93 | "unit": "sec" 94 | }, 95 | { 96 | "type": "address", 97 | "name": "admin", 98 | "indexed": true 99 | } 100 | ], 101 | "anonymous": false, 102 | "type": "event" 103 | }, 104 | { 105 | "name": "NewAdmin", 106 | "inputs": [ 107 | { 108 | "type": "address", 109 | "name": "admin", 110 | "indexed": true 111 | } 112 | ], 113 | "anonymous": false, 114 | "type": "event" 115 | }, 116 | { 117 | "name": "CommitNewParameters", 118 | "inputs": [ 119 | { 120 | "type": "uint256", 121 | "name": "deadline", 122 | "indexed": true, 123 | "unit": "sec" 124 | }, 125 | { 126 | "type": "int128", 127 | "name": "A", 128 | "indexed": false 129 | }, 130 | { 131 | "type": "int128", 132 | "name": "fee", 133 | "indexed": false 134 | }, 135 | { 136 | "type": "int128", 137 | "name": "admin_fee", 138 | "indexed": false 139 | } 140 | ], 141 | "anonymous": false, 142 | "type": "event" 143 | }, 144 | { 145 | "name": "NewParameters", 146 | "inputs": [ 147 | { 148 | "type": "int128", 149 | "name": "A", 150 | "indexed": false 151 | }, 152 | { 153 | "type": "int128", 154 | "name": "fee", 155 | "indexed": false 156 | }, 157 | { 158 | "type": "int128", 159 | "name": "admin_fee", 160 | "indexed": false 161 | } 162 | ], 163 | "anonymous": false, 164 | "type": "event" 165 | }, 166 | { 167 | "outputs": [], 168 | "inputs": [ 169 | { 170 | "type": "address[2]", 171 | "name": "_coins" 172 | }, 173 | { 174 | "type": "address[2]", 175 | "name": "_underlying_coins" 176 | }, 177 | { 178 | "type": "address", 179 | "name": "_pool_token" 180 | }, 181 | { 182 | "type": "int128", 183 | "name": "_A" 184 | }, 185 | { 186 | "type": "int128", 187 | "name": "_fee" 188 | } 189 | ], 190 | "constant": false, 191 | "payable": false, 192 | "type": "constructor" 193 | }, 194 | { 195 | "name": "get_virtual_price", 196 | "outputs": [ 197 | { 198 | "type": "uint256", 199 | "name": "out" 200 | } 201 | ], 202 | "inputs": [], 203 | "constant": true, 204 | "payable": false, 205 | "type": "function", 206 | "gas": 1069395 207 | }, 208 | { 209 | "name": "add_liquidity", 210 | "outputs": [], 211 | "inputs": [ 212 | { 213 | "type": "uint256[2]", 214 | "name": "amounts" 215 | }, 216 | { 217 | "type": "uint256", 218 | "unit": "sec", 219 | "name": "deadline" 220 | } 221 | ], 222 | "constant": false, 223 | "payable": false, 224 | "type": "function", 225 | "gas": 2258504 226 | }, 227 | { 228 | "name": "get_dy", 229 | "outputs": [ 230 | { 231 | "type": "uint256", 232 | "name": "out" 233 | } 234 | ], 235 | "inputs": [ 236 | { 237 | "type": "int128", 238 | "name": "i" 239 | }, 240 | { 241 | "type": "int128", 242 | "name": "j" 243 | }, 244 | { 245 | "type": "uint256", 246 | "name": "dx" 247 | } 248 | ], 249 | "constant": true, 250 | "payable": false, 251 | "type": "function", 252 | "gas": 2527952 253 | }, 254 | { 255 | "name": "get_dy_underlying", 256 | "outputs": [ 257 | { 258 | "type": "uint256", 259 | "name": "out" 260 | } 261 | ], 262 | "inputs": [ 263 | { 264 | "type": "int128", 265 | "name": "i" 266 | }, 267 | { 268 | "type": "int128", 269 | "name": "j" 270 | }, 271 | { 272 | "type": "uint256", 273 | "name": "dx" 274 | } 275 | ], 276 | "constant": true, 277 | "payable": false, 278 | "type": "function", 279 | "gas": 2527921 280 | }, 281 | { 282 | "name": "exchange", 283 | "outputs": [], 284 | "inputs": [ 285 | { 286 | "type": "int128", 287 | "name": "i" 288 | }, 289 | { 290 | "type": "int128", 291 | "name": "j" 292 | }, 293 | { 294 | "type": "uint256", 295 | "name": "dx" 296 | }, 297 | { 298 | "type": "uint256", 299 | "name": "min_dy" 300 | }, 301 | { 302 | "type": "uint256", 303 | "unit": "sec", 304 | "name": "deadline" 305 | } 306 | ], 307 | "constant": false, 308 | "payable": false, 309 | "type": "function", 310 | "gas": 5167089 311 | }, 312 | { 313 | "name": "exchange_underlying", 314 | "outputs": [], 315 | "inputs": [ 316 | { 317 | "type": "int128", 318 | "name": "i" 319 | }, 320 | { 321 | "type": "int128", 322 | "name": "j" 323 | }, 324 | { 325 | "type": "uint256", 326 | "name": "dx" 327 | }, 328 | { 329 | "type": "uint256", 330 | "name": "min_dy" 331 | }, 332 | { 333 | "type": "uint256", 334 | "unit": "sec", 335 | "name": "deadline" 336 | } 337 | ], 338 | "constant": false, 339 | "payable": false, 340 | "type": "function", 341 | "gas": 5177748 342 | }, 343 | { 344 | "name": "remove_liquidity", 345 | "outputs": [], 346 | "inputs": [ 347 | { 348 | "type": "uint256", 349 | "name": "_amount" 350 | }, 351 | { 352 | "type": "uint256", 353 | "unit": "sec", 354 | "name": "deadline" 355 | }, 356 | { 357 | "type": "uint256[2]", 358 | "name": "min_amounts" 359 | } 360 | ], 361 | "constant": false, 362 | "payable": false, 363 | "type": "function", 364 | "gas": 146036 365 | }, 366 | { 367 | "name": "remove_liquidity_imbalance", 368 | "outputs": [], 369 | "inputs": [ 370 | { 371 | "type": "uint256[2]", 372 | "name": "amounts" 373 | }, 374 | { 375 | "type": "uint256", 376 | "unit": "sec", 377 | "name": "deadline" 378 | } 379 | ], 380 | "constant": false, 381 | "payable": false, 382 | "type": "function", 383 | "gas": 2327978 384 | }, 385 | { 386 | "name": "commit_new_parameters", 387 | "outputs": [], 388 | "inputs": [ 389 | { 390 | "type": "int128", 391 | "name": "amplification" 392 | }, 393 | { 394 | "type": "int128", 395 | "name": "new_fee" 396 | }, 397 | { 398 | "type": "int128", 399 | "name": "new_admin_fee" 400 | } 401 | ], 402 | "constant": false, 403 | "payable": false, 404 | "type": "function", 405 | "gas": 144817 406 | }, 407 | { 408 | "name": "apply_new_parameters", 409 | "outputs": [], 410 | "inputs": [], 411 | "constant": false, 412 | "payable": false, 413 | "type": "function", 414 | "gas": 129762 415 | }, 416 | { 417 | "name": "revert_new_parameters", 418 | "outputs": [], 419 | "inputs": [], 420 | "constant": false, 421 | "payable": false, 422 | "type": "function", 423 | "gas": 21085 424 | }, 425 | { 426 | "name": "commit_transfer_ownership", 427 | "outputs": [], 428 | "inputs": [ 429 | { 430 | "type": "address", 431 | "name": "_owner" 432 | } 433 | ], 434 | "constant": false, 435 | "payable": false, 436 | "type": "function", 437 | "gas": 73162 438 | }, 439 | { 440 | "name": "apply_transfer_ownership", 441 | "outputs": [], 442 | "inputs": [], 443 | "constant": false, 444 | "payable": false, 445 | "type": "function", 446 | "gas": 58018 447 | }, 448 | { 449 | "name": "revert_transfer_ownership", 450 | "outputs": [], 451 | "inputs": [], 452 | "constant": false, 453 | "payable": false, 454 | "type": "function", 455 | "gas": 21175 456 | }, 457 | { 458 | "name": "withdraw_admin_fees", 459 | "outputs": [], 460 | "inputs": [], 461 | "constant": false, 462 | "payable": false, 463 | "type": "function", 464 | "gas": 9403 465 | }, 466 | { 467 | "name": "coins", 468 | "outputs": [ 469 | { 470 | "type": "address", 471 | "name": "out" 472 | } 473 | ], 474 | "inputs": [ 475 | { 476 | "type": "int128", 477 | "name": "arg0" 478 | } 479 | ], 480 | "constant": true, 481 | "payable": false, 482 | "type": "function", 483 | "gas": 1380 484 | }, 485 | { 486 | "name": "underlying_coins", 487 | "outputs": [ 488 | { 489 | "type": "address", 490 | "name": "out" 491 | } 492 | ], 493 | "inputs": [ 494 | { 495 | "type": "int128", 496 | "name": "arg0" 497 | } 498 | ], 499 | "constant": true, 500 | "payable": false, 501 | "type": "function", 502 | "gas": 1410 503 | }, 504 | { 505 | "name": "balances", 506 | "outputs": [ 507 | { 508 | "type": "uint256", 509 | "name": "out" 510 | } 511 | ], 512 | "inputs": [ 513 | { 514 | "type": "int128", 515 | "name": "arg0" 516 | } 517 | ], 518 | "constant": true, 519 | "payable": false, 520 | "type": "function", 521 | "gas": 1440 522 | }, 523 | { 524 | "name": "A", 525 | "outputs": [ 526 | { 527 | "type": "int128", 528 | "name": "out" 529 | } 530 | ], 531 | "inputs": [], 532 | "constant": true, 533 | "payable": false, 534 | "type": "function", 535 | "gas": 1271 536 | }, 537 | { 538 | "name": "fee", 539 | "outputs": [ 540 | { 541 | "type": "int128", 542 | "name": "out" 543 | } 544 | ], 545 | "inputs": [], 546 | "constant": true, 547 | "payable": false, 548 | "type": "function", 549 | "gas": 1301 550 | }, 551 | { 552 | "name": "admin_fee", 553 | "outputs": [ 554 | { 555 | "type": "int128", 556 | "name": "out" 557 | } 558 | ], 559 | "inputs": [], 560 | "constant": true, 561 | "payable": false, 562 | "type": "function", 563 | "gas": 1331 564 | }, 565 | { 566 | "name": "owner", 567 | "outputs": [ 568 | { 569 | "type": "address", 570 | "name": "out" 571 | } 572 | ], 573 | "inputs": [], 574 | "constant": true, 575 | "payable": false, 576 | "type": "function", 577 | "gas": 1361 578 | }, 579 | { 580 | "name": "admin_actions_deadline", 581 | "outputs": [ 582 | { 583 | "type": "uint256", 584 | "unit": "sec", 585 | "name": "out" 586 | } 587 | ], 588 | "inputs": [], 589 | "constant": true, 590 | "payable": false, 591 | "type": "function", 592 | "gas": 1391 593 | }, 594 | { 595 | "name": "transfer_ownership_deadline", 596 | "outputs": [ 597 | { 598 | "type": "uint256", 599 | "unit": "sec", 600 | "name": "out" 601 | } 602 | ], 603 | "inputs": [], 604 | "constant": true, 605 | "payable": false, 606 | "type": "function", 607 | "gas": 1421 608 | }, 609 | { 610 | "name": "future_A", 611 | "outputs": [ 612 | { 613 | "type": "int128", 614 | "name": "out" 615 | } 616 | ], 617 | "inputs": [], 618 | "constant": true, 619 | "payable": false, 620 | "type": "function", 621 | "gas": 1451 622 | }, 623 | { 624 | "name": "future_fee", 625 | "outputs": [ 626 | { 627 | "type": "int128", 628 | "name": "out" 629 | } 630 | ], 631 | "inputs": [], 632 | "constant": true, 633 | "payable": false, 634 | "type": "function", 635 | "gas": 1481 636 | }, 637 | { 638 | "name": "future_admin_fee", 639 | "outputs": [ 640 | { 641 | "type": "int128", 642 | "name": "out" 643 | } 644 | ], 645 | "inputs": [], 646 | "constant": true, 647 | "payable": false, 648 | "type": "function", 649 | "gas": 1511 650 | }, 651 | { 652 | "name": "future_owner", 653 | "outputs": [ 654 | { 655 | "type": "address", 656 | "name": "out" 657 | } 658 | ], 659 | "inputs": [], 660 | "constant": true, 661 | "payable": false, 662 | "type": "function", 663 | "gas": 1541 664 | } 665 | ]""") 666 | TOKEN_ABI = json.loads("""[ 667 | { 668 | "constant": true, 669 | "inputs": [], 670 | "name": "name", 671 | "outputs": [ 672 | { 673 | "name": "", 674 | "type": "string" 675 | } 676 | ], 677 | "payable": false, 678 | "stateMutability": "view", 679 | "type": "function" 680 | }, 681 | { 682 | "constant": false, 683 | "inputs": [ 684 | { 685 | "name": "_spender", 686 | "type": "address" 687 | }, 688 | { 689 | "name": "_value", 690 | "type": "uint256" 691 | } 692 | ], 693 | "name": "approve", 694 | "outputs": [ 695 | { 696 | "name": "", 697 | "type": "bool" 698 | } 699 | ], 700 | "payable": false, 701 | "stateMutability": "nonpayable", 702 | "type": "function" 703 | }, 704 | { 705 | "constant": true, 706 | "inputs": [], 707 | "name": "totalSupply", 708 | "outputs": [ 709 | { 710 | "name": "", 711 | "type": "uint256" 712 | } 713 | ], 714 | "payable": false, 715 | "stateMutability": "view", 716 | "type": "function" 717 | }, 718 | { 719 | "constant": false, 720 | "inputs": [ 721 | { 722 | "name": "_from", 723 | "type": "address" 724 | }, 725 | { 726 | "name": "_to", 727 | "type": "address" 728 | }, 729 | { 730 | "name": "_value", 731 | "type": "uint256" 732 | } 733 | ], 734 | "name": "transferFrom", 735 | "outputs": [ 736 | { 737 | "name": "", 738 | "type": "bool" 739 | } 740 | ], 741 | "payable": false, 742 | "stateMutability": "nonpayable", 743 | "type": "function" 744 | }, 745 | { 746 | "constant": true, 747 | "inputs": [], 748 | "name": "decimals", 749 | "outputs": [ 750 | { 751 | "name": "", 752 | "type": "uint8" 753 | } 754 | ], 755 | "payable": false, 756 | "stateMutability": "view", 757 | "type": "function" 758 | }, 759 | { 760 | "constant": true, 761 | "inputs": [ 762 | { 763 | "name": "_owner", 764 | "type": "address" 765 | } 766 | ], 767 | "name": "balanceOf", 768 | "outputs": [ 769 | { 770 | "name": "balance", 771 | "type": "uint256" 772 | } 773 | ], 774 | "payable": false, 775 | "stateMutability": "view", 776 | "type": "function" 777 | }, 778 | { 779 | "constant": true, 780 | "inputs": [], 781 | "name": "symbol", 782 | "outputs": [ 783 | { 784 | "name": "", 785 | "type": "string" 786 | } 787 | ], 788 | "payable": false, 789 | "stateMutability": "view", 790 | "type": "function" 791 | }, 792 | { 793 | "constant": false, 794 | "inputs": [ 795 | { 796 | "name": "_to", 797 | "type": "address" 798 | }, 799 | { 800 | "name": "_value", 801 | "type": "uint256" 802 | } 803 | ], 804 | "name": "transfer", 805 | "outputs": [ 806 | { 807 | "name": "", 808 | "type": "bool" 809 | } 810 | ], 811 | "payable": false, 812 | "stateMutability": "nonpayable", 813 | "type": "function" 814 | }, 815 | { 816 | "constant": true, 817 | "inputs": [ 818 | { 819 | "name": "_owner", 820 | "type": "address" 821 | }, 822 | { 823 | "name": "_spender", 824 | "type": "address" 825 | } 826 | ], 827 | "name": "allowance", 828 | "outputs": [ 829 | { 830 | "name": "", 831 | "type": "uint256" 832 | } 833 | ], 834 | "payable": false, 835 | "stateMutability": "view", 836 | "type": "function" 837 | }, 838 | { 839 | "payable": true, 840 | "stateMutability": "payable", 841 | "type": "fallback" 842 | }, 843 | { 844 | "anonymous": false, 845 | "inputs": [ 846 | { 847 | "indexed": true, 848 | "name": "owner", 849 | "type": "address" 850 | }, 851 | { 852 | "indexed": true, 853 | "name": "spender", 854 | "type": "address" 855 | }, 856 | { 857 | "indexed": false, 858 | "name": "value", 859 | "type": "uint256" 860 | } 861 | ], 862 | "name": "Approval", 863 | "type": "event" 864 | }, 865 | { 866 | "anonymous": false, 867 | "inputs": [ 868 | { 869 | "indexed": true, 870 | "name": "from", 871 | "type": "address" 872 | }, 873 | { 874 | "indexed": true, 875 | "name": "to", 876 | "type": "address" 877 | }, 878 | { 879 | "indexed": false, 880 | "name": "value", 881 | "type": "uint256" 882 | } 883 | ], 884 | "name": "Transfer", 885 | "type": "event" 886 | } 887 | ]""") 888 | -------------------------------------------------------------------------------- /curvestats-averages.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from collections import defaultdict 4 | from time import time 5 | import lmdb 6 | import json 7 | 8 | DB_NAME = 'curvestats.lmdb' # <- DB [block][pool#]{...} 9 | START_BLOCK = 9456294 10 | TICKS = [1, 5, 10, 15, 30, 60 * 24] # min 11 | day_ago = time() - 86400 12 | 13 | summarized_data = {} 14 | db = lmdb.open(DB_NAME) 15 | db.set_mapsize(16 * 2 ** 36) 16 | 17 | 18 | def int2uid(value): 19 | return int.to_bytes(value, 4, 'big') 20 | 21 | 22 | def get_block(b): 23 | with db.begin(write=False) as tx: 24 | obj = tx.get(int2uid(b)) 25 | if not obj: 26 | return False 27 | return json.loads(obj) 28 | 29 | 30 | if __name__ == "__main__": 31 | b = START_BLOCK 32 | decimals = { 33 | 'compound': [18, 6], 34 | 'usdt': [18, 6, 6], 35 | 'y': [18, 6, 6, 18], 36 | 'busd': [18, 6, 6, 18], 37 | 'susd': [18, 6, 6, 18], 38 | 'pax': [18, 6, 6, 18], 39 | 'ren2': [8, 8], 40 | 'rens': [8, 8, 18], 41 | 'hbtc': [18, 8], 42 | '3pool': [18, 6, 6], 43 | 'gusd': [2, 18], 44 | 'husd': [8, 18], 45 | 'usdn': [18, 18], 46 | 'usdk': [18, 18], 47 | 'linkusd': [18, 18], 48 | 'musd': [18, 18], 49 | 'rsv': [18, 18], 50 | 'tbtc': [18, 18], 51 | 'dusd': [18, 18], 52 | 'pbtc': [18, 18], 53 | 'bbtc': [8, 18], 54 | 'obtc': [18, 18], 55 | 'ust': [18, 18], 56 | 'eurs': [2, 18], 57 | 'seth': [18, 18], 58 | 'aave': [18, 6, 6], 59 | 'idle': [18, 6, 6], 60 | 'steth': [18, 18], 61 | 'saave': [18, 18], 62 | 'ankreth': [18, 18], 63 | 'ib': [18, 6, 6], 64 | 'link': [18, 18], 65 | 'usdp': [18, 18], 66 | 'tusd': [18, 18], 67 | 'frax': [18, 18], 68 | 'lusd': [18, 18], 69 | 'busdv2': [18, 18], 70 | 'alusd': [18, 18], 71 | 'reth': [18, 18], 72 | 'mim': [18, 18], 73 | 'eurt': [18, 18], 74 | 'rai': [18, 18], 75 | '4pool': [6, 6, 6, 18], 76 | '2pool': [6, 6] 77 | } 78 | underlying_decimals = { 79 | 'gusd': [2, 18, 6, 6], 'husd': [8, 18, 6, 6], 'usdn': [18, 18, 6, 6], 'usdk': [18, 18, 6, 6], 80 | 'linkusd': [18, 18, 6, 6], 'musd': [18, 18, 6, 6], 'rsv': [18, 18, 6, 6], 'tbtc': [18, 8, 8, 18], 81 | 'dusd': [18, 18, 6, 6], 'pbtc': [18, 8, 8, 18], 'bbtc': [8, 8, 8, 18], 'obtc': [18, 8, 8, 18], 82 | 'ust': [18, 18, 6, 6], 'seth': [18, 18], 'aave': [18, 6, 6], 'idle': [18, 6, 6], 'ankreth': [18, 18], 83 | 'usdp': [18, 18, 6, 6], 'tusd': [18, 18, 6, 6], 'frax': [18, 18, 6, 6], 'lusd': [18, 18, 6, 6], 84 | 'busdv2': [18, 18, 6, 6], 'alusd': [18, 18, 6, 6], 'reth': [18, 18], 'mim': [18, 18, 6, 6], 85 | 'eurt': [18, 18], 'rai': [18, 18, 6, 6], '4pool': [6, 6, 6, 18], '2pool': [6, 6]} 86 | start_blocks = {'tbtc': 11095929, 'usdp': 11922058} 87 | virtual_prices = [] 88 | daily_volumes = defaultdict(float) 89 | pools = ['compound', 'usdt', 'y', 'busd', 'susd', 'pax', 'ren2', 'rens', 'hbtc', '3pool', 'gusd', 'husd', 'usdn', 90 | 'usdk', 'linkusd', 'musd', 'rsv', 'tbtc', 'dusd', 'pbtc', 'bbtc', 'obtc', 'ust', 'eurs', 'seth', 'aave', 91 | 'idle', 'steth', 'saave', 'ankreth', 'ib', 'link', 'usdp', 'tusd', 'frax', 'lusd', 'busdv2', 'alusd', 92 | 'reth', 'mim', 'eurt', 'rai', '4pool', '2pool'] 93 | ctr = 0 94 | while True: 95 | block = get_block(b) 96 | if not block: 97 | ctr += 1 98 | b += 1 99 | if ctr > 100: 100 | break 101 | else: 102 | continue 103 | else: 104 | ctr = 0 105 | 106 | virtual_prices.append( 107 | [block[pools[1]]['timestamp']] 108 | + [block[pool]['virtual_price'] / 1e18 if pool in block else 0 for pool in pools]) 109 | 110 | for pool in block: 111 | if pool not in summarized_data: 112 | summarized_data[pool] = {} 113 | 114 | if pool not in pools or start_blocks.get(pool, 0) >= b: 115 | continue 116 | 117 | for tick in TICKS: 118 | ts = block[pool]['timestamp'] // (tick * 60) * (tick * 60) 119 | if tick not in summarized_data[pool]: 120 | summarized_data[pool][tick] = {} 121 | if ts not in summarized_data[pool][tick]: 122 | summarized_data[pool][tick][ts] = {} 123 | obj = block[pool].copy() 124 | obj['volume'] = summarized_data[pool][tick][ts].get('volume', {}) 125 | obj['prices'] = summarized_data[pool][tick][ts].get('prices', {}) 126 | for t in obj['trades']: 127 | pair = sorted([(t['sold_id'], t['tokens_sold']), (t['bought_id'], t['tokens_bought'])]) 128 | pair, tokens = list(zip(*pair)) # (id1, id2), (vol1, vol2) 129 | jpair = '{}-{}'.format(*pair) 130 | if t.get('underlying', False): 131 | t0 = tokens[0] * 10 ** (18 - underlying_decimals[pool][pair[0]]) 132 | t1 = tokens[1] * 10 ** (18 - underlying_decimals[pool][pair[1]]) 133 | else: 134 | t0 = tokens[0] * 10 ** (18 - decimals[pool][pair[0]]) 135 | t1 = tokens[1] * 10 ** (18 - decimals[pool][pair[1]]) 136 | if tick == 5 and ts > day_ago: 137 | daily_volumes[pool] += (t0 + t1) / (2 * 1e18) 138 | if t1 > 0 and t0 > 0: 139 | price = t1 / t0 140 | if jpair not in obj['prices']: 141 | obj['prices'][jpair] = [] 142 | obj['prices'][jpair].append(price) 143 | if jpair in obj['volume']: 144 | obj['volume'][jpair] = (obj['volume'][jpair][0] + tokens[0]), (obj['volume'][jpair][1] + tokens[1]) 145 | else: 146 | obj['volume'][jpair] = tokens 147 | del obj['trades'] 148 | for jpair in obj['prices']: 149 | prices = obj['prices'][jpair] 150 | # OHLC 151 | if prices: 152 | obj['prices'][jpair] = [prices[0], min(prices), max(prices), prices[-1]] 153 | summarized_data[pool][tick][ts] = obj 154 | 155 | b += 1 156 | 157 | last_time, *p_last = virtual_prices[-1] 158 | first_time, *p_first = virtual_prices[0] 159 | 160 | day_ix = [(abs(vp[0] - (last_time - 86400)), tuple(vp)) for i, vp in enumerate(virtual_prices)] 161 | week_ix = [(abs(vp[0] - (last_time - 7 * 86400)), tuple(vp)) for i, vp in enumerate(virtual_prices)] 162 | month_ix = [(abs(vp[0] - (last_time - 30 * 86400)), tuple(vp)) for i, vp in enumerate(virtual_prices)] 163 | 164 | vps = {'day': min(day_ix)[1], 165 | 'week': min(week_ix)[1], 166 | 'month': min(month_ix)[1]} 167 | 168 | profits = { 169 | interval: { 170 | pool: ((last / v) ** (86400 / (last_time - vp[0]))) ** 365 - 1 171 | if v > 0 else 0 172 | for pool, v, last in zip(pools, vp[1:], p_last)} 173 | for interval, vp in vps.items() 174 | } 175 | profits['total'] = {} 176 | for i, pool in enumerate(pools): 177 | try: 178 | t, v = [(vp[0], vp[i + 1]) for vp in virtual_prices if vp[i + 1] > 0][0] 179 | profits['total'][pool] = ((p_last[i] / v) ** (86400 / (last_time - t))) ** 365 - 1 180 | except IndexError: 181 | profits['total'][pool] = 0 182 | 183 | for pool in summarized_data: 184 | for t in summarized_data[pool]: 185 | data = sorted(summarized_data[pool][t].values(), key=lambda x: x['timestamp'])[-1000:] 186 | with open(f'json/{pool}-{t}m.json', 'w') as f: 187 | json.dump(data, f) 188 | with open('json/virtual-prices.json', 'w') as f: 189 | json.dump({ 190 | 'pools': pools, 191 | 'virtual_prices': virtual_prices}, f) 192 | with open('json/apys.json', 'w') as f: 193 | json.dump({'apy': profits, 'volume': daily_volumes}, f) 194 | -------------------------------------------------------------------------------- /curvestats-monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import lmdb 4 | import json 5 | import time 6 | import config_infura # noqa 7 | from time import sleep 8 | from multiprocessing import Pool 9 | from functools import partial 10 | 11 | from curvestats.compound import CompoundPool 12 | from curvestats.y import YPool 13 | from curvestats.btc import BtcPool, NewBtcPool 14 | from curvestats.newpool import NewPool 15 | from curvestats.meta import MetaPool 16 | from curvestats.metaf import MetaPoolU 17 | from curvestats.idle import IDLEPool 18 | from curvestats.ankr import ANKRPool 19 | from curvestats.yv2 import YV2Pool 20 | from curvestats.reth import RETHPool 21 | from curvestats.rai import RaiPool 22 | 23 | MPOOL_SIZE = 20 24 | 25 | pools = { 26 | 'compound': (CompoundPool, ("0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56", "0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2"), 9554041), 27 | 'usdt': (CompoundPool, ("0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C", "0x9fC689CCaDa600B6DF723D9E47D84d76664a1F23"), 9456294), 28 | 'y': (YPool, ("0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51", "0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8"), 9476469), 29 | 'busd': (YPool, ("0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27", "0x3B3Ac5386837Dc563660FB6a0937DFAa5924333B"), 9567296), 30 | 'susd': (CompoundPool, ('0xA5407eAE9Ba41422680e2e00537571bcC53efBfD', '0xC25a3A3b969415c80451098fa907EC722572917F'), 9906599), 31 | 'pax': (YPool, ("0x06364f10B501e868329afBc005b3492902d6C763", "0xD905e2eaeBe188fc92179b6350807D8bd91Db0D8"), 10041041), 32 | 'ren2': (BtcPool, ("0x93054188d876f558f4a66B2EF1d97d16eDf0895B", "0x49849C98ae39Fff122806C06791Fa73784FB3675"), 10151386), 33 | 'rens': (BtcPool, ("0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714", "0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3"), 10276945), 34 | 'hbtc': (NewBtcPool, ("0x4CA9b3063Ec5866A4B82E437059D2C43d1be596F", "0xb19059ebb43466C323583928285a49f558E572Fd"), 10732330), 35 | '3pool': (NewPool, ("0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490"), 10809482), 36 | 'gusd': (MetaPool, ("0x4f062658EaAF2C1ccf8C8e36D6824CDf41167956", "0xD2967f45c4f384DEEa880F807Be904762a3DeA07"), 11005605), 37 | 'husd': (MetaPool, ("0x3eF6A01A0f81D6046290f3e2A8c5b843e738E604", "0x5B5CFE992AdAC0C9D48E05854B2d91C73a003858"), 11010071), 38 | 'usdn': (MetaPool, ("0x0f9cb53Ebe405d49A0bbdBD291A65Ff571bC83e1", "0x4f3E8F405CF5aFC05D68142F3783bDfE13811522"), 11010515), 39 | 'usdk': (MetaPool, ("0x3E01dD8a5E1fb3481F0F589056b428Fc308AF0Fb", "0x97E2768e8E73511cA874545DC5Ff8067eB19B787"), 11010306), 40 | 'linkusd': (MetaPool, ("0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171", "0x6D65b498cb23deAba52db31c93Da9BFFb340FB8F"), 11011557), 41 | 'musd': (MetaPool, ("0x8474DdbE98F5aA3179B3B3F5942D724aFcdec9f6", "0x1AEf73d49Dedc4b1778d0706583995958Dc862e6"), 11011941), 42 | 'rsv': (MetaPool, ("0xC18cC39da8b11dA8c3541C598eE022258F9744da", "0xC2Ee6b0334C261ED60C72f6054450b61B8f18E35"), 11037532), 43 | 'tbtc': (MetaPool, ("0xC25099792E9349C7DD09759744ea681C7de2cb66", "0x64eda51d3Ad40D56b9dFc5554E06F94e1Dd786Fd"), 11095929), 44 | 'dusd': (MetaPool, ("0x8038C01A0390a8c547446a0b2c18fc9aEFEcc10c", "0x3a664Ab939FD8482048609f652f9a0B0677337B9"), 11187277), 45 | 'pbtc': (MetaPool, ("0x7F55DDe206dbAD629C080068923b36fe9D6bDBeF", "0xDE5331AC4B3630f94853Ff322B66407e0D6331E8"), 11421596), 46 | 'bbtc': (MetaPool, ("0x071c661B4DeefB59E2a3DdB20Db036821eeE8F4b", "0x410e3E86ef427e30B9235497143881f717d93c2A"), 11455023), 47 | 'obtc': (MetaPool, ("0xd81dA8D904b52208541Bade1bD6595D8a251F8dd", "0x2fE94ea3d5d4a175184081439753DE15AeF9d614"), 11459239), 48 | 'ust': (MetaPool, ("0x890f4e345B1dAED0367A877a1612f86A1f86985f", "0x94e131324b6054c0D789b190b2dAC504e4361b53"), 11466569), 49 | 'eurs': (NewPool, ("0x0Ce6a5fF5217e38315f87032CF90686C96627CAA", "0x194eBd173F6cDacE046C53eACcE9B953F28411d1"), 11466872), 50 | 'seth': (NewPool, ("0xc5424B857f758E906013F3555Dad202e4bdB4567", "0xA3D87FffcE63B53E0d54fAa1cc983B7eB0b74A9c"), 11491949), 51 | 'aave': (NewPool, ("0xDeBF20617708857ebe4F679508E7b7863a8A8EeE", "0xFd2a8fA60Abd58Efe3EeE34dd494cD491dC14900"), 11497107), 52 | 'idle': (IDLEPool, ("0x83f252f036761a1E3d10DACa8e16D7b21E3744D7", "0x09f4B84A87FC81FC84220fD7287b613B8A9D4c05"), 11503377), 53 | 'steth': (NewPool, ("0xDC24316b9AE028F1497c275EB9192a3Ea0f67022", "0x06325440D014e39736583c165C2963BA99fAf14E"), 11592552), 54 | 'saave': (NewPool, ("0xEB16Ae0052ed37f479f7fe63849198Df1765a733", "0x02d341CcB60fAaf662bC0554d13778015d1b285C"), 11772501), 55 | 'ankreth': (ANKRPool, ("0xA96A65c051bF88B4095Ee1f2451C2A9d43F53Ae2", "0xaA17A236F2bAdc98DDc0Cf999AbB47D47Fc0A6Cf"), 11774140), 56 | 'ib': (YV2Pool, ("0x2dded6Da1BF5DBdF597C45fcFaa3194e53EcfeAF", "0x5282a4eF67D9C33135340fB3289cc1711c13638C"), 11831120), 57 | 'link': (NewPool, ("0xF178C0b5Bb7e7aBF4e12A4838C7b7c5bA2C623c0", "0xcee60cFa923170e4f8204AE08B4fA6A3F5656F3a"), 11875216), 58 | 'usdp': (MetaPool, ("0x42d7025938bEc20B69cBae5A77421082407f053A", "0x7Eb40E450b9655f4B3cC4259BCC731c63ff55ae6"), 11922058), 59 | 'tusd': (MetaPoolU, ("0xEcd5e75AFb02eFa118AF914515D6521aaBd189F1", "0xEcd5e75AFb02eFa118AF914515D6521aaBd189F1"), 12007000), 60 | 'frax': (MetaPoolU, ("0xd632f22692FaC7611d2AA1C0D552930D43CAEd3B", "0xd632f22692FaC7611d2AA1C0D552930D43CAEd3B"), 11968731), 61 | 'lusd': (MetaPoolU, ("0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA", "0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA"), 12184844), 62 | 'busdv2': (MetaPoolU, ("0x4807862AA8b2bF68830e4C8dc86D0e9A998e085a", "0x4807862AA8b2bF68830e4C8dc86D0e9A998e085a"), 12237710), 63 | 'alusd': (MetaPoolU, ("0x43b4FdFD4Ff969587185cDB6f0BD875c5Fc83f8c", "0x43b4FdFD4Ff969587185cDB6f0BD875c5Fc83f8c"), 11955334), 64 | 'reth': (RETHPool, ("0xF9440930043eb3997fc70e1339dBb11F341de7A8", "0x53a901d48795C58f485cBB38df08FA96a24669D5"), 12463577), 65 | 'mim': (MetaPoolU, ("0x5a6A4D54456819380173272A5E8E9B9904BdF41B", "0x5a6A4D54456819380173272A5E8E9B9904BdF41B"), 12557140), 66 | 'eurt': (MetaPoolU, ("0xFD5dB7463a3aB53fD211b4af195c5BCCC1A03890", "0xFD5dB7463a3aB53fD211b4af195c5BCCC1A03890"), 12914705), 67 | 'rai': (RaiPool, ("0x618788357D0EBd8A37e763ADab3bc575D54c2C7d", "0x6BA5b4e438FA0aAf7C1bD179285aF65d13bD3D90"), 13634175), 68 | '4pool': (NewPool, ("0x4e0915C88bC70750D68C481540F081fEFaF22273", "0x4e0915C88bC70750D68C481540F081fEFaF22273"), 14631360), 69 | '2pool': (NewPool, ("0x1005F7406f32a61BD760CfA14aCCd2737913d546", "0x1005F7406f32a61BD760CfA14aCCd2737913d546"), 14631074 ), 70 | } 71 | start_blocks = {} 72 | 73 | DB_NAME = 'curvestats.lmdb' # <- DB [block][pool#]{...} 74 | 75 | 76 | def init_pools(): 77 | from curvestats.w3 import w3 78 | w3 = w3() 79 | for i, p in pools.items(): 80 | if isinstance(p, tuple): 81 | pools[i] = p[0](*p[1], w3=w3) 82 | start_blocks[i] = p[2] 83 | 84 | 85 | def fetch_stats(block, i='compound'): 86 | init_pools() 87 | return pools[i].fetch_stats(block) 88 | 89 | 90 | def int2uid(value): 91 | return int.to_bytes(value, 4, 'big') 92 | 93 | 94 | def pools_not_in_block(tx, b): 95 | out = [] 96 | block = tx.get(int2uid(b)) 97 | if block: 98 | block = json.loads(block) 99 | if block: 100 | for k in pools: 101 | if k not in block: 102 | out.append(k) 103 | else: 104 | out = list(pools) 105 | return out 106 | 107 | 108 | mpool = Pool(MPOOL_SIZE) 109 | init_pools() 110 | 111 | 112 | if __name__ == '__main__': 113 | from curvestats.w3 import w3 114 | w3 = w3() 115 | init_pools() 116 | 117 | db = lmdb.open(DB_NAME, map_size=(2 ** 36)) 118 | 119 | start_block = 14631074 120 | # start_block = w3.eth.getBlock('latest')['number'] - 1000 121 | print('Monitor started') 122 | 123 | # Initial data 124 | with db.begin(write=True) as tx: 125 | if pools_not_in_block(tx, 0) or True: # XXX 126 | tx.put(int2uid(0), json.dumps( 127 | {k: { 128 | 'N': pool.N, 129 | 'underlying_N': pool.underlying_N if hasattr(pool, 'underlying_N') else pool.N, 130 | 'decimals': pool.decimals, 131 | 'underlying_decimals': pool.underlying_decimals if hasattr(pool, 'underlying_decimals') else pool.decimals, 132 | 'token': pool.token.address, 'pool': pool.pool.address, 133 | 'coins': [pool.coins[j].address for j in range(pool.N)], 134 | 'underlying_coins': [pool.underlying_coins[j].address for j in range(getattr(pool, 'underlying_N', pool.N))]} 135 | for k, pool in pools.items()}).encode()) 136 | 137 | while True: 138 | while True: 139 | try: 140 | current_block = w3.eth.getBlock('latest')['number'] + 1 141 | break 142 | except Exception: 143 | time.sleep(10) 144 | 145 | if current_block - start_block > MPOOL_SIZE: 146 | blocks = range(start_block, start_block + MPOOL_SIZE) 147 | with db.begin(write=True) as tx: 148 | pools_to_fetch = pools_not_in_block(tx, blocks[-1]) 149 | if pools_to_fetch: 150 | stats = {} 151 | for p in pools_to_fetch: 152 | if blocks[0] >= start_blocks[p]: 153 | newstats = mpool.map(partial(fetch_stats, i=p), blocks) 154 | for b, s in zip(blocks, newstats): 155 | if b not in stats: 156 | stats[b] = {} 157 | stats[b][p] = s 158 | for b, v in stats.items(): 159 | block = tx.get(int2uid(b)) 160 | if block: 161 | block = json.loads(block) 162 | v.update(block) 163 | tx.put(int2uid(b), json.dumps(v).encode()) 164 | pools_fetched = [p for p in pools_to_fetch 165 | if blocks[-1] in stats and p in stats[blocks[-1]]] 166 | print('...', start_block, pools_fetched) 167 | else: 168 | print('... already in DB:', start_block) 169 | start_block += MPOOL_SIZE 170 | 171 | else: 172 | if current_block > start_block: 173 | for block in range(start_block, current_block): 174 | with db.begin(write=True) as tx: 175 | if pools_not_in_block(tx, block): 176 | stats = {} 177 | for p, pool in pools.items(): 178 | if block >= start_blocks[p]: 179 | stats[p] = pool.fetch_stats(block) 180 | print(block, [len(s['trades']) for s in stats.values()]) 181 | tx.put(int2uid(block), json.dumps(stats).encode()) 182 | start_block = current_block 183 | 184 | sleep(15) 185 | -------------------------------------------------------------------------------- /curvestats/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Recording full statistics about the state of Curve pools 4 | """ 5 | from retry import retry 6 | from web3.exceptions import BadFunctionCallOutput, ABIFunctionNotFound, ABIEventFunctionNotFound 7 | from .abi import ABI, TOKEN_ABI 8 | 9 | 10 | class Pool: 11 | @retry(Exception, delay=5, tries=5, backoff=2) 12 | def __init__(self, pool, token, w3=None, abi=ABI): 13 | if not w3: 14 | from .w3 import w3 15 | self.w3 = w3() 16 | else: 17 | self.w3 = w3 18 | self.pool_contract = self.w3.eth.contract(abi=abi, address=pool) 19 | self.pool = self.pool_contract.functions 20 | self.token_contract = self.w3.eth.contract(abi=TOKEN_ABI, address=token) 21 | self.token = self.token_contract.functions 22 | 23 | self.N = 0 24 | self.underlying_coins = [] 25 | self.coins = [] 26 | self.decimals = [] 27 | for i in range(10): 28 | try: 29 | self.pool.balances(i).call() 30 | c = self.pool.coins(i).call() 31 | self.coins.append(c) # just address 32 | try: 33 | uc = self.pool.underlying_coins(i).call() 34 | except (BadFunctionCallOutput, ABIFunctionNotFound, ValueError): 35 | uc = c 36 | uc = self.w3.eth.contract(abi=TOKEN_ABI, address=uc).functions 37 | self.underlying_coins.append(uc) 38 | try: 39 | self.decimals.append(uc.decimals().call()) 40 | except Exception: 41 | self.decimals.append(18) 42 | self.N += 1 43 | except (BadFunctionCallOutput, ValueError): 44 | if i == 0: 45 | raise 46 | else: 47 | break 48 | 49 | def get_rate(self, i, block=None): 50 | return 10 ** 18 51 | 52 | @retry(Exception, delay=5, tries=5, backoff=2) 53 | def fetch_stats(self, block='latest'): 54 | full_block = self.w3.eth.getBlock(block) 55 | block = full_block['number'] 56 | timestamp = full_block['timestamp'] 57 | kw = {'block_identifier': block} 58 | rates = [self.get_rate(i, block=block) for i in range(self.N)] 59 | balances = [self.pool.balances(i).call(**kw) for i in range(self.N)] 60 | is_deposited = True 61 | for b in balances: 62 | is_deposited *= (b > 0) 63 | trades = [] 64 | 65 | try: 66 | for e in self.pool_contract.events.TokenExchangeUnderlying.getLogs(fromBlock=block, toBlock=block): 67 | ev = e['args'] 68 | trades.append({ 69 | 'sold_id': ev['sold_id'], 70 | 'tokens_sold': ev['tokens_sold'], 71 | 'bought_id': ev['bought_id'], 72 | 'tokens_bought': ev['tokens_bought']}) 73 | except ABIEventFunctionNotFound: 74 | pass 75 | 76 | for e in self.pool_contract.events.TokenExchange.getLogs(fromBlock=block, toBlock=block): 77 | ev = e['args'] 78 | trades.append({ 79 | 'sold_id': ev['sold_id'], 80 | 'tokens_sold': ev['tokens_sold'] * rates[ev['sold_id']] // 1e18, 81 | 'bought_id': ev['bought_id'], 82 | 'tokens_bought': ev['tokens_bought'] * rates[ev['bought_id']] // 1e18}) 83 | 84 | return { 85 | 'A': self.pool.A().call(**kw), 86 | 'fee': self.pool.fee().call(**kw), 87 | 'admin_fee': self.pool.admin_fee().call(**kw), 88 | 'supply': self.token.totalSupply().call(**kw), 89 | 'virtual_price': is_deposited and self.pool.get_virtual_price().call(**kw), 90 | 'timestamp': timestamp, 91 | 'balances': balances, 92 | 'rates': rates, 93 | 'trades': trades 94 | } 95 | -------------------------------------------------------------------------------- /curvestats/aave_pool.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import AAVE_ABI 7 | 8 | 9 | class AavePool(Pool): 10 | def __init__(self, *args, w3=None): 11 | super().__init__(*args, w3=w3, abi=AAVE_ABI) 12 | for i in range(self.N): 13 | c = self.w3.eth.contract(abi=TOKEN_ABI, address=self.coins[i]).functions 14 | self.coins[i] = c 15 | 16 | def get_rate(self, i, block=None): 17 | if not block: 18 | block = self.w3.eth.getBlock('latest')['number'] 19 | kw = {'block_identifier': block} 20 | 21 | rate = 10 ** 18 22 | return rate 23 | -------------------------------------------------------------------------------- /curvestats/abi.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | ABI = json.loads("""[ 4 | { 5 | "name": "TokenExchange", 6 | "inputs": [ 7 | { 8 | "type": "address", 9 | "name": "buyer", 10 | "indexed": true 11 | }, 12 | { 13 | "type": "int128", 14 | "name": "sold_id", 15 | "indexed": false 16 | }, 17 | { 18 | "type": "uint256", 19 | "name": "tokens_sold", 20 | "indexed": false 21 | }, 22 | { 23 | "type": "int128", 24 | "name": "bought_id", 25 | "indexed": false 26 | }, 27 | { 28 | "type": "uint256", 29 | "name": "tokens_bought", 30 | "indexed": false 31 | } 32 | ], 33 | "anonymous": false, 34 | "type": "event" 35 | }, 36 | { 37 | "name": "TokenExchangeUnderlying", 38 | "inputs": [ 39 | { 40 | "type": "address", 41 | "name": "buyer", 42 | "indexed": true 43 | }, 44 | { 45 | "type": "int128", 46 | "name": "sold_id", 47 | "indexed": false 48 | }, 49 | { 50 | "type": "uint256", 51 | "name": "tokens_sold", 52 | "indexed": false 53 | }, 54 | { 55 | "type": "int128", 56 | "name": "bought_id", 57 | "indexed": false 58 | }, 59 | { 60 | "type": "uint256", 61 | "name": "tokens_bought", 62 | "indexed": false 63 | } 64 | ], 65 | "anonymous": false, 66 | "type": "event" 67 | }, 68 | { 69 | "name": "AddLiquidity", 70 | "inputs": [ 71 | { 72 | "type": "address", 73 | "name": "provider", 74 | "indexed": true 75 | }, 76 | { 77 | "type": "uint256[2]", 78 | "name": "token_amounts", 79 | "indexed": false 80 | }, 81 | { 82 | "type": "uint256[2]", 83 | "name": "fees", 84 | "indexed": false 85 | }, 86 | { 87 | "type": "uint256", 88 | "name": "invariant", 89 | "indexed": false 90 | }, 91 | { 92 | "type": "uint256", 93 | "name": "token_supply", 94 | "indexed": false 95 | } 96 | ], 97 | "anonymous": false, 98 | "type": "event" 99 | }, 100 | { 101 | "name": "RemoveLiquidity", 102 | "inputs": [ 103 | { 104 | "type": "address", 105 | "name": "provider", 106 | "indexed": true 107 | }, 108 | { 109 | "type": "uint256[2]", 110 | "name": "token_amounts", 111 | "indexed": false 112 | }, 113 | { 114 | "type": "uint256[2]", 115 | "name": "fees", 116 | "indexed": false 117 | }, 118 | { 119 | "type": "uint256", 120 | "name": "token_supply", 121 | "indexed": false 122 | } 123 | ], 124 | "anonymous": false, 125 | "type": "event" 126 | }, 127 | { 128 | "name": "RemoveLiquidityImbalance", 129 | "inputs": [ 130 | { 131 | "type": "address", 132 | "name": "provider", 133 | "indexed": true 134 | }, 135 | { 136 | "type": "uint256[2]", 137 | "name": "token_amounts", 138 | "indexed": false 139 | }, 140 | { 141 | "type": "uint256[2]", 142 | "name": "fees", 143 | "indexed": false 144 | }, 145 | { 146 | "type": "uint256", 147 | "name": "invariant", 148 | "indexed": false 149 | }, 150 | { 151 | "type": "uint256", 152 | "name": "token_supply", 153 | "indexed": false 154 | } 155 | ], 156 | "anonymous": false, 157 | "type": "event" 158 | }, 159 | { 160 | "name": "CommitNewAdmin", 161 | "inputs": [ 162 | { 163 | "type": "uint256", 164 | "name": "deadline", 165 | "indexed": true, 166 | "unit": "sec" 167 | }, 168 | { 169 | "type": "address", 170 | "name": "admin", 171 | "indexed": true 172 | } 173 | ], 174 | "anonymous": false, 175 | "type": "event" 176 | }, 177 | { 178 | "name": "NewAdmin", 179 | "inputs": [ 180 | { 181 | "type": "address", 182 | "name": "admin", 183 | "indexed": true 184 | } 185 | ], 186 | "anonymous": false, 187 | "type": "event" 188 | }, 189 | { 190 | "name": "CommitNewParameters", 191 | "inputs": [ 192 | { 193 | "type": "uint256", 194 | "name": "deadline", 195 | "indexed": true, 196 | "unit": "sec" 197 | }, 198 | { 199 | "type": "uint256", 200 | "name": "A", 201 | "indexed": false 202 | }, 203 | { 204 | "type": "uint256", 205 | "name": "fee", 206 | "indexed": false 207 | }, 208 | { 209 | "type": "uint256", 210 | "name": "admin_fee", 211 | "indexed": false 212 | } 213 | ], 214 | "anonymous": false, 215 | "type": "event" 216 | }, 217 | { 218 | "name": "NewParameters", 219 | "inputs": [ 220 | { 221 | "type": "uint256", 222 | "name": "A", 223 | "indexed": false 224 | }, 225 | { 226 | "type": "uint256", 227 | "name": "fee", 228 | "indexed": false 229 | }, 230 | { 231 | "type": "uint256", 232 | "name": "admin_fee", 233 | "indexed": false 234 | } 235 | ], 236 | "anonymous": false, 237 | "type": "event" 238 | }, 239 | { 240 | "outputs": [], 241 | "inputs": [ 242 | { 243 | "type": "address[2]", 244 | "name": "_coins" 245 | }, 246 | { 247 | "type": "address[2]", 248 | "name": "_underlying_coins" 249 | }, 250 | { 251 | "type": "address", 252 | "name": "_pool_token" 253 | }, 254 | { 255 | "type": "uint256", 256 | "name": "_A" 257 | }, 258 | { 259 | "type": "uint256", 260 | "name": "_fee" 261 | } 262 | ], 263 | "constant": false, 264 | "payable": false, 265 | "type": "constructor" 266 | }, 267 | { 268 | "name": "get_virtual_price", 269 | "outputs": [ 270 | { 271 | "type": "uint256", 272 | "name": "out" 273 | } 274 | ], 275 | "inputs": [], 276 | "constant": true, 277 | "payable": false, 278 | "type": "function", 279 | "gas": 1084167 280 | }, 281 | { 282 | "name": "calc_token_amount", 283 | "outputs": [ 284 | { 285 | "type": "uint256", 286 | "name": "out" 287 | } 288 | ], 289 | "inputs": [ 290 | { 291 | "type": "uint256[2]", 292 | "name": "amounts" 293 | }, 294 | { 295 | "type": "bool", 296 | "name": "deposit" 297 | } 298 | ], 299 | "constant": true, 300 | "payable": false, 301 | "type": "function", 302 | "gas": 4239939 303 | }, 304 | { 305 | "name": "add_liquidity", 306 | "outputs": [], 307 | "inputs": [ 308 | { 309 | "type": "uint256[2]", 310 | "name": "amounts" 311 | }, 312 | { 313 | "type": "uint256", 314 | "name": "min_mint_amount" 315 | } 316 | ], 317 | "constant": false, 318 | "payable": false, 319 | "type": "function", 320 | "gas": 6479997 321 | }, 322 | { 323 | "name": "get_dy", 324 | "outputs": [ 325 | { 326 | "type": "uint256", 327 | "name": "out" 328 | } 329 | ], 330 | "inputs": [ 331 | { 332 | "type": "int128", 333 | "name": "i" 334 | }, 335 | { 336 | "type": "int128", 337 | "name": "j" 338 | }, 339 | { 340 | "type": "uint256", 341 | "name": "dx" 342 | } 343 | ], 344 | "constant": true, 345 | "payable": false, 346 | "type": "function", 347 | "gas": 2543681 348 | }, 349 | { 350 | "name": "get_dx", 351 | "outputs": [ 352 | { 353 | "type": "uint256", 354 | "name": "out" 355 | } 356 | ], 357 | "inputs": [ 358 | { 359 | "type": "int128", 360 | "name": "i" 361 | }, 362 | { 363 | "type": "int128", 364 | "name": "j" 365 | }, 366 | { 367 | "type": "uint256", 368 | "name": "dy" 369 | } 370 | ], 371 | "constant": true, 372 | "payable": false, 373 | "type": "function", 374 | "gas": 2543687 375 | }, 376 | { 377 | "name": "get_dy_underlying", 378 | "outputs": [ 379 | { 380 | "type": "uint256", 381 | "name": "out" 382 | } 383 | ], 384 | "inputs": [ 385 | { 386 | "type": "int128", 387 | "name": "i" 388 | }, 389 | { 390 | "type": "int128", 391 | "name": "j" 392 | }, 393 | { 394 | "type": "uint256", 395 | "name": "dx" 396 | } 397 | ], 398 | "constant": true, 399 | "payable": false, 400 | "type": "function", 401 | "gas": 2543506 402 | }, 403 | { 404 | "name": "get_dx_underlying", 405 | "outputs": [ 406 | { 407 | "type": "uint256", 408 | "name": "out" 409 | } 410 | ], 411 | "inputs": [ 412 | { 413 | "type": "int128", 414 | "name": "i" 415 | }, 416 | { 417 | "type": "int128", 418 | "name": "j" 419 | }, 420 | { 421 | "type": "uint256", 422 | "name": "dy" 423 | } 424 | ], 425 | "constant": true, 426 | "payable": false, 427 | "type": "function", 428 | "gas": 2543512 429 | }, 430 | { 431 | "name": "exchange", 432 | "outputs": [], 433 | "inputs": [ 434 | { 435 | "type": "int128", 436 | "name": "i" 437 | }, 438 | { 439 | "type": "int128", 440 | "name": "j" 441 | }, 442 | { 443 | "type": "uint256", 444 | "name": "dx" 445 | }, 446 | { 447 | "type": "uint256", 448 | "name": "min_dy" 449 | } 450 | ], 451 | "constant": false, 452 | "payable": false, 453 | "type": "function", 454 | "gas": 5184573 455 | }, 456 | { 457 | "name": "exchange_underlying", 458 | "outputs": [], 459 | "inputs": [ 460 | { 461 | "type": "int128", 462 | "name": "i" 463 | }, 464 | { 465 | "type": "int128", 466 | "name": "j" 467 | }, 468 | { 469 | "type": "uint256", 470 | "name": "dx" 471 | }, 472 | { 473 | "type": "uint256", 474 | "name": "min_dy" 475 | } 476 | ], 477 | "constant": false, 478 | "payable": false, 479 | "type": "function", 480 | "gas": 5200817 481 | }, 482 | { 483 | "name": "remove_liquidity", 484 | "outputs": [], 485 | "inputs": [ 486 | { 487 | "type": "uint256", 488 | "name": "_amount" 489 | }, 490 | { 491 | "type": "uint256[2]", 492 | "name": "min_amounts" 493 | } 494 | ], 495 | "constant": false, 496 | "payable": false, 497 | "type": "function", 498 | "gas": 153898 499 | }, 500 | { 501 | "name": "remove_liquidity_imbalance", 502 | "outputs": [], 503 | "inputs": [ 504 | { 505 | "type": "uint256[2]", 506 | "name": "amounts" 507 | }, 508 | { 509 | "type": "uint256", 510 | "name": "max_burn_amount" 511 | } 512 | ], 513 | "constant": false, 514 | "payable": false, 515 | "type": "function", 516 | "gas": 6479708 517 | }, 518 | { 519 | "name": "commit_new_parameters", 520 | "outputs": [], 521 | "inputs": [ 522 | { 523 | "type": "uint256", 524 | "name": "amplification" 525 | }, 526 | { 527 | "type": "uint256", 528 | "name": "new_fee" 529 | }, 530 | { 531 | "type": "uint256", 532 | "name": "new_admin_fee" 533 | } 534 | ], 535 | "constant": false, 536 | "payable": false, 537 | "type": "function", 538 | "gas": 146105 539 | }, 540 | { 541 | "name": "apply_new_parameters", 542 | "outputs": [], 543 | "inputs": [], 544 | "constant": false, 545 | "payable": false, 546 | "type": "function", 547 | "gas": 133512 548 | }, 549 | { 550 | "name": "revert_new_parameters", 551 | "outputs": [], 552 | "inputs": [], 553 | "constant": false, 554 | "payable": false, 555 | "type": "function", 556 | "gas": 21835 557 | }, 558 | { 559 | "name": "commit_transfer_ownership", 560 | "outputs": [], 561 | "inputs": [ 562 | { 563 | "type": "address", 564 | "name": "_owner" 565 | } 566 | ], 567 | "constant": false, 568 | "payable": false, 569 | "type": "function", 570 | "gas": 74512 571 | }, 572 | { 573 | "name": "apply_transfer_ownership", 574 | "outputs": [], 575 | "inputs": [], 576 | "constant": false, 577 | "payable": false, 578 | "type": "function", 579 | "gas": 60568 580 | }, 581 | { 582 | "name": "revert_transfer_ownership", 583 | "outputs": [], 584 | "inputs": [], 585 | "constant": false, 586 | "payable": false, 587 | "type": "function", 588 | "gas": 21925 589 | }, 590 | { 591 | "name": "withdraw_admin_fees", 592 | "outputs": [], 593 | "inputs": [], 594 | "constant": false, 595 | "payable": false, 596 | "type": "function", 597 | "gas": 12831 598 | }, 599 | { 600 | "name": "kill_me", 601 | "outputs": [], 602 | "inputs": [], 603 | "constant": false, 604 | "payable": false, 605 | "type": "function", 606 | "gas": 37878 607 | }, 608 | { 609 | "name": "unkill_me", 610 | "outputs": [], 611 | "inputs": [], 612 | "constant": false, 613 | "payable": false, 614 | "type": "function", 615 | "gas": 22015 616 | }, 617 | { 618 | "name": "coins", 619 | "outputs": [ 620 | { 621 | "type": "address", 622 | "name": "out" 623 | } 624 | ], 625 | "inputs": [ 626 | { 627 | "type": "int128", 628 | "name": "arg0" 629 | } 630 | ], 631 | "constant": true, 632 | "payable": false, 633 | "type": "function", 634 | "gas": 2190 635 | }, 636 | { 637 | "name": "underlying_coins", 638 | "outputs": [ 639 | { 640 | "type": "address", 641 | "name": "out" 642 | } 643 | ], 644 | "inputs": [ 645 | { 646 | "type": "int128", 647 | "name": "arg0" 648 | } 649 | ], 650 | "constant": true, 651 | "payable": false, 652 | "type": "function", 653 | "gas": 2220 654 | }, 655 | { 656 | "name": "balances", 657 | "outputs": [ 658 | { 659 | "type": "uint256", 660 | "name": "out" 661 | } 662 | ], 663 | "inputs": [ 664 | { 665 | "type": "int128", 666 | "name": "arg0" 667 | } 668 | ], 669 | "constant": true, 670 | "payable": false, 671 | "type": "function", 672 | "gas": 2250 673 | }, 674 | { 675 | "name": "A", 676 | "outputs": [ 677 | { 678 | "type": "uint256", 679 | "name": "out" 680 | } 681 | ], 682 | "inputs": [], 683 | "constant": true, 684 | "payable": false, 685 | "type": "function", 686 | "gas": 2081 687 | }, 688 | { 689 | "name": "fee", 690 | "outputs": [ 691 | { 692 | "type": "uint256", 693 | "name": "out" 694 | } 695 | ], 696 | "inputs": [], 697 | "constant": true, 698 | "payable": false, 699 | "type": "function", 700 | "gas": 2111 701 | }, 702 | { 703 | "name": "admin_fee", 704 | "outputs": [ 705 | { 706 | "type": "uint256", 707 | "name": "out" 708 | } 709 | ], 710 | "inputs": [], 711 | "constant": true, 712 | "payable": false, 713 | "type": "function", 714 | "gas": 2141 715 | }, 716 | { 717 | "name": "owner", 718 | "outputs": [ 719 | { 720 | "type": "address", 721 | "name": "out" 722 | } 723 | ], 724 | "inputs": [], 725 | "constant": true, 726 | "payable": false, 727 | "type": "function", 728 | "gas": 2171 729 | }, 730 | { 731 | "name": "admin_actions_deadline", 732 | "outputs": [ 733 | { 734 | "type": "uint256", 735 | "unit": "sec", 736 | "name": "out" 737 | } 738 | ], 739 | "inputs": [], 740 | "constant": true, 741 | "payable": false, 742 | "type": "function", 743 | "gas": 2201 744 | }, 745 | { 746 | "name": "transfer_ownership_deadline", 747 | "outputs": [ 748 | { 749 | "type": "uint256", 750 | "unit": "sec", 751 | "name": "out" 752 | } 753 | ], 754 | "inputs": [], 755 | "constant": true, 756 | "payable": false, 757 | "type": "function", 758 | "gas": 2231 759 | }, 760 | { 761 | "name": "future_A", 762 | "outputs": [ 763 | { 764 | "type": "uint256", 765 | "name": "out" 766 | } 767 | ], 768 | "inputs": [], 769 | "constant": true, 770 | "payable": false, 771 | "type": "function", 772 | "gas": 2261 773 | }, 774 | { 775 | "name": "future_fee", 776 | "outputs": [ 777 | { 778 | "type": "uint256", 779 | "name": "out" 780 | } 781 | ], 782 | "inputs": [], 783 | "constant": true, 784 | "payable": false, 785 | "type": "function", 786 | "gas": 2291 787 | }, 788 | { 789 | "name": "future_admin_fee", 790 | "outputs": [ 791 | { 792 | "type": "uint256", 793 | "name": "out" 794 | } 795 | ], 796 | "inputs": [], 797 | "constant": true, 798 | "payable": false, 799 | "type": "function", 800 | "gas": 2321 801 | }, 802 | { 803 | "name": "future_owner", 804 | "outputs": [ 805 | { 806 | "type": "address", 807 | "name": "out" 808 | } 809 | ], 810 | "inputs": [], 811 | "constant": true, 812 | "payable": false, 813 | "type": "function", 814 | "gas": 2351 815 | } 816 | ]""") 817 | TOKEN_ABI = json.loads("""[ 818 | { 819 | "constant": true, 820 | "inputs": [], 821 | "name": "name", 822 | "outputs": [ 823 | { 824 | "name": "", 825 | "type": "string" 826 | } 827 | ], 828 | "payable": false, 829 | "stateMutability": "view", 830 | "type": "function" 831 | }, 832 | { 833 | "constant": false, 834 | "inputs": [ 835 | { 836 | "name": "_spender", 837 | "type": "address" 838 | }, 839 | { 840 | "name": "_value", 841 | "type": "uint256" 842 | } 843 | ], 844 | "name": "approve", 845 | "outputs": [ 846 | { 847 | "name": "", 848 | "type": "bool" 849 | } 850 | ], 851 | "payable": false, 852 | "stateMutability": "nonpayable", 853 | "type": "function" 854 | }, 855 | { 856 | "constant": true, 857 | "inputs": [], 858 | "name": "totalSupply", 859 | "outputs": [ 860 | { 861 | "name": "", 862 | "type": "uint256" 863 | } 864 | ], 865 | "payable": false, 866 | "stateMutability": "view", 867 | "type": "function" 868 | }, 869 | { 870 | "constant": false, 871 | "inputs": [ 872 | { 873 | "name": "_from", 874 | "type": "address" 875 | }, 876 | { 877 | "name": "_to", 878 | "type": "address" 879 | }, 880 | { 881 | "name": "_value", 882 | "type": "uint256" 883 | } 884 | ], 885 | "name": "transferFrom", 886 | "outputs": [ 887 | { 888 | "name": "", 889 | "type": "bool" 890 | } 891 | ], 892 | "payable": false, 893 | "stateMutability": "nonpayable", 894 | "type": "function" 895 | }, 896 | { 897 | "constant": true, 898 | "inputs": [], 899 | "name": "decimals", 900 | "outputs": [ 901 | { 902 | "name": "", 903 | "type": "uint8" 904 | } 905 | ], 906 | "payable": false, 907 | "stateMutability": "view", 908 | "type": "function" 909 | }, 910 | { 911 | "constant": true, 912 | "inputs": [ 913 | { 914 | "name": "_owner", 915 | "type": "address" 916 | } 917 | ], 918 | "name": "balanceOf", 919 | "outputs": [ 920 | { 921 | "name": "balance", 922 | "type": "uint256" 923 | } 924 | ], 925 | "payable": false, 926 | "stateMutability": "view", 927 | "type": "function" 928 | }, 929 | { 930 | "constant": true, 931 | "inputs": [], 932 | "name": "symbol", 933 | "outputs": [ 934 | { 935 | "name": "", 936 | "type": "string" 937 | } 938 | ], 939 | "payable": false, 940 | "stateMutability": "view", 941 | "type": "function" 942 | }, 943 | { 944 | "constant": false, 945 | "inputs": [ 946 | { 947 | "name": "_to", 948 | "type": "address" 949 | }, 950 | { 951 | "name": "_value", 952 | "type": "uint256" 953 | } 954 | ], 955 | "name": "transfer", 956 | "outputs": [ 957 | { 958 | "name": "", 959 | "type": "bool" 960 | } 961 | ], 962 | "payable": false, 963 | "stateMutability": "nonpayable", 964 | "type": "function" 965 | }, 966 | { 967 | "constant": true, 968 | "inputs": [ 969 | { 970 | "name": "_owner", 971 | "type": "address" 972 | }, 973 | { 974 | "name": "_spender", 975 | "type": "address" 976 | } 977 | ], 978 | "name": "allowance", 979 | "outputs": [ 980 | { 981 | "name": "", 982 | "type": "uint256" 983 | } 984 | ], 985 | "payable": false, 986 | "stateMutability": "view", 987 | "type": "function" 988 | }, 989 | { 990 | "payable": true, 991 | "stateMutability": "payable", 992 | "type": "fallback" 993 | }, 994 | { 995 | "anonymous": false, 996 | "inputs": [ 997 | { 998 | "indexed": true, 999 | "name": "owner", 1000 | "type": "address" 1001 | }, 1002 | { 1003 | "indexed": true, 1004 | "name": "spender", 1005 | "type": "address" 1006 | }, 1007 | { 1008 | "indexed": false, 1009 | "name": "value", 1010 | "type": "uint256" 1011 | } 1012 | ], 1013 | "name": "Approval", 1014 | "type": "event" 1015 | }, 1016 | { 1017 | "anonymous": false, 1018 | "inputs": [ 1019 | { 1020 | "indexed": true, 1021 | "name": "from", 1022 | "type": "address" 1023 | }, 1024 | { 1025 | "indexed": true, 1026 | "name": "to", 1027 | "type": "address" 1028 | }, 1029 | { 1030 | "indexed": false, 1031 | "name": "value", 1032 | "type": "uint256" 1033 | } 1034 | ], 1035 | "name": "Transfer", 1036 | "type": "event" 1037 | } 1038 | ]""") 1039 | 1040 | NEW_ABI = json.loads(""" 1041 | [ 1042 | { 1043 | "anonymous": false, 1044 | "inputs": [ 1045 | { 1046 | "indexed": true, 1047 | "name": "buyer", 1048 | "type": "address" 1049 | }, 1050 | { 1051 | "indexed": false, 1052 | "name": "sold_id", 1053 | "type": "int128" 1054 | }, 1055 | { 1056 | "indexed": false, 1057 | "name": "tokens_sold", 1058 | "type": "uint256" 1059 | }, 1060 | { 1061 | "indexed": false, 1062 | "name": "bought_id", 1063 | "type": "int128" 1064 | }, 1065 | { 1066 | "indexed": false, 1067 | "name": "tokens_bought", 1068 | "type": "uint256" 1069 | } 1070 | ], 1071 | "name": "TokenExchange", 1072 | "type": "event" 1073 | }, 1074 | { 1075 | "anonymous": false, 1076 | "inputs": [ 1077 | { 1078 | "indexed": true, 1079 | "name": "buyer", 1080 | "type": "address" 1081 | }, 1082 | { 1083 | "indexed": false, 1084 | "name": "sold_id", 1085 | "type": "int128" 1086 | }, 1087 | { 1088 | "indexed": false, 1089 | "name": "tokens_sold", 1090 | "type": "uint256" 1091 | }, 1092 | { 1093 | "indexed": false, 1094 | "name": "bought_id", 1095 | "type": "int128" 1096 | }, 1097 | { 1098 | "indexed": false, 1099 | "name": "tokens_bought", 1100 | "type": "uint256" 1101 | } 1102 | ], 1103 | "name": "TokenExchangeUnderlying", 1104 | "type": "event" 1105 | }, 1106 | { 1107 | "anonymous": false, 1108 | "inputs": [ 1109 | { 1110 | "indexed": true, 1111 | "name": "provider", 1112 | "type": "address" 1113 | }, 1114 | { 1115 | "indexed": false, 1116 | "name": "token_amounts", 1117 | "type": "uint256[2]" 1118 | }, 1119 | { 1120 | "indexed": false, 1121 | "name": "fees", 1122 | "type": "uint256[2]" 1123 | }, 1124 | { 1125 | "indexed": false, 1126 | "name": "invariant", 1127 | "type": "uint256" 1128 | }, 1129 | { 1130 | "indexed": false, 1131 | "name": "token_supply", 1132 | "type": "uint256" 1133 | } 1134 | ], 1135 | "name": "AddLiquidity", 1136 | "type": "event" 1137 | }, 1138 | { 1139 | "anonymous": false, 1140 | "inputs": [ 1141 | { 1142 | "indexed": true, 1143 | "name": "provider", 1144 | "type": "address" 1145 | }, 1146 | { 1147 | "indexed": false, 1148 | "name": "token_amounts", 1149 | "type": "uint256[2]" 1150 | }, 1151 | { 1152 | "indexed": false, 1153 | "name": "fees", 1154 | "type": "uint256[2]" 1155 | }, 1156 | { 1157 | "indexed": false, 1158 | "name": "token_supply", 1159 | "type": "uint256" 1160 | } 1161 | ], 1162 | "name": "RemoveLiquidity", 1163 | "type": "event" 1164 | }, 1165 | { 1166 | "anonymous": false, 1167 | "inputs": [ 1168 | { 1169 | "indexed": true, 1170 | "name": "provider", 1171 | "type": "address" 1172 | }, 1173 | { 1174 | "indexed": false, 1175 | "name": "token_amount", 1176 | "type": "uint256" 1177 | }, 1178 | { 1179 | "indexed": false, 1180 | "name": "coin_amount", 1181 | "type": "uint256" 1182 | } 1183 | ], 1184 | "name": "RemoveLiquidityOne", 1185 | "type": "event" 1186 | }, 1187 | { 1188 | "anonymous": false, 1189 | "inputs": [ 1190 | { 1191 | "indexed": true, 1192 | "name": "provider", 1193 | "type": "address" 1194 | }, 1195 | { 1196 | "indexed": false, 1197 | "name": "token_amounts", 1198 | "type": "uint256[2]" 1199 | }, 1200 | { 1201 | "indexed": false, 1202 | "name": "fees", 1203 | "type": "uint256[2]" 1204 | }, 1205 | { 1206 | "indexed": false, 1207 | "name": "invariant", 1208 | "type": "uint256" 1209 | }, 1210 | { 1211 | "indexed": false, 1212 | "name": "token_supply", 1213 | "type": "uint256" 1214 | } 1215 | ], 1216 | "name": "RemoveLiquidityImbalance", 1217 | "type": "event" 1218 | }, 1219 | { 1220 | "anonymous": false, 1221 | "inputs": [ 1222 | { 1223 | "indexed": true, 1224 | "name": "deadline", 1225 | "type": "uint256" 1226 | }, 1227 | { 1228 | "indexed": true, 1229 | "name": "admin", 1230 | "type": "address" 1231 | } 1232 | ], 1233 | "name": "CommitNewAdmin", 1234 | "type": "event" 1235 | }, 1236 | { 1237 | "anonymous": false, 1238 | "inputs": [ 1239 | { 1240 | "indexed": true, 1241 | "name": "admin", 1242 | "type": "address" 1243 | } 1244 | ], 1245 | "name": "NewAdmin", 1246 | "type": "event" 1247 | }, 1248 | { 1249 | "anonymous": false, 1250 | "inputs": [ 1251 | { 1252 | "indexed": true, 1253 | "name": "deadline", 1254 | "type": "uint256" 1255 | }, 1256 | { 1257 | "indexed": false, 1258 | "name": "fee", 1259 | "type": "uint256" 1260 | }, 1261 | { 1262 | "indexed": false, 1263 | "name": "admin_fee", 1264 | "type": "uint256" 1265 | } 1266 | ], 1267 | "name": "CommitNewFee", 1268 | "type": "event" 1269 | }, 1270 | { 1271 | "anonymous": false, 1272 | "inputs": [ 1273 | { 1274 | "indexed": false, 1275 | "name": "fee", 1276 | "type": "uint256" 1277 | }, 1278 | { 1279 | "indexed": false, 1280 | "name": "admin_fee", 1281 | "type": "uint256" 1282 | } 1283 | ], 1284 | "name": "NewFee", 1285 | "type": "event" 1286 | }, 1287 | { 1288 | "anonymous": false, 1289 | "inputs": [ 1290 | { 1291 | "indexed": false, 1292 | "name": "old_A", 1293 | "type": "uint256" 1294 | }, 1295 | { 1296 | "indexed": false, 1297 | "name": "new_A", 1298 | "type": "uint256" 1299 | }, 1300 | { 1301 | "indexed": false, 1302 | "name": "initial_time", 1303 | "type": "uint256" 1304 | }, 1305 | { 1306 | "indexed": false, 1307 | "name": "future_time", 1308 | "type": "uint256" 1309 | } 1310 | ], 1311 | "name": "RampA", 1312 | "type": "event" 1313 | }, 1314 | { 1315 | "anonymous": false, 1316 | "inputs": [ 1317 | { 1318 | "indexed": false, 1319 | "name": "A", 1320 | "type": "uint256" 1321 | }, 1322 | { 1323 | "indexed": false, 1324 | "name": "t", 1325 | "type": "uint256" 1326 | } 1327 | ], 1328 | "name": "StopRampA", 1329 | "type": "event" 1330 | }, 1331 | { 1332 | "inputs": [ 1333 | { 1334 | "name": "_owner", 1335 | "type": "address" 1336 | }, 1337 | { 1338 | "name": "_coins", 1339 | "type": "address[2]" 1340 | }, 1341 | { 1342 | "name": "_pool_token", 1343 | "type": "address" 1344 | }, 1345 | { 1346 | "name": "_A", 1347 | "type": "uint256" 1348 | }, 1349 | { 1350 | "name": "_fee", 1351 | "type": "uint256" 1352 | }, 1353 | { 1354 | "name": "_admin_fee", 1355 | "type": "uint256" 1356 | } 1357 | ], 1358 | "outputs": [], 1359 | "stateMutability": "nonpayable", 1360 | "type": "constructor", 1361 | "name": "constructor" 1362 | }, 1363 | { 1364 | "gas": 5227, 1365 | "inputs": [], 1366 | "name": "A", 1367 | "outputs": [ 1368 | { 1369 | "name": "", 1370 | "type": "uint256" 1371 | } 1372 | ], 1373 | "stateMutability": "view", 1374 | "type": "function" 1375 | }, 1376 | { 1377 | "gas": 955150, 1378 | "inputs": [], 1379 | "name": "get_virtual_price", 1380 | "outputs": [ 1381 | { 1382 | "name": "", 1383 | "type": "uint256" 1384 | } 1385 | ], 1386 | "stateMutability": "view", 1387 | "type": "function" 1388 | }, 1389 | { 1390 | "gas": 3797461, 1391 | "inputs": [ 1392 | { 1393 | "name": "amounts", 1394 | "type": "uint256[2]" 1395 | }, 1396 | { 1397 | "name": "deposit", 1398 | "type": "bool" 1399 | } 1400 | ], 1401 | "name": "calc_token_amount", 1402 | "outputs": [ 1403 | { 1404 | "name": "", 1405 | "type": "uint256" 1406 | } 1407 | ], 1408 | "stateMutability": "view", 1409 | "type": "function" 1410 | }, 1411 | { 1412 | "gas": 5836477, 1413 | "inputs": [ 1414 | { 1415 | "name": "amounts", 1416 | "type": "uint256[2]" 1417 | }, 1418 | { 1419 | "name": "min_mint_amount", 1420 | "type": "uint256" 1421 | } 1422 | ], 1423 | "name": "add_liquidity", 1424 | "outputs": [], 1425 | "stateMutability": "nonpayable", 1426 | "type": "function" 1427 | }, 1428 | { 1429 | "gas": 2317363, 1430 | "inputs": [ 1431 | { 1432 | "name": "i", 1433 | "type": "int128" 1434 | }, 1435 | { 1436 | "name": "j", 1437 | "type": "int128" 1438 | }, 1439 | { 1440 | "name": "dx", 1441 | "type": "uint256" 1442 | } 1443 | ], 1444 | "name": "get_dy", 1445 | "outputs": [ 1446 | { 1447 | "name": "", 1448 | "type": "uint256" 1449 | } 1450 | ], 1451 | "stateMutability": "view", 1452 | "type": "function" 1453 | }, 1454 | { 1455 | "gas": 2317058, 1456 | "inputs": [ 1457 | { 1458 | "name": "i", 1459 | "type": "int128" 1460 | }, 1461 | { 1462 | "name": "j", 1463 | "type": "int128" 1464 | }, 1465 | { 1466 | "name": "dx", 1467 | "type": "uint256" 1468 | } 1469 | ], 1470 | "name": "get_dy_underlying", 1471 | "outputs": [ 1472 | { 1473 | "name": "", 1474 | "type": "uint256" 1475 | } 1476 | ], 1477 | "stateMutability": "view", 1478 | "type": "function" 1479 | }, 1480 | { 1481 | "gas": 2454671, 1482 | "inputs": [ 1483 | { 1484 | "name": "i", 1485 | "type": "int128" 1486 | }, 1487 | { 1488 | "name": "j", 1489 | "type": "int128" 1490 | }, 1491 | { 1492 | "name": "dx", 1493 | "type": "uint256" 1494 | }, 1495 | { 1496 | "name": "min_dy", 1497 | "type": "uint256" 1498 | } 1499 | ], 1500 | "name": "exchange", 1501 | "outputs": [], 1502 | "stateMutability": "nonpayable", 1503 | "type": "function" 1504 | }, 1505 | { 1506 | "gas": 143246, 1507 | "inputs": [ 1508 | { 1509 | "name": "_amount", 1510 | "type": "uint256" 1511 | }, 1512 | { 1513 | "name": "min_amounts", 1514 | "type": "uint256[2]" 1515 | } 1516 | ], 1517 | "name": "remove_liquidity", 1518 | "outputs": [], 1519 | "stateMutability": "nonpayable", 1520 | "type": "function" 1521 | }, 1522 | { 1523 | "gas": 5836308, 1524 | "inputs": [ 1525 | { 1526 | "name": "amounts", 1527 | "type": "uint256[2]" 1528 | }, 1529 | { 1530 | "name": "max_burn_amount", 1531 | "type": "uint256" 1532 | } 1533 | ], 1534 | "name": "remove_liquidity_imbalance", 1535 | "outputs": [], 1536 | "stateMutability": "nonpayable", 1537 | "type": "function" 1538 | }, 1539 | { 1540 | "gas": 1102, 1541 | "inputs": [ 1542 | { 1543 | "name": "_token_amount", 1544 | "type": "uint256" 1545 | }, 1546 | { 1547 | "name": "i", 1548 | "type": "int128" 1549 | } 1550 | ], 1551 | "name": "calc_withdraw_one_coin", 1552 | "outputs": [ 1553 | { 1554 | "name": "", 1555 | "type": "uint256" 1556 | } 1557 | ], 1558 | "stateMutability": "view", 1559 | "type": "function" 1560 | }, 1561 | { 1562 | "gas": 3660494, 1563 | "inputs": [ 1564 | { 1565 | "name": "_token_amount", 1566 | "type": "uint256" 1567 | }, 1568 | { 1569 | "name": "i", 1570 | "type": "int128" 1571 | }, 1572 | { 1573 | "name": "min_amount", 1574 | "type": "uint256" 1575 | } 1576 | ], 1577 | "name": "remove_liquidity_one_coin", 1578 | "outputs": [], 1579 | "stateMutability": "nonpayable", 1580 | "type": "function" 1581 | }, 1582 | { 1583 | "gas": 151919, 1584 | "inputs": [ 1585 | { 1586 | "name": "_future_A", 1587 | "type": "uint256" 1588 | }, 1589 | { 1590 | "name": "_future_time", 1591 | "type": "uint256" 1592 | } 1593 | ], 1594 | "name": "ramp_A", 1595 | "outputs": [], 1596 | "stateMutability": "nonpayable", 1597 | "type": "function" 1598 | }, 1599 | { 1600 | "gas": 148637, 1601 | "inputs": [], 1602 | "name": "stop_ramp_A", 1603 | "outputs": [], 1604 | "stateMutability": "nonpayable", 1605 | "type": "function" 1606 | }, 1607 | { 1608 | "gas": 110461, 1609 | "inputs": [ 1610 | { 1611 | "name": "new_fee", 1612 | "type": "uint256" 1613 | }, 1614 | { 1615 | "name": "new_admin_fee", 1616 | "type": "uint256" 1617 | } 1618 | ], 1619 | "name": "commit_new_fee", 1620 | "outputs": [], 1621 | "stateMutability": "nonpayable", 1622 | "type": "function" 1623 | }, 1624 | { 1625 | "gas": 97242, 1626 | "inputs": [], 1627 | "name": "apply_new_fee", 1628 | "outputs": [], 1629 | "stateMutability": "nonpayable", 1630 | "type": "function" 1631 | }, 1632 | { 1633 | "gas": 21895, 1634 | "inputs": [], 1635 | "name": "revert_new_parameters", 1636 | "outputs": [], 1637 | "stateMutability": "nonpayable", 1638 | "type": "function" 1639 | }, 1640 | { 1641 | "gas": 74572, 1642 | "inputs": [ 1643 | { 1644 | "name": "_owner", 1645 | "type": "address" 1646 | } 1647 | ], 1648 | "name": "commit_transfer_ownership", 1649 | "outputs": [], 1650 | "stateMutability": "nonpayable", 1651 | "type": "function" 1652 | }, 1653 | { 1654 | "gas": 60710, 1655 | "inputs": [], 1656 | "name": "apply_transfer_ownership", 1657 | "outputs": [], 1658 | "stateMutability": "nonpayable", 1659 | "type": "function" 1660 | }, 1661 | { 1662 | "gas": 21985, 1663 | "inputs": [], 1664 | "name": "revert_transfer_ownership", 1665 | "outputs": [], 1666 | "stateMutability": "nonpayable", 1667 | "type": "function" 1668 | }, 1669 | { 1670 | "gas": 3481, 1671 | "inputs": [ 1672 | { 1673 | "name": "i", 1674 | "type": "uint256" 1675 | } 1676 | ], 1677 | "name": "admin_balances", 1678 | "outputs": [ 1679 | { 1680 | "name": "", 1681 | "type": "uint256" 1682 | } 1683 | ], 1684 | "stateMutability": "view", 1685 | "type": "function" 1686 | }, 1687 | { 1688 | "gas": 9218, 1689 | "inputs": [], 1690 | "name": "withdraw_admin_fees", 1691 | "outputs": [], 1692 | "stateMutability": "nonpayable", 1693 | "type": "function" 1694 | }, 1695 | { 1696 | "gas": 74965, 1697 | "inputs": [], 1698 | "name": "donate_admin_fees", 1699 | "outputs": [], 1700 | "stateMutability": "nonpayable", 1701 | "type": "function" 1702 | }, 1703 | { 1704 | "gas": 37998, 1705 | "inputs": [], 1706 | "name": "kill_me", 1707 | "outputs": [], 1708 | "stateMutability": "nonpayable", 1709 | "type": "function" 1710 | }, 1711 | { 1712 | "gas": 22135, 1713 | "inputs": [], 1714 | "name": "unkill_me", 1715 | "outputs": [], 1716 | "stateMutability": "nonpayable", 1717 | "type": "function" 1718 | }, 1719 | { 1720 | "gas": 2220, 1721 | "inputs": [ 1722 | { 1723 | "name": "arg0", 1724 | "type": "uint256" 1725 | } 1726 | ], 1727 | "name": "coins", 1728 | "outputs": [ 1729 | { 1730 | "name": "", 1731 | "type": "address" 1732 | } 1733 | ], 1734 | "stateMutability": "view", 1735 | "type": "function" 1736 | }, 1737 | { 1738 | "gas": 2250, 1739 | "inputs": [ 1740 | { 1741 | "name": "arg0", 1742 | "type": "uint256" 1743 | } 1744 | ], 1745 | "name": "balances", 1746 | "outputs": [ 1747 | { 1748 | "name": "", 1749 | "type": "uint256" 1750 | } 1751 | ], 1752 | "stateMutability": "view", 1753 | "type": "function" 1754 | }, 1755 | { 1756 | "gas": 2171, 1757 | "inputs": [], 1758 | "name": "fee", 1759 | "outputs": [ 1760 | { 1761 | "name": "", 1762 | "type": "uint256" 1763 | } 1764 | ], 1765 | "stateMutability": "view", 1766 | "type": "function" 1767 | }, 1768 | { 1769 | "gas": 2201, 1770 | "inputs": [], 1771 | "name": "admin_fee", 1772 | "outputs": [ 1773 | { 1774 | "name": "", 1775 | "type": "uint256" 1776 | } 1777 | ], 1778 | "stateMutability": "view", 1779 | "type": "function" 1780 | }, 1781 | { 1782 | "gas": 2231, 1783 | "inputs": [], 1784 | "name": "owner", 1785 | "outputs": [ 1786 | { 1787 | "name": "", 1788 | "type": "address" 1789 | } 1790 | ], 1791 | "stateMutability": "view", 1792 | "type": "function" 1793 | }, 1794 | { 1795 | "gas": 2261, 1796 | "inputs": [], 1797 | "name": "initial_A", 1798 | "outputs": [ 1799 | { 1800 | "name": "", 1801 | "type": "uint256" 1802 | } 1803 | ], 1804 | "stateMutability": "view", 1805 | "type": "function" 1806 | }, 1807 | { 1808 | "gas": 2291, 1809 | "inputs": [], 1810 | "name": "future_A", 1811 | "outputs": [ 1812 | { 1813 | "name": "", 1814 | "type": "uint256" 1815 | } 1816 | ], 1817 | "stateMutability": "view", 1818 | "type": "function" 1819 | }, 1820 | { 1821 | "gas": 2321, 1822 | "inputs": [], 1823 | "name": "initial_A_time", 1824 | "outputs": [ 1825 | { 1826 | "name": "", 1827 | "type": "uint256" 1828 | } 1829 | ], 1830 | "stateMutability": "view", 1831 | "type": "function" 1832 | }, 1833 | { 1834 | "gas": 2351, 1835 | "inputs": [], 1836 | "name": "future_A_time", 1837 | "outputs": [ 1838 | { 1839 | "name": "", 1840 | "type": "uint256" 1841 | } 1842 | ], 1843 | "stateMutability": "view", 1844 | "type": "function" 1845 | }, 1846 | { 1847 | "gas": 2381, 1848 | "inputs": [], 1849 | "name": "admin_actions_deadline", 1850 | "outputs": [ 1851 | { 1852 | "name": "", 1853 | "type": "uint256" 1854 | } 1855 | ], 1856 | "stateMutability": "view", 1857 | "type": "function" 1858 | }, 1859 | { 1860 | "gas": 2411, 1861 | "inputs": [], 1862 | "name": "transfer_ownership_deadline", 1863 | "outputs": [ 1864 | { 1865 | "name": "", 1866 | "type": "uint256" 1867 | } 1868 | ], 1869 | "stateMutability": "view", 1870 | "type": "function" 1871 | }, 1872 | { 1873 | "gas": 2441, 1874 | "inputs": [], 1875 | "name": "future_fee", 1876 | "outputs": [ 1877 | { 1878 | "name": "", 1879 | "type": "uint256" 1880 | } 1881 | ], 1882 | "stateMutability": "view", 1883 | "type": "function" 1884 | }, 1885 | { 1886 | "gas": 2471, 1887 | "inputs": [], 1888 | "name": "future_admin_fee", 1889 | "outputs": [ 1890 | { 1891 | "name": "", 1892 | "type": "uint256" 1893 | } 1894 | ], 1895 | "stateMutability": "view", 1896 | "type": "function" 1897 | }, 1898 | { 1899 | "gas": 2501, 1900 | "inputs": [], 1901 | "name": "future_owner", 1902 | "outputs": [ 1903 | { 1904 | "name": "", 1905 | "type": "address" 1906 | } 1907 | ], 1908 | "stateMutability": "view", 1909 | "type": "function" 1910 | } 1911 | ] 1912 | """) 1913 | 1914 | IDLE_ABI = json.loads("""[{"name":"TokenExchange","inputs":[{"type":"address","name":"buyer","indexed":true},{"type":"int128","name":"sold_id","indexed":false},{"type":"uint256","name":"tokens_sold","indexed":false},{"type":"int128","name":"bought_id","indexed":false},{"type":"uint256","name":"tokens_bought","indexed":false}],"anonymous":false,"type":"event"},{"name":"TokenExchangeUnderlying","inputs":[{"type":"address","name":"buyer","indexed":true},{"type":"int128","name":"sold_id","indexed":false},{"type":"uint256","name":"tokens_sold","indexed":false},{"type":"int128","name":"bought_id","indexed":false},{"type":"uint256","name":"tokens_bought","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityOne","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256","name":"token_amount","indexed":false},{"type":"uint256","name":"coin_amount","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityImbalance","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"CommitNewAdmin","inputs":[{"type":"uint256","name":"deadline","indexed":true},{"type":"address","name":"admin","indexed":true}],"anonymous":false,"type":"event"},{"name":"NewAdmin","inputs":[{"type":"address","name":"admin","indexed":true}],"anonymous":false,"type":"event"},{"name":"CommitNewFee","inputs":[{"type":"uint256","name":"deadline","indexed":true},{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false,"type":"event"},{"name":"NewFee","inputs":[{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false,"type":"event"},{"name":"RampA","inputs":[{"type":"uint256","name":"old_A","indexed":false},{"type":"uint256","name":"new_A","indexed":false},{"type":"uint256","name":"initial_time","indexed":false},{"type":"uint256","name":"future_time","indexed":false}],"anonymous":false,"type":"event"},{"name":"StopRampA","inputs":[{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"t","indexed":false}],"anonymous":false,"type":"event"},{"outputs":[],"inputs":[{"type":"address","name":"_owner"},{"type":"address","name":"_reward_admin"},{"type":"address","name":"_reward_claimant"},{"type":"address[3]","name":"_coins"},{"type":"address[3]","name":"_underlying_coins"},{"type":"address","name":"_pool_token"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"},{"type":"uint256","name":"_admin_fee"}],"stateMutability":"nonpayable","type":"constructor"},{"name":"A","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":5199},{"name":"A_precise","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":5161},{"name":"get_virtual_price","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":1194016},{"name":"calc_token_amount","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"amounts"},{"type":"bool","name":"is_deposit"}],"stateMutability":"view","type":"function","gas":4725859},{"name":"add_liquidity","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_min_mint_amount"}],"stateMutability":"nonpayable","type":"function"},{"name":"add_liquidity","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_min_mint_amount"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"get_dy","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"}],"stateMutability":"view","type":"function","gas":2809093},{"name":"get_dx","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dy"}],"stateMutability":"view","type":"function","gas":2808954},{"name":"get_dy_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"}],"stateMutability":"view","type":"function","gas":2808933},{"name":"get_dx_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dy"}],"stateMutability":"view","type":"function","gas":2808794},{"name":"exchange","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"},{"type":"uint256","name":"min_dy"}],"stateMutability":"nonpayable","type":"function","gas":5769355},{"name":"exchange_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"},{"type":"uint256","name":"min_dy"}],"stateMutability":"nonpayable","type":"function","gas":5773227},{"name":"remove_liquidity","outputs":[{"type":"uint256[3]","name":""}],"inputs":[{"type":"uint256","name":"_amount"},{"type":"uint256[3]","name":"_min_amounts"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity","outputs":[{"type":"uint256[3]","name":""}],"inputs":[{"type":"uint256","name":"_amount"},{"type":"uint256[3]","name":"_min_amounts"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity_imbalance","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_max_burn_amount"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity_imbalance","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_max_burn_amount"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"calc_withdraw_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"}],"stateMutability":"view","type":"function"},{"name":"calc_withdraw_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"view","type":"function"},{"name":"remove_liquidity_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"uint256","name":"_min_amount"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"uint256","name":"_min_amount"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"ramp_A","outputs":[],"inputs":[{"type":"uint256","name":"_future_A"},{"type":"uint256","name":"_future_time"}],"stateMutability":"nonpayable","type":"function","gas":151924},{"name":"stop_ramp_A","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":148685},{"name":"commit_new_fee","outputs":[],"inputs":[{"type":"uint256","name":"new_fee"},{"type":"uint256","name":"new_admin_fee"}],"stateMutability":"nonpayable","type":"function","gas":110521},{"name":"apply_new_fee","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":97302},{"name":"revert_new_parameters","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":21955},{"name":"commit_transfer_ownership","outputs":[],"inputs":[{"type":"address","name":"_owner"}],"stateMutability":"nonpayable","type":"function","gas":74693},{"name":"apply_transfer_ownership","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":60770},{"name":"revert_transfer_ownership","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":22045},{"name":"admin_balances","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"i"}],"stateMutability":"view","type":"function","gas":3541},{"name":"withdraw_admin_fees","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":14528},{"name":"donate_admin_fees","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":111449},{"name":"kill_me","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":38058},{"name":"unkill_me","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":22195},{"name":"claim_rewards","outputs":[{"type":"bool","name":""}],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":27334},{"name":"set_reward_claimant","outputs":[],"inputs":[{"type":"address","name":"_reward_claimant"}],"stateMutability":"nonpayable","type":"function","gas":37358},{"name":"set_reward_admin","outputs":[],"inputs":[{"type":"address","name":"_reward_admin"}],"stateMutability":"nonpayable","type":"function","gas":37388},{"name":"set_rewards","outputs":[],"inputs":[{"type":"address[8]","name":"_rewards"}],"stateMutability":"nonpayable","type":"function","gas":296715},{"name":"coins","outputs":[{"type":"address","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2400},{"name":"underlying_coins","outputs":[{"type":"address","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2430},{"name":"balances","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2460},{"name":"fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2381},{"name":"admin_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2411},{"name":"owner","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2441},{"name":"lp_token","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2471},{"name":"initial_A","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2501},{"name":"future_A","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2531},{"name":"initial_A_time","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2561},{"name":"future_A_time","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2591},{"name":"admin_actions_deadline","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2621},{"name":"transfer_ownership_deadline","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2651},{"name":"future_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2681},{"name":"future_admin_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2711},{"name":"future_owner","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2741},{"name":"reward_tokens","outputs":[{"type":"address","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2880},{"name":"reward_claimant","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2801},{"name":"reward_admin","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2831}]""") 1915 | 1916 | YV2_ABI = json.loads("""[{"name":"TokenExchange","inputs":[{"type":"address","name":"buyer","indexed":true},{"type":"int128","name":"sold_id","indexed":false},{"type":"uint256","name":"tokens_sold","indexed":false},{"type":"int128","name":"bought_id","indexed":false},{"type":"uint256","name":"tokens_bought","indexed":false}],"anonymous":false,"type":"event"},{"name":"TokenExchangeUnderlying","inputs":[{"type":"address","name":"buyer","indexed":true},{"type":"int128","name":"sold_id","indexed":false},{"type":"uint256","name":"tokens_sold","indexed":false},{"type":"int128","name":"bought_id","indexed":false},{"type":"uint256","name":"tokens_bought","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityOne","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256","name":"token_amount","indexed":false},{"type":"uint256","name":"coin_amount","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityImbalance","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[3]","name":"token_amounts","indexed":false},{"type":"uint256[3]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false,"type":"event"},{"name":"CommitNewAdmin","inputs":[{"type":"uint256","name":"deadline","indexed":true},{"type":"address","name":"admin","indexed":true}],"anonymous":false,"type":"event"},{"name":"NewAdmin","inputs":[{"type":"address","name":"admin","indexed":true}],"anonymous":false,"type":"event"},{"name":"CommitNewFee","inputs":[{"type":"uint256","name":"deadline","indexed":true},{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false,"type":"event"},{"name":"NewFee","inputs":[{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false,"type":"event"},{"name":"RampA","inputs":[{"type":"uint256","name":"old_A","indexed":false},{"type":"uint256","name":"new_A","indexed":false},{"type":"uint256","name":"initial_time","indexed":false},{"type":"uint256","name":"future_time","indexed":false}],"anonymous":false,"type":"event"},{"name":"StopRampA","inputs":[{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"t","indexed":false}],"anonymous":false,"type":"event"},{"outputs":[],"inputs":[{"type":"address","name":"_owner"},{"type":"address[3]","name":"_coins"},{"type":"address[3]","name":"_underlying_coins"},{"type":"address","name":"_pool_token"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"},{"type":"uint256","name":"_admin_fee"}],"stateMutability":"nonpayable","type":"constructor"},{"name":"A","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":5199},{"name":"A_precise","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":5161},{"name":"get_virtual_price","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":1198876},{"name":"calc_token_amount","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"amounts"},{"type":"bool","name":"is_deposit"}],"stateMutability":"view","type":"function","gas":4730885},{"name":"add_liquidity","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_min_mint_amount"}],"stateMutability":"nonpayable","type":"function"},{"name":"add_liquidity","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_min_mint_amount"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"get_dy","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"}],"stateMutability":"view","type":"function","gas":2814013},{"name":"get_dx","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dy"}],"stateMutability":"view","type":"function","gas":2813874},{"name":"get_dy_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"}],"stateMutability":"view","type":"function","gas":2813853},{"name":"get_dx_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dy"}],"stateMutability":"view","type":"function","gas":2813714},{"name":"exchange","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"},{"type":"uint256","name":"min_dy"}],"stateMutability":"nonpayable","type":"function","gas":5773633},{"name":"exchange_underlying","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"dx"},{"type":"uint256","name":"min_dy"}],"stateMutability":"nonpayable","type":"function","gas":5777954},{"name":"remove_liquidity","outputs":[{"type":"uint256[3]","name":""}],"inputs":[{"type":"uint256","name":"_amount"},{"type":"uint256[3]","name":"_min_amounts"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity","outputs":[{"type":"uint256[3]","name":""}],"inputs":[{"type":"uint256","name":"_amount"},{"type":"uint256[3]","name":"_min_amounts"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity_imbalance","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_max_burn_amount"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity_imbalance","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256[3]","name":"_amounts"},{"type":"uint256","name":"_max_burn_amount"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"calc_withdraw_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"}],"stateMutability":"view","type":"function"},{"name":"calc_withdraw_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"view","type":"function"},{"name":"remove_liquidity_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"uint256","name":"_min_amount"}],"stateMutability":"nonpayable","type":"function"},{"name":"remove_liquidity_one_coin","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"uint256","name":"_min_amount"},{"type":"bool","name":"_use_underlying"}],"stateMutability":"nonpayable","type":"function"},{"name":"ramp_A","outputs":[],"inputs":[{"type":"uint256","name":"_future_A"},{"type":"uint256","name":"_future_time"}],"stateMutability":"nonpayable","type":"function","gas":151954},{"name":"stop_ramp_A","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":148715},{"name":"commit_new_fee","outputs":[],"inputs":[{"type":"uint256","name":"new_fee"},{"type":"uint256","name":"new_admin_fee"}],"stateMutability":"nonpayable","type":"function","gas":110551},{"name":"apply_new_fee","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":97332},{"name":"revert_new_parameters","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":21985},{"name":"commit_transfer_ownership","outputs":[],"inputs":[{"type":"address","name":"_owner"}],"stateMutability":"nonpayable","type":"function","gas":74723},{"name":"apply_transfer_ownership","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":60800},{"name":"revert_transfer_ownership","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":22075},{"name":"admin_balances","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"i"}],"stateMutability":"view","type":"function","gas":3571},{"name":"withdraw_admin_fees","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":14558},{"name":"donate_admin_fees","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":111479},{"name":"kill_me","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":38088},{"name":"unkill_me","outputs":[],"inputs":[],"stateMutability":"nonpayable","type":"function","gas":22225},{"name":"coins","outputs":[{"type":"address","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2310},{"name":"underlying_coins","outputs":[{"type":"address","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2340},{"name":"balances","outputs":[{"type":"uint256","name":""}],"inputs":[{"type":"uint256","name":"arg0"}],"stateMutability":"view","type":"function","gas":2370},{"name":"fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2291},{"name":"admin_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2321},{"name":"owner","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2351},{"name":"lp_token","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2381},{"name":"initial_A","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2411},{"name":"future_A","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2441},{"name":"initial_A_time","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2471},{"name":"future_A_time","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2501},{"name":"admin_actions_deadline","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2531},{"name":"transfer_ownership_deadline","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2561},{"name":"future_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2591},{"name":"future_admin_fee","outputs":[{"type":"uint256","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2621},{"name":"future_owner","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2651}]""") 1917 | 1918 | RAI_ABI = json.loads("""[{"name":"TokenExchange","inputs":[{"name":"buyer","type":"address","indexed":true},{"name":"sold_id","type":"int128","indexed":false},{"name":"tokens_sold","type":"uint256","indexed":false},{"name":"bought_id","type":"int128","indexed":false},{"name":"tokens_bought","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"TokenExchangeUnderlying","inputs":[{"name":"buyer","type":"address","indexed":true},{"name":"sold_id","type":"int128","indexed":false},{"name":"tokens_sold","type":"uint256","indexed":false},{"name":"bought_id","type":"int128","indexed":false},{"name":"tokens_bought","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddLiquidity","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amounts","type":"uint256[2]","indexed":false},{"name":"fees","type":"uint256[2]","indexed":false},{"name":"invariant","type":"uint256","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidity","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amounts","type":"uint256[2]","indexed":false},{"name":"fees","type":"uint256[2]","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityOne","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amount","type":"uint256","indexed":false},{"name":"coin_amount","type":"uint256","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityImbalance","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amounts","type":"uint256[2]","indexed":false},{"name":"fees","type":"uint256[2]","indexed":false},{"name":"invariant","type":"uint256","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"CommitNewAdmin","inputs":[{"name":"deadline","type":"uint256","indexed":true},{"name":"admin","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"NewAdmin","inputs":[{"name":"admin","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"CommitNewFee","inputs":[{"name":"deadline","type":"uint256","indexed":true},{"name":"fee","type":"uint256","indexed":false},{"name":"admin_fee","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"NewFee","inputs":[{"name":"fee","type":"uint256","indexed":false},{"name":"admin_fee","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RampA","inputs":[{"name":"old_A","type":"uint256","indexed":false},{"name":"new_A","type":"uint256","indexed":false},{"name":"initial_time","type":"uint256","indexed":false},{"name":"future_time","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"StopRampA","inputs":[{"name":"A","type":"uint256","indexed":false},{"name":"t","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_owner","type":"address"},{"name":"_coins","type":"address[2]"},{"name":"_pool_token","type":"address"},{"name":"_base_pool","type":"address"},{"name":"_redemption_price_snap","type":"address"},{"name":"_A","type":"uint256"},{"name":"_fee","type":"uint256"},{"name":"_admin_fee","type":"uint256"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"A","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":10374},{"stateMutability":"view","type":"function","name":"A_precise","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":10336},{"stateMutability":"view","type":"function","name":"get_virtual_price","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":2070135},{"stateMutability":"view","type":"function","name":"get_virtual_price_2","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":2295357},{"stateMutability":"view","type":"function","name":"calc_token_amount","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_is_deposit","type":"bool"}],"outputs":[{"name":"","type":"uint256"}],"gas":4038330},{"stateMutability":"nonpayable","type":"function","name":"add_liquidity","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_min_mint_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":6231201},{"stateMutability":"view","type":"function","name":"get_dy","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":2483148},{"stateMutability":"view","type":"function","name":"get_dy_underlying","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":2494262},{"stateMutability":"nonpayable","type":"function","name":"exchange","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":2723828},{"stateMutability":"nonpayable","type":"function","name":"exchange_underlying","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":2754318},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity","inputs":[{"name":"_amount","type":"uint256"},{"name":"_min_amounts","type":"uint256[2]"}],"outputs":[{"name":"","type":"uint256[2]"}],"gas":174423},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity_imbalance","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_max_burn_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":6216452},{"stateMutability":"view","type":"function","name":"calc_withdraw_one_coin","inputs":[{"name":"_token_amount","type":"uint256"},{"name":"i","type":"int128"}],"outputs":[{"name":"","type":"uint256"}],"gas":8658},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity_one_coin","inputs":[{"name":"_token_amount","type":"uint256"},{"name":"i","type":"int128"},{"name":"_min_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":4009643},{"stateMutability":"nonpayable","type":"function","name":"ramp_A","inputs":[{"name":"_future_A","type":"uint256"},{"name":"_future_time","type":"uint256"}],"outputs":[],"gas":159429},{"stateMutability":"nonpayable","type":"function","name":"stop_ramp_A","inputs":[],"outputs":[],"gas":154890},{"stateMutability":"nonpayable","type":"function","name":"commit_new_fee","inputs":[{"name":"_new_fee","type":"uint256"},{"name":"_new_admin_fee","type":"uint256"}],"outputs":[],"gas":112848},{"stateMutability":"nonpayable","type":"function","name":"apply_new_fee","inputs":[],"outputs":[],"gas":103529},{"stateMutability":"nonpayable","type":"function","name":"revert_new_parameters","inputs":[],"outputs":[],"gas":22982},{"stateMutability":"nonpayable","type":"function","name":"commit_transfer_ownership","inputs":[{"name":"_owner","type":"address"}],"outputs":[],"gas":77020},{"stateMutability":"nonpayable","type":"function","name":"apply_transfer_ownership","inputs":[],"outputs":[],"gas":65697},{"stateMutability":"nonpayable","type":"function","name":"revert_transfer_ownership","inputs":[],"outputs":[],"gas":23072},{"stateMutability":"view","type":"function","name":"admin_balances","inputs":[{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":7928},{"stateMutability":"nonpayable","type":"function","name":"withdraw_admin_fees","inputs":[],"outputs":[],"gas":22177},{"stateMutability":"nonpayable","type":"function","name":"kill_me","inputs":[],"outputs":[],"gas":40355},{"stateMutability":"nonpayable","type":"function","name":"unkill_me","inputs":[],"outputs":[],"gas":23192},{"stateMutability":"view","type":"function","name":"coins","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}],"gas":3277},{"stateMutability":"view","type":"function","name":"balances","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":3307},{"stateMutability":"view","type":"function","name":"fee","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3228},{"stateMutability":"view","type":"function","name":"admin_fee","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3258},{"stateMutability":"view","type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3288},{"stateMutability":"view","type":"function","name":"lp_token","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3318},{"stateMutability":"view","type":"function","name":"redemption_price_snap","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3348},{"stateMutability":"view","type":"function","name":"base_pool","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3378},{"stateMutability":"view","type":"function","name":"base_virtual_price","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3408},{"stateMutability":"view","type":"function","name":"base_cache_updated","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3438},{"stateMutability":"view","type":"function","name":"base_coins","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}],"gas":3577},{"stateMutability":"view","type":"function","name":"initial_A","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3498},{"stateMutability":"view","type":"function","name":"future_A","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3528},{"stateMutability":"view","type":"function","name":"initial_A_time","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3558},{"stateMutability":"view","type":"function","name":"future_A_time","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3588},{"stateMutability":"view","type":"function","name":"admin_actions_deadline","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3618},{"stateMutability":"view","type":"function","name":"transfer_ownership_deadline","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3648},{"stateMutability":"view","type":"function","name":"future_fee","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3678},{"stateMutability":"view","type":"function","name":"future_admin_fee","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3708},{"stateMutability":"view","type":"function","name":"future_owner","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3738}]""") 1919 | 1920 | RAI_PRICE_SNAP = """[{"inputs":[{"internalType":"address","name":"oracleRelayer_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"AddAuthorization","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"revertReason","type":"bytes"}],"name":"FailUpdateSnappedPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"parameter","type":"bytes32"},{"indexed":false,"internalType":"address","name":"data","type":"address"}],"name":"ModifyParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"RemoveAuthorization","type":"event"},{"inputs":[],"name":"TEN_THOUSAND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorizedAccounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"parameter","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"modifyParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracleRelayer","outputs":[{"internalType":"contract OracleRelayerLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"snappedRedemptionPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateAndGetSnappedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateSnappedPrice","outputs":[],"stateMutability":"nonpayable","type":"function"}]""" 1921 | -------------------------------------------------------------------------------- /curvestats/ankr.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Y (iearn) tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import NEW_ABI 7 | 8 | 9 | ANKR_ABI = TOKEN_ABI.copy() 10 | ANKR_ABI += [ 11 | { 12 | "inputs": [], 13 | "name": "ratio", 14 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 15 | "stateMutability": "view", 16 | "type": "function"} 17 | ] 18 | 19 | 20 | class ANKRPool(Pool): 21 | def __init__(self, *args, w3=None): 22 | super().__init__(*args, w3=w3, abi=NEW_ABI) 23 | for i in range(self.N): 24 | c = self.w3.eth.contract(abi=ANKR_ABI, address=self.coins[i]).functions 25 | self.coins[i] = c 26 | 27 | def get_rate(self, i, block=None): 28 | if not block: 29 | block = self.w3.eth.getBlock('latest')['number'] 30 | kw = {'block_identifier': block} 31 | use_lending = (self.coins[i].address != "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") 32 | rate = 10 ** 18 33 | if use_lending: 34 | rate = 10**18 * 10**18 // self.coins[i].ratio().call(**kw) 35 | return rate 36 | -------------------------------------------------------------------------------- /curvestats/btc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Bitcoin tokens where Ren, like Compound, uses exchangeRateCurrent 3 | """ 4 | 5 | from web3.exceptions import BadFunctionCallOutput 6 | from . import Pool, TOKEN_ABI 7 | from .abi import NEW_ABI 8 | 9 | 10 | COMPOUND_ABI = TOKEN_ABI.copy() 11 | COMPOUND_ABI += [ 12 | { 13 | "constant": True, 14 | "inputs": [], 15 | "name": "exchangeRateCurrent", 16 | "outputs": [ 17 | { 18 | "name": "", 19 | "type": "uint256" 20 | } 21 | ], 22 | "payable": False, 23 | "stateMutability": "view", 24 | "type": "function", 25 | "signature": "0x182df0f5" 26 | }, 27 | ] 28 | 29 | 30 | class BtcPool(Pool): 31 | def __init__(self, *args, w3=None): 32 | super().__init__(*args, w3=w3) 33 | for i in range(self.N): 34 | c = self.w3.eth.contract(abi=COMPOUND_ABI, address=self.coins[i]).functions 35 | self.coins[i] = c 36 | 37 | def get_rate(self, i, block=None): 38 | if not block: 39 | block = self.w3.eth.getBlock('latest')['number'] 40 | kw = {'block_identifier': block} 41 | 42 | try: 43 | rate = self.coins[i].exchangeRateCurrent().call(**kw) 44 | except (BadFunctionCallOutput, ValueError): 45 | rate = 10 ** 18 46 | return rate 47 | 48 | 49 | class NewBtcPool(Pool): 50 | def __init__(self, *args, w3=None): 51 | super().__init__(*args, w3=w3, abi=NEW_ABI) 52 | for i in range(self.N): 53 | c = self.w3.eth.contract(abi=COMPOUND_ABI, address=self.coins[i]).functions 54 | self.coins[i] = c 55 | 56 | def get_rate(self, i, block=None): 57 | if not block: 58 | block = self.w3.eth.getBlock('latest')['number'] 59 | kw = {'block_identifier': block} 60 | 61 | try: 62 | rate = self.coins[i].exchangeRateCurrent().call(**kw) 63 | except (BadFunctionCallOutput, ValueError): 64 | rate = 10 ** 18 65 | return rate 66 | -------------------------------------------------------------------------------- /curvestats/compound.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | 7 | 8 | COMPOUND_ABI = TOKEN_ABI.copy() 9 | COMPOUND_ABI += [ 10 | { 11 | "constant": True, 12 | "inputs": [], 13 | "name": "exchangeRateStored", 14 | "outputs": [ 15 | { 16 | "name": "", 17 | "type": "uint256" 18 | } 19 | ], 20 | "payable": False, 21 | "stateMutability": "view", 22 | "type": "function", 23 | "signature": "0x182df0f5" 24 | }, 25 | { 26 | "constant": True, 27 | "inputs": [], 28 | "name": "supplyRatePerBlock", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "uint256" 33 | } 34 | ], 35 | "payable": False, 36 | "stateMutability": "view", 37 | "type": "function", 38 | "signature": "0xae9d70b0" 39 | }, 40 | { 41 | "constant": True, 42 | "inputs": [], 43 | "name": "accrualBlockNumber", 44 | "outputs": [ 45 | { 46 | "name": "", 47 | "type": "uint256" 48 | } 49 | ], 50 | "payable": False, 51 | "stateMutability": "view", 52 | "type": "function", 53 | "signature": "0x6c540baf" 54 | }, 55 | ] 56 | 57 | 58 | class CompoundPool(Pool): 59 | def __init__(self, *args, w3=None): 60 | super().__init__(*args, w3=w3) 61 | for i in range(self.N): 62 | c = self.w3.eth.contract(abi=COMPOUND_ABI, address=self.coins[i]).functions 63 | self.coins[i] = c 64 | 65 | def get_rate(self, i, block=None): 66 | if not block: 67 | block = self.w3.eth.getBlock('latest')['number'] 68 | kw = {'block_identifier': block} 69 | use_lending = (self.coins[i].address != self.underlying_coins[i].address) 70 | 71 | rate = 10 ** 18 72 | if use_lending: 73 | rate = self.coins[i].exchangeRateStored().call(**kw) 74 | supply_rate = self.coins[i].supplyRatePerBlock().call(**kw) 75 | old_block = self.coins[i].accrualBlockNumber().call(**kw) 76 | rate += rate * supply_rate * (block - old_block) // 10 ** 18 77 | return rate 78 | -------------------------------------------------------------------------------- /curvestats/icy.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import NEW_ABI 7 | 8 | ABI = NEW_ABI.copy() 9 | ABI += [{"name":"get_coin_rates","outputs":[{"type":"uint256[6]","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":20572}] 10 | 11 | 12 | class IcyPool(Pool): 13 | def __init__(self, *args, w3=None): 14 | super().__init__(*args, w3=w3, abi=ABI) 15 | for i in range(self.N): 16 | c = self.w3.eth.contract(abi=TOKEN_ABI, address=self.coins[i]).functions 17 | self.coins[i] = c 18 | 19 | def get_rate(self, i, block=None): 20 | if not block: 21 | block = self.w3.eth.getBlock('latest')['number'] 22 | kw = {'block_identifier': block} 23 | use_lending = (i < self.N - 1) 24 | 25 | rate = 10 ** 18 26 | if use_lending: 27 | rate = self.pool.get_coin_rates().call(**kw)[i] 28 | return rate 29 | -------------------------------------------------------------------------------- /curvestats/idle.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Y (iearn) tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import IDLE_ABI as IDLE_POOL_ABI 7 | 8 | 9 | IDLE_ABI = TOKEN_ABI.copy() 10 | IDLE_ABI += [ 11 | { 12 | "constant": True, 13 | "inputs": [], 14 | "name": "tokenPrice", 15 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 16 | "payable": False, 17 | "stateMutability": "view", 18 | "type": "function"} 19 | ] 20 | 21 | 22 | class IDLEPool(Pool): 23 | def __init__(self, *args, w3=None): 24 | super().__init__(*args, w3=w3, abi=IDLE_POOL_ABI) 25 | for i in range(self.N): 26 | c = self.w3.eth.contract(abi=IDLE_ABI, address=self.coins[i]).functions 27 | self.coins[i] = c 28 | 29 | def get_rate(self, i, block=None): 30 | if not block: 31 | block = self.w3.eth.getBlock('latest')['number'] 32 | kw = {'block_identifier': block} 33 | use_lending = (self.coins[i].address != self.underlying_coins[i].address) 34 | 35 | rate = 10 ** 18 36 | if use_lending: 37 | rate = self.coins[i].tokenPrice().call(**kw) 38 | return rate 39 | -------------------------------------------------------------------------------- /curvestats/meta.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from retry import retry 6 | from web3.exceptions import BadFunctionCallOutput, ABIFunctionNotFound, ABIEventFunctionNotFound 7 | from . import Pool, TOKEN_ABI 8 | from .abi import NEW_ABI 9 | 10 | ABI = NEW_ABI.copy() 11 | ABI += [{"name":"base_pool","outputs":[{"type":"address","name":""}],"inputs":[],"stateMutability":"view","type":"function","gas":2291}] 12 | 13 | 14 | class MetaPool: 15 | def __init__(self, pool, token, w3=None, abi=ABI): 16 | if not w3: 17 | from web3.auto.infura import w3 as infura_w3 18 | self.w3 = infura_w3 19 | else: 20 | self.w3 = w3 21 | self.pool_contract = self.w3.eth.contract(abi=abi, address=pool) 22 | self.pool = self.pool_contract.functions 23 | self.token_contract = self.w3.eth.contract(abi=TOKEN_ABI, address=token) 24 | self.token = self.token_contract.functions 25 | self.base_pool = self.w3.eth.contract(abi=ABI, address=self.pool.base_pool().call()).functions 26 | 27 | self.coins = [] 28 | for i in range(10): 29 | try: 30 | self.pool.balances(i).call() 31 | c = self.pool.coins(i).call() 32 | self.coins.append(c) 33 | except (BadFunctionCallOutput, ValueError): 34 | break 35 | self.N = len(self.coins) 36 | self.coins = [self.w3.eth.contract(abi=TOKEN_ABI, address=addr).functions for addr in self.coins] 37 | self.decimals = [c.decimals().call() for c in self.coins] 38 | 39 | self.underlying_coins = self.coins[:-1] 40 | self.underlying_decimals = self.decimals[:-1] 41 | self.underlying_N = self.N - 1 42 | for i in range(10): 43 | try: 44 | self.base_pool.balances(i).call() 45 | uc = self.base_pool.coins(i).call() 46 | uc = self.w3.eth.contract(abi=TOKEN_ABI, address=uc).functions 47 | self.underlying_coins.append(uc) 48 | self.underlying_decimals.append(uc.decimals().call()) 49 | self.underlying_N += 1 50 | except (BadFunctionCallOutput, ValueError): 51 | break 52 | 53 | def get_rate(self, i, underlying=False, block=None): 54 | if not block: 55 | block = self.w3.eth.getBlock('latest')['number'] 56 | kw = {'block_identifier': block} 57 | use_lending = (i == self.N - 1) and not underlying 58 | 59 | rate = 10 ** 18 60 | if use_lending: 61 | rate = self.base_pool.get_virtual_price().call(**kw) 62 | return rate 63 | 64 | @retry(Exception, delay=5, tries=5, backoff=2) 65 | def fetch_stats(self, block='latest'): 66 | full_block = self.w3.eth.getBlock(block) 67 | block = full_block['number'] 68 | timestamp = full_block['timestamp'] 69 | kw = {'block_identifier': block} 70 | rates = [self.get_rate(i, block=block) for i in range(self.N)] 71 | underlying_rate = 10 ** 18 72 | balances = [self.pool.balances(i).call(**kw) for i in range(self.N)] 73 | is_deposited = True 74 | for b in balances: 75 | is_deposited *= (b > 0) 76 | trades = [] 77 | 78 | try: 79 | for e in self.pool_contract.events.TokenExchangeUnderlying.getLogs(fromBlock=block, toBlock=block): 80 | ev = e['args'] 81 | trades.append({ 82 | 'sold_id': ev['sold_id'], 83 | 'tokens_sold': ev['tokens_sold'], 84 | 'bought_id': ev['bought_id'], 85 | 'tokens_bought': ev['tokens_bought'], 86 | 'underlying': True}) 87 | except ABIEventFunctionNotFound: 88 | pass 89 | 90 | for e in self.pool_contract.events.TokenExchange.getLogs(fromBlock=block, toBlock=block): 91 | ev = e['args'] 92 | trades.append({ 93 | 'sold_id': ev['sold_id'], 94 | 'tokens_sold': ev['tokens_sold'] * rates[ev['sold_id']] // 1e18, 95 | 'bought_id': ev['bought_id'], 96 | 'tokens_bought': ev['tokens_bought'] * rates[ev['bought_id']] // 1e18}) 97 | 98 | return { 99 | 'A': self.pool.A().call(**kw), 100 | 'fee': self.pool.fee().call(**kw), 101 | 'admin_fee': self.pool.admin_fee().call(**kw), 102 | 'supply': self.token.totalSupply().call(**kw), 103 | 'virtual_price': is_deposited and self.pool.get_virtual_price().call(**kw), 104 | 'timestamp': timestamp, 105 | 'balances': balances, 106 | 'rates': rates, 107 | 'underlying_rate': underlying_rate, 108 | 'trades': trades 109 | } 110 | -------------------------------------------------------------------------------- /curvestats/metaf.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from retry import retry 6 | from web3.exceptions import BadFunctionCallOutput, ABIEventFunctionNotFound 7 | from . import TOKEN_ABI 8 | from .abi import NEW_ABI 9 | 10 | ABI = NEW_ABI.copy() 11 | ABI += [{"name": "base_pool", "outputs": [{"type": "address", "name": ""}], "inputs": [], "stateMutability": "view", "type": "function", "gas": 2291}] 12 | 13 | 14 | class MetaPoolU: 15 | def __init__(self, pool, token, w3=None, abi=ABI): 16 | if not w3: 17 | from web3.auto.infura import w3 as infura_w3 18 | self.w3 = infura_w3 19 | else: 20 | self.w3 = w3 21 | self.pool_contract = self.w3.eth.contract(abi=abi, address=pool) 22 | self.pool = self.pool_contract.functions 23 | self.token_contract = self.w3.eth.contract(abi=TOKEN_ABI, address=token) 24 | self.token = self.token_contract.functions 25 | self.base_pool = self.w3.eth.contract(abi=ABI, address="0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7").functions 26 | 27 | self.coins = [] 28 | for i in range(10): 29 | try: 30 | self.pool.balances(i).call() 31 | c = self.pool.coins(i).call() 32 | self.coins.append(c) 33 | except (BadFunctionCallOutput, ValueError): 34 | break 35 | self.N = len(self.coins) 36 | self.coins = [self.w3.eth.contract(abi=TOKEN_ABI, address=addr).functions for addr in self.coins] 37 | self.decimals = [c.decimals().call() for c in self.coins] 38 | 39 | self.underlying_coins = self.coins[:-1] 40 | self.underlying_decimals = self.decimals[:-1] 41 | self.underlying_N = self.N - 1 42 | for i in range(10): 43 | try: 44 | self.base_pool.balances(i).call() 45 | uc = self.base_pool.coins(i).call() 46 | uc = self.w3.eth.contract(abi=TOKEN_ABI, address=uc).functions 47 | self.underlying_coins.append(uc) 48 | self.underlying_decimals.append(uc.decimals().call()) 49 | self.underlying_N += 1 50 | except (BadFunctionCallOutput, ValueError): 51 | break 52 | 53 | def get_rate(self, i, underlying=False, block=None): 54 | if not block: 55 | block = self.w3.eth.getBlock('latest')['number'] 56 | kw = {'block_identifier': block} 57 | use_lending = (i == self.N - 1) and not underlying 58 | 59 | rate = 10 ** 18 60 | if use_lending: 61 | rate = self.base_pool.get_virtual_price().call(**kw) 62 | return rate 63 | 64 | @retry(Exception, delay=5, tries=5, backoff=2) 65 | def fetch_stats(self, block='latest'): 66 | full_block = self.w3.eth.getBlock(block) 67 | block = full_block['number'] 68 | timestamp = full_block['timestamp'] 69 | kw = {'block_identifier': block} 70 | rates = [self.get_rate(i, block=block) for i in range(self.N)] 71 | underlying_rate = 10 ** 18 72 | balances = [self.pool.balances(i).call(**kw) for i in range(self.N)] 73 | is_deposited = True 74 | for b in balances: 75 | is_deposited *= (b > 0) 76 | trades = [] 77 | 78 | try: 79 | for e in self.pool_contract.events.TokenExchangeUnderlying.getLogs(fromBlock=block, toBlock=block): 80 | ev = e['args'] 81 | trades.append({ 82 | 'sold_id': ev['sold_id'], 83 | 'tokens_sold': ev['tokens_sold'], 84 | 'bought_id': ev['bought_id'], 85 | 'tokens_bought': ev['tokens_bought'], 86 | 'underlying': True}) 87 | except ABIEventFunctionNotFound: 88 | pass 89 | 90 | for e in self.pool_contract.events.TokenExchange.getLogs(fromBlock=block, toBlock=block): 91 | ev = e['args'] 92 | trades.append({ 93 | 'sold_id': ev['sold_id'], 94 | 'tokens_sold': ev['tokens_sold'] * rates[ev['sold_id']] // 1e18, 95 | 'bought_id': ev['bought_id'], 96 | 'tokens_bought': ev['tokens_bought'] * rates[ev['bought_id']] // 1e18}) 97 | 98 | return { 99 | 'A': self.pool.A().call(**kw), 100 | 'fee': self.pool.fee().call(**kw), 101 | 'admin_fee': self.pool.admin_fee().call(**kw), 102 | 'supply': self.token.totalSupply().call(**kw), 103 | 'virtual_price': is_deposited and self.pool.get_virtual_price().call(**kw), 104 | 'timestamp': timestamp, 105 | 'balances': balances, 106 | 'rates': rates, 107 | 'underlying_rate': underlying_rate, 108 | 'trades': trades 109 | } 110 | -------------------------------------------------------------------------------- /curvestats/newpool.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import NEW_ABI 7 | 8 | 9 | class NewPool(Pool): 10 | def __init__(self, *args, w3=None): 11 | super().__init__(*args, w3=w3, abi=NEW_ABI) 12 | for i in range(self.N): 13 | c = self.w3.eth.contract(abi=TOKEN_ABI, address=self.coins[i]).functions 14 | self.coins[i] = c 15 | 16 | def get_rate(self, i, block=None): 17 | if not block: 18 | block = self.w3.eth.getBlock('latest')['number'] 19 | kw = {'block_identifier': block} 20 | 21 | rate = 10 ** 18 22 | return rate 23 | -------------------------------------------------------------------------------- /curvestats/rai.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Compound tokens being used under the hood 3 | """ 4 | 5 | from retry import retry 6 | from web3.exceptions import BadFunctionCallOutput, ABIEventFunctionNotFound 7 | from . import TOKEN_ABI 8 | from .abi import RAI_ABI, RAI_PRICE_SNAP 9 | 10 | 11 | class RaiPool: 12 | def __init__(self, pool, token, w3=None, abi=RAI_ABI): 13 | if not w3: 14 | from web3.auto.infura import w3 as infura_w3 15 | self.w3 = infura_w3 16 | else: 17 | self.w3 = w3 18 | self.pool_contract = self.w3.eth.contract(abi=abi, address=pool) 19 | self.pool = self.pool_contract.functions 20 | self.token_contract = self.w3.eth.contract(abi=TOKEN_ABI, address=token) 21 | self.token = self.token_contract.functions 22 | self.base_pool = self.w3.eth.contract(abi=abi, address=self.pool.base_pool().call()).functions 23 | 24 | self.coins = [] 25 | for i in range(10): 26 | try: 27 | self.pool.balances(i).call() 28 | c = self.pool.coins(i).call() 29 | self.coins.append(c) 30 | except (BadFunctionCallOutput, ValueError): 31 | break 32 | self.N = len(self.coins) 33 | self.coins = [self.w3.eth.contract(abi=TOKEN_ABI, address=addr).functions for addr in self.coins] 34 | self.decimals = [c.decimals().call() for c in self.coins] 35 | 36 | self.underlying_coins = self.coins[:-1] 37 | self.underlying_decimals = self.decimals[:-1] 38 | self.underlying_N = self.N - 1 39 | for i in range(10): 40 | try: 41 | self.base_pool.balances(i).call() 42 | uc = self.base_pool.coins(i).call() 43 | uc = self.w3.eth.contract(abi=TOKEN_ABI, address=uc).functions 44 | self.underlying_coins.append(uc) 45 | self.underlying_decimals.append(uc.decimals().call()) 46 | self.underlying_N += 1 47 | except (BadFunctionCallOutput, ValueError): 48 | break 49 | 50 | self.price_snap = self.w3.eth.contract(abi=RAI_PRICE_SNAP, address=self.pool.redemption_price_snap().call()).functions 51 | 52 | def get_rate(self, i, underlying=False, block=None): 53 | if not block: 54 | block = self.w3.eth.getBlock('latest')['number'] 55 | kw = {'block_identifier': block} 56 | 57 | if i == 0: 58 | rate = self.price_snap.snappedRedemptionPrice().call(**kw) // 10**9 59 | if i == 1: 60 | rate = self.base_pool.get_virtual_price().call(**kw) 61 | return rate 62 | 63 | @retry(Exception, delay=5, tries=5, backoff=2) 64 | def fetch_stats(self, block='latest'): 65 | full_block = self.w3.eth.getBlock(block) 66 | block = full_block['number'] 67 | timestamp = full_block['timestamp'] 68 | kw = {'block_identifier': block} 69 | rates = [self.get_rate(i, block=block) for i in range(self.N)] 70 | underlying_rate = 10 ** 18 71 | balances = [self.pool.balances(i).call(**kw) for i in range(self.N)] 72 | is_deposited = True 73 | for b in balances: 74 | is_deposited *= (b > 0) 75 | trades = [] 76 | 77 | try: 78 | for e in self.pool_contract.events.TokenExchangeUnderlying.getLogs(fromBlock=block, toBlock=block): 79 | ev = e['args'] 80 | trades.append({ 81 | 'sold_id': ev['sold_id'], 82 | 'tokens_sold': ev['tokens_sold'], 83 | 'bought_id': ev['bought_id'], 84 | 'tokens_bought': ev['tokens_bought'], 85 | 'underlying': True}) 86 | except ABIEventFunctionNotFound: 87 | pass 88 | 89 | for e in self.pool_contract.events.TokenExchange.getLogs(fromBlock=block, toBlock=block): 90 | ev = e['args'] 91 | trades.append({ 92 | 'sold_id': ev['sold_id'], 93 | 'tokens_sold': ev['tokens_sold'] * rates[ev['sold_id']] // 1e18, 94 | 'bought_id': ev['bought_id'], 95 | 'tokens_bought': ev['tokens_bought'] * rates[ev['bought_id']] // 1e18}) 96 | 97 | return { 98 | 'A': self.pool.A().call(**kw), 99 | 'fee': self.pool.fee().call(**kw), 100 | 'admin_fee': self.pool.admin_fee().call(**kw), 101 | 'supply': self.token.totalSupply().call(**kw), 102 | 'virtual_price': is_deposited and self.pool.get_virtual_price_2().call(**kw), 103 | 'timestamp': timestamp, 104 | 'balances': balances, 105 | 'rates': rates, 106 | 'underlying_rate': underlying_rate, 107 | 'trades': trades 108 | } 109 | -------------------------------------------------------------------------------- /curvestats/reth.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Y (iearn) tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import NEW_ABI 7 | 8 | 9 | RETH_ABI = TOKEN_ABI.copy() 10 | RETH_ABI += [ 11 | { 12 | "inputs": [], 13 | "name": "getExchangeRate", 14 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 15 | "stateMutability": "view", "type": "function"} 16 | ] 17 | 18 | 19 | class RETHPool(Pool): 20 | def __init__(self, *args, w3=None): 21 | super().__init__(*args, w3=w3, abi=NEW_ABI) 22 | for i in range(self.N): 23 | c = self.w3.eth.contract(abi=RETH_ABI, address=self.coins[i]).functions 24 | self.coins[i] = c 25 | 26 | def get_rate(self, i, block=None): 27 | if not block: 28 | block = self.w3.eth.getBlock('latest')['number'] 29 | kw = {'block_identifier': block} 30 | use_lending = (self.coins[i].address != "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") 31 | rate = 10 ** 18 32 | if use_lending: 33 | rate = self.coins[i].getExchangeRate().call(**kw) 34 | return rate 35 | -------------------------------------------------------------------------------- /curvestats/susd.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Y (iearn) tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | 7 | 8 | Y_ABI = TOKEN_ABI.copy() 9 | Y_ABI += [ 10 | { 11 | "constant": True, 12 | "inputs": [], 13 | "name": "getPricePerFullShare", 14 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 15 | "payable": False, 16 | "stateMutability": "view", 17 | "type": "function"} 18 | ] 19 | 20 | CRV_ABI = [ 21 | { 22 | "name": "get_virtual_price", 23 | "outputs": [ 24 | { 25 | "type": "uint256", 26 | "name": "out" 27 | } 28 | ], 29 | "inputs": [], 30 | "constant": True, 31 | "payable": False, 32 | "type": "function", 33 | "gas": 1074737 34 | } 35 | ] 36 | 37 | 38 | class SUSDPool(Pool): 39 | def __init__(self, pool, token, rate_contracts, w3=None): 40 | super().__init__(pool, token, w3=w3) 41 | self.rate_contracts = [] 42 | 43 | for i in range(self.N): 44 | c = self.w3.eth.contract(abi=Y_ABI, address=self.coins[i]).functions 45 | self.coins[i] = c 46 | if rate_contracts[i]: 47 | r = self.w3.eth.contract(abi=CRV_ABI, address=rate_contracts[i]).functions 48 | else: 49 | r = None 50 | self.rate_contracts.append(r) 51 | 52 | def get_rate(self, i, block=None): 53 | if not block: 54 | block = self.w3.eth.getBlock('latest')['number'] 55 | kw = {'block_identifier': block} 56 | use_lending = (self.coins[i].address != self.underlying_coins[i].address) 57 | 58 | rate = 10 ** 18 59 | if use_lending: 60 | rate = self.coins[i].getPricePerFullShare().call(**kw) 61 | elif self.rate_contracts[i] is not None: 62 | rate = self.rate_contracts[i].get_virtual_price().call(**kw) 63 | return rate 64 | -------------------------------------------------------------------------------- /curvestats/y.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Y (iearn) tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | 7 | 8 | Y_ABI = TOKEN_ABI.copy() 9 | Y_ABI += [ 10 | { 11 | "constant": True, 12 | "inputs": [], 13 | "name": "getPricePerFullShare", 14 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 15 | "payable": False, 16 | "stateMutability": "view", 17 | "type": "function"} 18 | ] 19 | 20 | 21 | class YPool(Pool): 22 | def __init__(self, *args, w3=None): 23 | super().__init__(*args, w3=w3) 24 | for i in range(self.N): 25 | c = self.w3.eth.contract(abi=Y_ABI, address=self.coins[i]).functions 26 | self.coins[i] = c 27 | 28 | def get_rate(self, i, block=None): 29 | if not block: 30 | block = self.w3.eth.getBlock('latest')['number'] 31 | kw = {'block_identifier': block} 32 | use_lending = (self.coins[i].address != self.underlying_coins[i].address) 33 | 34 | rate = 10 ** 18 35 | if use_lending: 36 | rate = self.coins[i].getPricePerFullShare().call(**kw) 37 | return rate 38 | -------------------------------------------------------------------------------- /curvestats/yv2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Y (iearn) tokens being used under the hood 3 | """ 4 | 5 | from . import Pool, TOKEN_ABI 6 | from .abi import YV2_ABI 7 | 8 | 9 | YV2_TOKEN_ABI = TOKEN_ABI.copy() 10 | YV2_TOKEN_ABI += [ 11 | { 12 | "constant": True, 13 | "inputs": [], 14 | "name": "exchangeRateStored", 15 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 16 | "payable": False, 17 | "stateMutability": "view", 18 | "type": "function"} 19 | ] 20 | 21 | 22 | class YV2Pool(Pool): 23 | def __init__(self, *args, w3=None): 24 | super().__init__(*args, w3=w3, abi=YV2_ABI) 25 | for i in range(self.N): 26 | c = self.w3.eth.contract(abi=YV2_TOKEN_ABI, address=self.coins[i]).functions 27 | self.coins[i] = c 28 | 29 | def get_rate(self, i, block=None): 30 | if not block: 31 | block = self.w3.eth.getBlock('latest')['number'] 32 | kw = {'block_identifier': block} 33 | use_lending = (self.coins[i].address != self.underlying_coins[i].address) 34 | 35 | rate = 10 ** 18 36 | if use_lending: 37 | rate = self.coins[i].exchangeRateStored().call(**kw) 38 | return rate 39 | -------------------------------------------------------------------------------- /export-json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import json 5 | 6 | day = 86400 7 | week = 7 * day 8 | 9 | data = [] 10 | output = {} 11 | 12 | with open('swap-stats.csv', 'r') as f: 13 | reader = csv.reader(f) 14 | next(reader) # Omit header 15 | for row in reader: 16 | data.append((int(row[0]), float(row[1]))) 17 | 18 | start, p0 = data[0] 19 | end, p1 = data[-1] 20 | 21 | start_week, p_week = next((t, p) for (t, p) in data if t >= end - week) 22 | start_day, p_day = next((t, p) for (t, p) in data if t >= end - day) 23 | 24 | apr = (p1 / p0) ** (365 * day / (end - start)) - 1 25 | weekly_apr = (p1 / p_week) ** (365 * day / (end - start_week)) - 1 26 | daily_apr = (p1 / p_day) ** (365 * day / (end - start_day)) - 1 27 | 28 | output['apr'] = apr 29 | output['daily_apr'] = daily_apr 30 | output['weekly_apr'] = weekly_apr 31 | output['data'] = data 32 | 33 | with open('stats.json', 'w') as f: 34 | json.dump(output, f) 35 | -------------------------------------------------------------------------------- /plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import csv 3 | import numpy as np 4 | from datetime import datetime 5 | 6 | 7 | def plot_profit(data): 8 | import matplotlib.pyplot as plt 9 | import math 10 | 11 | # Configure matplotlib for publication quality 12 | # http://www.scipy.org/Cookbook/Matplotlib/LaTeX_Examples 13 | # thesis: 345 14 | fig_width_pt = 350 15 | inches_per_pt = 1.0/72.27 # Convert pt to inches 16 | golden_mean = (math.sqrt(5)-1.0)/2.0 # Aesthetic ratio 17 | fig_width = fig_width_pt * inches_per_pt # width in inches 18 | fig_height = fig_width * golden_mean # height in inches 19 | fig_size = [fig_width, fig_height] 20 | params = { 21 | 'backend': 'ps', 22 | 'axes.labelsize': 8, 23 | 'axes.linewidth': 0.35, 24 | 'font.family': 'serif', 25 | 'font.size': 8, 26 | 'legend.fontsize': 7, 27 | 'xtick.labelsize': 6, 28 | 'ytick.labelsize': 6, 29 | 'xtick.major.size': 2, 30 | 'ytick.major.size': 2, 31 | 'text.usetex': False, 32 | 'figure.figsize': fig_size, 33 | 'lines.linewidth': 0.7, 34 | 'lines.markeredgewidth': 0.2, 35 | } 36 | plt.rcParams.update(params) 37 | plt.figure(1) 38 | plt.clf() 39 | a = 0.13 40 | b = 0.13 41 | plt.axes([a, b, 0.98-a, 0.99-b]) 42 | 43 | t, p = data[:, 0], data[:, 1] 44 | dt = t.max() - t.min() 45 | dp = p.max() - p.min() 46 | plt.plot(t, p, c='blue') 47 | plt.xlim(t.min() - dt * 0.05, t.max() + dt * 0.05) 48 | plt.ylim(p.min() - dp * 0.05, p.max() + dp * 0.05) 49 | plt.xlabel('time') 50 | plt.ylabel('virtual price ($)') 51 | plt.savefig('profit.png', dpi=300) 52 | 53 | 54 | def read_data(): 55 | data = [] 56 | with open('swap-stats.csv', 'r') as f: 57 | reader = csv.reader(f) 58 | next(reader) # Omit header 59 | for row in reader: 60 | data.append((datetime.fromtimestamp(int(row[0])), float(row[1]))) 61 | return np.array(data) 62 | 63 | 64 | if __name__ == '__main__': 65 | plot_profit(read_data()) 66 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | web3 2 | ipython 3 | -------------------------------------------------------------------------------- /stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import time 4 | import config 5 | from retry import retry 6 | from web3.auto.infura import w3 7 | 8 | ### 9 | PRINT_FMT = r'[{0}] token_price: {1:.6f} | dai->usdc: {2:.6f} | usdc->dai: {3:.6f}' 10 | FILE_FMT = '{0}, {1:.6f}, {2:.6f}, {3:.6f}\n' 11 | swap = w3.eth.contract(abi=config.SWAP_ABI, address=config.SWAP_ADDRESS) 12 | 13 | 14 | @retry(Exception, delay=5, tries=5, backoff=2) 15 | def get_info(): 16 | virtual_price = swap.caller.get_virtual_price() / 10 ** 18 17 | dai2usdc = swap.caller.get_dy_underlying(0, 1, 10 ** 18) / 10 ** 6 18 | usdc2dai = swap.caller.get_dy_underlying(1, 0, 10 ** 6) / 10 ** 18 19 | return [virtual_price, dai2usdc, usdc2dai] 20 | 21 | 22 | if __name__ == '__main__': 23 | while True: 24 | results = get_info() 25 | t = int(time.time()) 26 | results = [t] + results 27 | with open('swap-stats.csv', 'a') as f: 28 | f.write(FILE_FMT.format(*results)) 29 | print(PRINT_FMT.format(*results)) 30 | time.sleep(60) 31 | -------------------------------------------------------------------------------- /test_libstats.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pprint import pprint 3 | from curvestats.compound import CompoundPool 4 | 5 | 6 | os.environ['WEB3_INFURA_PROJECT_ID'] = 'efd35366fc0445f98df93cc418832774' 7 | 8 | 9 | if __name__ == '__main__': 10 | pool = CompoundPool("0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56", "0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2") 11 | pprint(pool.N) 12 | pprint(pool.decimals) 13 | stats = pool.fetch_stats() 14 | pprint(stats) 15 | pprint([stats['balances'][i] * stats['rates'][i] / 1e36 for i in range(pool.N)]) 16 | --------------------------------------------------------------------------------