diff --git a/sips/sip-027/results/multisig-dao-votes.csv b/sips/sip-027/results/multisig-dao-votes.csv new file mode 100644 index 00000000..bc19c88c --- /dev/null +++ b/sips/sip-027/results/multisig-dao-votes.csv @@ -0,0 +1,161 @@ +voter,txid,for,power +SP360XZY8BAEV22YC2E1S7STRBRZWN8WEP07MFPV6,0x6b589e691f9172ee0e25eddb20b7fcc8b900d4b66a1cd96c352440341eb42877,true,1100000 +SP3YAYV2F7GQV833K0J72ESAVD92MXE46N7SZN58R,0x34bcde19f393565deb8eab26cb10cac72f5342ccfdd60b79441230f27ef3c545,true,1419822 +SP243QG2P4SY34JVGDRGGVW5FNE9XWQZJ77PRFHRP,0xd4a819f99c6ac9fab2a8b6e2c330cd3cd13528487de36865b8a15172e32c9e28,true,1275413 +SP39YBTTN2VV61F6AZRVT9F75SDPCTKH0TV313CEN,0xe6ad85f0c9496e88000e02b684dfe5a726058b59a9f4431c8ca2ad81147e124f,true,1100000 +SP3HWZB4KFBSWK886D6CK4ZBZ6CTFM2EXJKVDETZ7,0xe385bf4b9a7f5875ee3d5f30ea818c53957882c67c79bb80c3cbb16bdba3ec9c,true,1100000 +SP1A6SG4G6FCJCP10QK9NKDH2KD6KW1WPG1J354ZP,0x6f01701c77352261a4ab82dd6af7a051d3135151411b0e370d84cc98d72a4a1c,true,1150000 +SP2SACH111M97FZWN2Z8XMJ1FCKSJM3NGE37MGXAT,0xf784396f0f315a495fce9d945bcfbfb689cf5e073c93b6332bcabbd9651a2f4c,true,149124536 +SP28F5HQ6KKNJ2ZG8016BGB2VJHBW9ESFC3RAHQP7,0x6b24eaf250e937b205dc56533aa4eba55fe21249daf54e048f4bb98d62558476,true,10808425 +SP2CEBH7PWF2SJ1CBH94TMT0D08P462HRGBKHFM6D,0x8b864356d9d6d5f520705adc83009f1a8b717b415665770f2d82aca55a7a704e,true,2285260 +SP3X8T8SA3FPRK6S8RD5XZEH9K44SP3KFJFEP4SQM,0xf88659464d5fb413388b2600b17269e7ca8055d9ef9589cab791cd9b43a7e529,true,1574211 +SP2Y6PN1W5F97RZ2ENNSAADVWBFDF3GCVC4YZ71CN,0x80993eed69eaf82076a097a6205a637f6c9c495b733bdea053e93f7b8b5085e2,true,199662565 +SP1M2KY35ND63DRY71WNSRH5JA2Q5VHZ0HXF8M6RJ,0x6d8d1a34794fe7871de30b4ed5edcef8108764d5dc62531d88ed059c70c56ce1,true,2000000 +SP2FGK1JPBZ25SXCV7Y3F9B5RTW9EB5R4VVQPB0SC,0xe2d67e72aafeb1d5d53c7c5ce55bbef7cde5ca35964c89b4f80dda4b1d42e50d,true,14598090 +SP32X4AF7D5JNA0PRFBEVRRT8K57C5B6WFV130Z5A,0x2b6dad48e03326a4e05d1d427ade5053a14bef0ec307af5f5e30aa4aa8aad122,true,3043660 +SP3G0FTJARHAF89P14SX1P9E3E9E4HT008VX2PNRZ,0x673ffb5999adaaf2e79789eead5f2bbf1ccc553ac7643315d490ae98567995e8,true,2130613 +SP18DGDASP836GWESYYRBCF3S6XZBWPV8GBV82TJS,0x5ab4363f85bf926005db51653614d3dbb096b60980e062b94b3d07c19294779b,true,2050975 +SP1JDYRCVFCQ3DTXM1G6Z5ZDPJ9BB205RBQ7BKW7B,0x7355f7132a7b991fc54185e4cecf64881ca6aaba06eb720421dfb7ee99267b2d,true,3170063 +SP3ZQ9D23C0A5S2QC7AR7WDFRWFW0CVF3KC07HTP5,0x66d2ec46f5f7fb45dcef73c82b5b371c43e082c1e583dcaf7dc4a5f9c445d334,true,1900000 +SP2SDZ8CB9G3KQ0A5ZRXJBWQ38TTG45AR1957PDFP,0xcd356668c8d2508f9c8c5a29a243754e3b3e26706735097827dacafba2a9317b,true,2477234 +SP1T07GK9H4M0WP4N1DSSA7NJ7GNTQZ0GBZM0GAR2,0x16fab55123e197aba0cc5b61966ca57fc20b419e37c5f724ca9bad13516756cc,true,100381915 +SP1YS34MP7V0DPYSXD80C42M36D5TJKFCZ60B3AEM,0xc4fdcab3d5852be1b7d9d4e87a909fcb00a02734e71a132739585eeebfc03ab0,true,1989920 +SP38WCGSSQJBFAKH77R93AMTHBBEF83DQ6EJ358F2,0x135de50022a20706c5a33634604981e1a1d54afb66eac0af7925f52ebb155000,true,792210062 +SP26STSDW5X5YY5N5DRPR4VDJY86FPMB4NZ0RNBW,0xc1194852e9e75208d47933d0bd07472ec3c16c539fe6ec8e65091836fdb4312c,true,44225357 +SP2W4AH8RHNHQB9C1600D6QVCF59NCREBW7YEC8VF,0x3119743f6debbde26f85f517c41693d77fb649eb44b64a97bab562959d1657c8,true,4451447 +SP6SVZRG52SS35ANKZR0RTBE0CN982E3AJZZKZF3,0x1c9b1aab039017a0fa74f11a15f26afeb0c700b87dcd2fc2b1364de16530aed5,true,12620962 +SP1P882HWHCTBKEPPEDZ1MY2CPKF1JJT2XMFNT289,0x7a60a26e51d3493386aef7bb41a4d7d7d15293af4c25607c35d510ac78f46a7e,true,23037346 +SP2RBTTFGDXSH54SYBKZ0XEXAAWEY4DWTVNXGD7XM,0x916cc328fb5b005301a8e4679c574a0ce08767a8ed238f0f4d8c22d72bce3d62,true,6881872 +SP223G8A01JPHS4PKHEK8AMPKGKGRT5YKQF7VVA4E,0x44377b4e2cd03b6033dc7c319cd99cb8f57949bfe990106dd9aec09ac3ee3421,true,11044433 +SP19ABGPHMYDK6PA9D9NE0FCCG8NF0TYEM74MVQQ8,0x6cf1e24e59a4350e37a66b505394626dd6701df99f7efcd9c285b7b7ec58f9bb,true,6932974 +SP1B46TPZD8Y3ETHGZYJAPHD9GHJK81K08WRB127X,0x22ee15655bf20b3720b6ac5d435edc030a174e6b9ee78312d098728147dcfc28,true,2653141 +SP3AMF8Q1X1THMT6YJ8D7B65NRT7ZN7YD92QG27MY,0xa10229ae62509fb04427f23546ca80be870460bdd3dcda5046f3847166cec5ee,true,2302773 +SPTV5V2TS7H726FBHQB04RF905XS16QH2DQE065J,0x031a8e8c55ec4cd19fff5f8dc127889648c499f902919f7690423ab203edea9a,true,2059926 +SP30QCGX85MZVBAMH0CH024CXAVA6F4T30PBXN67A,0x7c7ee7f754b057ddd1632bcc83574bf5ee3b3d10aa7dfda2e8ecf3bb50faa5cd,true,4299058 +SPJNGNX5RBR9RDWWANG1AJ6A5RJKXMY32M0YK4SD,0x6ffddfdc3d232fd7426fd0383cc0e4af38f10ae23ed812417b884e678b7ba11a,true,1391896 +SP1PAGYEDF35JACKPBBTDRYDTV84ZAT0FAMCC38V9,0xfa16a6d35cdf908f085d002122d8c816954116bddee92ee86a8d747c782b0a2d,true,8969819 +SP216Y4DYSSBMMEACTMNRFYAWQZ1GWY49DJWH54PC,0x51751fb0d4d3fc2ee9feb4918cc499a4a659f64373c3cd32c6c81975945d1b2e,true,1475030 +SP1K30YJE3K05ETW7MBQP8VM2ZC5DFPECT2ATXDPF,0x34641dc4439c406ea15b5fdd07f57c416f5f6cd207584fa3d4de07751efc9a0e,true,18438824 +SP1B09WJ17REKAASWXMHN49Z7Z993G71Y4P7MVX7T,0xdc496a1109a0d23624900f2189281e624ca96aa1b27291e1c82d77ecbaffca9b,true,5420429 +SP1A4ZE8AKBVWHCN72CM6018XCRZSR6ED8VD8Q7S6,0xeb156e804eb842cbb1b2f8839fadb5d245c631a35a2743f2e7bc42942e4a0c4d,true,50746561 +SP2PFT921TWX6G1S9S70FMTYB3X3YJD4NC8WFMKBF,0x7e617f9e0944df9cc9d7e6874e10cfee986636bdaf6addd12771369234e156cd,true,2011839 +SP1W5XQ730V53A4CTW8DK5KD1DSMEGN4ZK3FW6NBF,0x086dc96ec55ef32a98191b5198e04813c4b54556e6956a817465be6e4f58b401,true,2125916 +SP2TWFDGSTC741C2RKGG6X2RNZ3TZASTJPHQQF0M0,0xe0624a10a09f0b9882f5cb7a06b80adcbde272cce78229309e80845c41aba745,true,7002142 +SP3XN8VRCGT78C7CTBEXJZ9EB2AECQ6E5WY4QT8YR,0x9fc008dafac490fb3c6a2e0a771c60f50c9c25a893afcb6eca012fdbe2f946bd,true,5997023 +SP2GP1FQ7TPTTHJYCCJKE5C9MT2VXRN50KZ4MJ63N,0xe765839d20a8267757ef62656eb08f2b3949544ab6703dce643079df2dc9e521,true,11371407 +SP3CTQWREGFB5FSFH4BF7F0637ECECXX06QDBVBF,0xfbceee700edf14ff7269b45d340bfde2fbc19d634d78addf824652300b8e2085,true,6219698 +SP27G4BAETJAXHDNCGVAC2036476MC3BE9K87CJ2D,0xe10880b801a501b886c33b46aa484be684d5462b8d338d89ac23898ec7943315,true,281975036 +SP3ATPYJHSG4C9H48RWGXJN913QSY8KZ09KSD88GS,0x39caa83ab3bf245a9ae04c95d2686ec830e55b1f63963764cb69fae637630d34,true,14696377060 +SP14ZYP25NW67XZQWMCDQCGH9S178JT78QJYE6K37,0x0630455c720bea171468c8d7ddb689089fe45143e5fc344e20fd29101ee855b4,true,389439881 +SP1B91MKXWMBQP50YWCNR08XZKBJJVSJRHB72SBX,0x427b2021a3e0b847028d9e6ab19127e13dc02ac98da4db87c73907a7e4cf855d,true,1875446 +SPQ3STDA3G4Q6QD716425BE7A2G378QFQ10RJK3V,0x4c24606902bba331c47e56a88ba665fa0794a183caafdacc450ef351384a0781,true,306061104 +SPBWF76FHRNA9C1A6ZZ896B3XRRK5TGGW7X9A55A,0xed7c02ea1483450bf214d2670926dc2fb821c35d40a8b3434081bb876a6a6e3f,true,9467197 +SP3N8ZJBY5R6V4QNW7GR7GA6VG73WAYXAFPEMF69X,0x96f0c1a7511657cb231c240c23c95e5ad5ed9ad0eff3fb119fe377214bbb23fa,true,42916333 +SP37Q561WR22AXA3EC9GJDN9QGK9K97Z3H940EV9Z,0xb423291333bf40bca78316624ca81c7e6bb24e9f72c8ebde9d70a0ea7e384d28,true,58684073811 +SPYMQGWH0SXVZQY2R46CYWVX1CEVHHV34H76DC49,0x5a023c36563a47b13f95994457df838c5c1611136586736deb28fa65e1560b48,true,136599000000 +SP3VCX5NFQ8VCHFS9M6N40ZJNVTRT4HZ62WFH5C4Q,0x63c503a1c0226de1684a734b0ae871dd711cddfa79efbbd3b87e4e891bb58e54,true,2900880575 +SP7PSDAPGQ2A36G1EPX363AZFWS017Q6FXFFF2BX,0xb647255da1daa688063352f3dfcca6d5566105b7c34228e20f9b532d157d8c15,true,35792584 +SP2944D80P2TQY1EY4E5RFWP3NZFGM3N6DEWPDTGX,0x286366ef1dd1fdeb0a657cfad67570370c505cd96968eb9af9a25a3d0c0c2406,true,1033986 +SP2NHZDAMMEEASE4DKHYYCVAG8RF8PA7YHPPW40BX,0xe59e178490bbae99d864881a37f5acb4bea7fa66dcc152ecf676664b463a9fcf,true,515963211 +SP34R4W2E28ZFF4NS3DXW1CJSP89BK07PC6GNXGNX,0xb0df1806fb668c760e57a385e9a75967cc207a3f32d00dfb152a06ebf216d3a0,true,5187547 +SP2C1WREHGM75C7TGFAEJPFKTFTEGZKF6DFT6E2GE,0xc10ef54a4a385cf459d9b85370239a6051759b3d18789d8ae897fa486676cf88,true,1962188 +SP3QGW69T7Q2BBB6RCCXGN6MCJCH10N0958W3GZ9Z,0x285e5360a798257679797411e7e4d421a2a789b453c10d0a0e3c2b477298eaeb,true,285597743 +SP25DP4A9QDM42KC40EXTYQPMQCT1P0R5243GWEGS,0xa3bed0a79545678d321405f159ed287c655c201f72bcae50832f1e5d2f3ff9c6,true,19206167 +SP3YS4Q6P6J2QF8K581V5E3GFAZWZ5YN6CMJY73QK,0xdc30f616eeccd486a6703d3fd88a585aeeb9196c6d4283b9ab090266209abfad,true,5641599 +SP28PKVZSWRYRKCP10FTS2FXK3DN3F76VPYPVHMSE,0x57d534f824d6ae950347f0034ca27331c6838ca307e99a4ddcf930a583d592c9,true,1786096318 +SP2NTAVRBEVVMDJJD0VV9FHDFY27DQCHG4RKP5A7F,0xa5757d27e27cbb8734e55129c884804a40ccde0f61d3bc4363d00864f67d4a2e,true,1494430 +SP3GBCZAYVMYVAC5GN5MJXTK1PJ3XVYKYD25R0FJJ,0x1b3dab8c37a15e63ac50e834e0cd19c063b232826c177323677c2eb48ddca4ae,true,88997970 +SP7T6J7JRKSAZH02G283M8GNCXT96BACHDRQ6B4C,0x8552b399f7c40c4095b2aba08e7e9ff5ad4ff5de3195669cfe92a61db9c3d361,true,2076695779 +SP31A0B5K60KHWM3S3JD0B47TG3R43PT1KRV7V53B,0x8425def76fed01cb059f8e1a4a85277df53dc432d327000d25559d7040dea550,true,2097466832 +SP393GB5D7ZYMH7AM6RMACBJMW5DMJ1JM6A7BRXCZ,0x491746e750d3b1924f93a4d261023b53a1bc6e0896ecfc276d0508504216cad1,true,1924917 +SP25HV48GJREWX3CSGTTV6J9CY2TYCXP3JNHK2NTG,0x0d513cfc4d76f2ee398debb213c51ce67300ba4d954f42aabeb5749bc974f749,true,67390824 +SP1R0X4XT4B3731JYXM52BZ7HSYHNREFCGY12W9N0,0x2576c45583204a31206c3f38772e211abfd1995374b8650cb46da77d705f8fa2,true,2510115 +SP23S4KHTBQADHS6Q0EQVHTC7Q9YRGBSD0F3X6QY,0x29f504fab7863323ec2cc6b35162f79474cbfce4cd2926ded502a3cf1da0102e,true,1158376 +SP2ARFMQ4BXJ5K7M28QDCH6JV3WY51TJ14054AENV,0xf234da697a5de48784f59d4d4f4bc42f5e1764185dfe41461a350adfd2988f59,true,7927820 +SP34HBB15K9P54ZRK2PEARGG0PW98QGSV92YKQHEW,0xa5ecebc041672d186e74175bee5c446e375ad4a50ebafe1feccb13fcc17a4100,true,14009107 +SP2KZ24AM4X9HGTG8314MS4VSY1CVAFH0G1KBZZ1D,0x6d6ac6139a7935a36e7c48ef4c0b59892278ad63fbd686178cdd9735a98f38dc,true,19226715 +SP5NSFTWED17R0HG8K44YBS4QZ3WW1N9WXGA167P,0x7cf9b2a276f5c61c1d4935c03c526f1d52c2b905b2338d69461987652cfe3980,true,30993050 +SP37MBZPJBVGVCDCBEA6EVKCY748VC48N7GZ842M4,0xb47caecc4dc02509e0293f30b335565d02e956e1e39ca2af2d7737e3f11f2ec7,true,3011540 +SP35J1CM4FFGW6JRVJ53QR45AECB3H6W1BEVR5N3H,0x9159e84c59ca524f805da9a1cf01368a740c6cf5531bd86043db962f357418e1,true,3166827 +SP2NPJCP8RY6ZSX7WZATECHTSQBNZ08WJ8JCW048C,0x7c2db30e12b127fad5888bdae20bed73a14a58f3fd7fa94d2a2ccdc45e264bdf,true,11159322 +SP2GPSRRW1MXYM5N1011W17EZ8HWPYXMDY1X9Z00Z,0x935295afaa092ea00aea2c980798a31028214e213f57134562e617d24dc8f1d0,true,2561033 +SP3SAYJ9YPDS3MK76QH9BAFR27DA86E3H1EATGDTG,0x955e2f30eb2050837dabd5ddaaaa1ec78da3fae87d5baf957787e2c524fd4529,true,3221610 +SP28ZTJS8Q58ERK8MDNFGQA85CHQRP4SYH85B95SG,0x83718228706422b6b3e6a5de8ed6c974743d6a63af7d8fd6bf9c8b616cd6b659,true,179469834 +SP3F0Z7QSRDR8GK66A714DPBDSE429N9RKV4MR0J0,0x1aeeed2960eb1453f00a4c790c5f70ae6413f561cbd5b482c9837f848a5e28b9,true,30078078 +SP2J1NM0YR9S2SD6VKHCTQ18C0ZB3EEDXY1VN2ZPF,0xf5826bb4685e4624a76c6a040014a7abb2686041e33392344c3affeefd2a2b1a,true,23691902 +SP10FVY8H3ZHKPERY1DYZNF0XNM1P7J8F1RAH70QD,0x836682b21cda2423f799831a7926623a73e45d340823eff7333bf3aae565bbed,true,2337541 +SPRSECC45ZWE1MKDT8CMH5Y3MG4NRQ4TJQXWAKE2,0x1515faf1b9f195510e5b1af924de0bdc4eb573083ae7e80bf16237c53bb26efc,true,12984370 +SPAN3P3RA2QRGM8V1J8JFDX583EFFT2V9RDCVTZC,0x6391bdcae175ed82fbc10eff92c240aa7ea8321e4537a520551208c81ea547bf,true,7228399 +SP2XT9VQ08317BJQH0EXCK1HE01CBEC9B69XSTE1D,0x69f9e8b876134e7f389ff66c10e5849b275d9d89899732df8a67faa297795788,true,4000411857 +SP1YAVCV34TT37ACR0ZD9JTASMF915MJMHCN8ENCQ,0xc10a2362fabf78b7a4c90054000f184e9e9a8385146519826686aa55ec931269,true,33655202 +SPQGBGEETB0DG0P6S125WBR6HCX1TNFHDB065AY5,0x70d2ae8c12a01c66707d060c36431d2f502adf91dbcc134434ed45e02e42ad64,true,97864435 +SP2881ZP80PJMGKVM6P4C37KHN6F8G044HAVR884K,0x5dca26cfc1905d0efa37269d3cd4b5c73b750814ba0bd1fc9486bb0645d9d2b8,true,99995585 +SP22682J0RP4AJSJ1JYFBQ1Q79Q880BVJDD28BPTR,0xa28931e47657d275e7df83c2eac96e90fe1d8d223dfd4783eec3d4aca223b41f,true,8096272790 +SP3GNQC2QSD5B3YGH3AASXZE30D4T040JWW8KBNPC,0x0b0ad925e077b1264d6ef0d13a8df32bccffbdda68296937ba9c9b961dd25c07,true,30868350864 +SP264K42S3AGW5ZHWPTY2XZ1YYX7CBQPYVPD5SSXQ,0x44298828276898ca0758341d1fa2aeec80288c5cdd45a877c811e5828daaf9c8,true,98648635 +SP1EPWNPPGEZMGKHFZ6WXEZHTVTKH0CT77NM32X43,0x8b67b8ab409c91c6609d9df0881e79d7b6a93ed443cb26c6a6fb2cbc87f7deec,true,6724828 +SP2EK6MPWJYXM0JE3K19AWCDT0041DFPMJERAPP9Y,0xd827bc26a076eca2e98e2820cdf287a4d2244759d9c70974903d2e03c417f189,true,1000000 +SP68C69NS28RKRZ4TTVEN538287T5BXH22M5HGE1,0x593aa596aee7d12e8dce73f6480f51716a1cf381be1cc813d68f866c48f7779c,true,6570296 +SP1P458Q2Z3CZY9CHDJ3GS5THDHCYD7PR0BM5JFZ3,0x07a673d61903c466b94ee135a32d2a42b3fb92c536e0528843683d4b9be2d191,false,1000000 +SP23BJCKF48J19360XQ31Q7D3E07ST9J5H5E1HMK7,0xcf4b3c223df6997eccc82c097d074fffc903671fec7155f7de0b4f7bf2f38d87,true,55939087 +SP3QC4R6M7M0DAZBXSZCW4FWGDCNDD05FV8Y0AY8C,0xfc196b7b1847e56b7751896bbfe5233f8e6aad0dce4c710dfb5d3860a78aef00,true,6024689 +SP330R59339Q2WQNVX43Z5AN1GCYMFJ9PN3K66YQD,0x2193120f378db28f230674f322c3416c7ac0f08cdbac044de9d59b5b3da9f57c,true,23786718 +SP327AMYAAJFHDSDGE6AD0HTACYQ4CCXJGT47M2H3,0x8ec8a6d0d5fa42922c7aa544b584103ee782e085100b00aa2649f9b08ba774b1,true,7370511 +SPM2JZ5R7M6AZQTXKEM94K63E2CN95TT6AMMA5PP,0xdee509d866df34653d33a1bf4bc168c2b2490e77b623d6a6043fd63feee20163,true,4668675 +SP2EDRYCPGTS32HZAGWV54RAVA2GTW0WPBP4HGCXR,0xca069edecfdd31a86a5b756cf4d6c3feb422e7e580543ef26b8c8883c9e66566,true,78040928 +SPBP4KDPZJJYV8N8JRHS9135V0YXBZDSA5MYMREV,0xbbea7173e7faed12b722ced51e18bdd34ccfbea62afc4392318382c91ed19416,true,2079187 +SP3EN2WMVAP7SNVV1QJA0ZZ6TC3R0044FZXE8PQTX,0x2faa9541de7804cab36469b21ff3771c0a552ad308040622761baf260d5768c4,true,20704274 +SP2HJVJQS0TRBTQ1WAWWN9H9W2HKGDZ7H5EZCEAQC,0x9ff584b12bc07a03a2e4ebac46b12cf72ac9c1423f5c06df0c7b34509d8f06b1,true,38329473 +SP376Y7METTJAT372GYDGD225YE20A01GAV7KJFKN,0xe17d80aa58dbf4862443d4c91a7b89b02a79d21398222ff53dc762443a67e50f,true,377899383 +SPAFRYT831WS7ZRHGZBPMNCBJRBC0ZT884HFXERA,0x147b7f2b8244915b97d53c1ee2a7b17fa82fa5faace72a252cd46412557ef885,true,1000000 +SP12V92X9H9C6F04AFX4C7NDRRMF4WD0S2EX33865,0x6528f0715d222d915de09a56295566a66e311b0235f8b2c24626bed3e830a2ff,true,5274622 +SP1VETYCVMJCCBNYXB0YYAWKGFA4MKMW2C21SR72A,0xdfbe828d66584220243f4affe024afda5d691ccb72e8364fc76d6db3e01e5e30,true,4676800 +SP1ZCGABS83EZGVNRNBANM585EKFH018GNB1X06DT,0x876fa585d65937dae8ca1ca3302fb6b917c7426f60ef9f5c03ec57e622b0450c,true,4376800 +SP1PV390R5TW2PHCCJT1D0621WP9VXQD4J7SGMNQT,0x54ef411aef1087782986d1850f0bec89e486846d1d79aeebecd8e24813479700,true,5076800 +SP18APAH9C1EPBD7QVGMNEF298CB9C95CMVW3M21P,0x2a4082f1e9a3be0616dc50a5e1b9c38b4a1cb9fad6a295e6881edb5372431bf1,true,5570232 +SP3D5H0YZZBAY3XBFVRDT8AJEK6XDM3X623SHHQ81,0x9c732f5e4704e9d3d1688f4ce3e516c4ff49a681f03906d2be2e9493fe307a25,true,2441354 +SP2J3F35AAWDTT52RDFR437D32TPAEE10NF9K0ZH8,0x8677cb2efe8ca2dd7b4e1d9320096ec16f63e0f4b0a19b6fbeef4a41ce8f1b62,true,2440668 +SP3D9XBW1Y39W3X2KK5GAF4KYTGW3KVPNS4R2H2K7,0x8005add3b23709f4aee5dd6271bee639247f811ea5b34403823b153d1db1135a,true,2240668 +SP3D4E8CVDPE7YVQAYAGRD9B43F53E13NYX5K0JVX,0x7b2435259b68b57b615df7314840ed8f17fdaf90e0363bb90d638955db987d95,true,2340668 +SPFDXVD3GQFS77A112E95QTC7Z0JHC3W5G6C3PH5,0x9e3893e9cb98ffcd54879f9c52f40b65e8e2f6920f31472655a1c9c83a8a6f1e,true,3132715 +SP2C9K1150C6E900YWGETMBZP6R4J1JMR3TWN2SHT,0xe9c8cd25893c318a2267536fb7fd4685672cbdc316a6ab94bf75ba9c82fb464e,true,3100051 +SP1N6DW24K1SWHV6A4QYZGCJ9E9EHG0X7Y0MYAQ00,0x288488e59fbf3a86d4575292e0e2c2b4f0329812a20cd368a88cc0cd85529f1c,true,2100051 +SPRW9XNCTE0RDS04D0Y5HHA5PDKR2A41CBAR3PB6,0x2072e90ed3d7adc208b40ec8d00fcbb97cf98eb2a1218462b1549b492881efdf,true,3100051 +SP1GPX3ZYJNDX1509F4SENPEGT2EC4PV8AAZDAYPM,0xe37d0a31771d22ee41a34ab5e7f2505442dda4284584640dbe8d3115699e4b3e,true,3138673 +SP3ESSFQ8Y0ZXBZB5XA60BFVV9NMTFR8Y1NCNMBGP,0xb45c612c8ff55b17a2630ec432d489fc3ed986dc67ea1fbf83b29e37d33d4c4a,true,1263785 +SP3GPV7YEVS2VNFYYXEJA4HWXA0HFX4SMFK9F12P7,0xbb8e43a55aa7ecdb02df524286d0743d6ccd8072ace302e9846c46f0a969cf6e,true,165210513 +SP2N7VSJ2DT9NY438G3VDWYFP3WWBKYN46GQPHH6T,0x1702a8613357c712683815424d5b8db2449b91f70aca1c01226da977b5c0aebc,true,18314864 +SP19NPW1QYFAVJ4DFY9C29X9MMVD1RA3SGK033EZ8,0xf4d7cfd80c37cc7e0c7074120c9b0df34194d34ec02e5ed05fbc60662f775276,true,3153952 +SPSEBFRZZEZSHGRKRR1Z55RX5AWHER3CYM0H9BMW,0x3df0996ef298010aa2fbabb280b326fc526eded19d5db84393ef6d9424f06866,true,996167964 +SPXZJPEQ3P0721P7HTP2Y27DAY216Z3ZNQYXAWFR,0x37139a5435f6ff0fd9bcf7a7da528db377f822b38cfee6980befa336f9b3bbac,true,1865528 +SP281NBPA7H99TPEBB22J1Y360GE3Z6735NN92C4D,0x410954df701dc226ea822a0c703ef77c2f17c00078b70991b0872e4f06767933,true,1464317 +SPQ2AT2319NV91VDRXV1M6CJKKCBTBJ6RZYN6RE6,0x17c5ce3209c69f641099feab61783a8fde1ba3730b14dbd3a43f4306efd2349d,true,1991244 +SP1Q1R96THZA9THXF2F0ZAJ7332Q1GHAPD97B5HF0,0xd6123d89b19dd0226dcbeea313e76a3266437ccca14ebb4c95546b7b9eb18bd4,true,1947299 +SP29X2GDNP6SJBCS50W5C45WW3WZKENCHCR2TWCTJ,0x0925ffeb47e92cb4fe8e9f8ec00fdb56460e660d656c8220c52bf4f78457e605,true,2247299 +SP25SWAJ0NXMH2EHEWE02VRW8VSY0SF7SQ9BFM0BK,0x831cdd24d7cb6947b57b2db56513ac8aa9816df95f1c9024fc951c4b5a80ec2e,true,2749477 +SP3DGEBES323CX9KV5GAJGC8SRNWFKC1NK0GK6BH,0xd28f1dcf8f15a3f16cff71a19202f8a82aa43c0ecfcfcb8cf7871ecbcd3e9b07,true,2949477 +SP1W2FZTH00ZEYDTCD62A7M5QFERRDHCH260B0QXF,0xb732c8117503b267ac8ba2c2a0b2cae133fd8553054d318148a247b43aa97d6e,true,2749477 +SP13R0ZZW68NH96DF1JZ65B543TBRM6FPTCC05G39,0xbff981631fcdc08478151bdee0ab6f19f857419a24a9cbe554ae0d5bfd9d90e0,true,3420963 +SP2F02FRWRSG74NH8CDWNHSRWS8YHBH04451R3ZXT,0xf9ac4dfb6bd1f47a7be605d79dda78d6c3de4c26e5cb3ada40d23f36cd104e18,true,2849477 +SP8170ZRP66BQEQVYBNVK4F5R8QQ0B4S24XC27YR,0xc326ec0a7cb3c81ede1edb13274eae0b889abbd3a2c875dde74f67358d9c89d0,true,3100051 +SP2HZMNKXP8JJGZ8W2B90CAZWP83ARH10BXNBKBGK,0x85ae320802b5bc026fd74d42952c316b7c1e66c609ffb41e5ba6e5e0d6620536,true,102804699 +SP1YP3RVGRKV3F0PBC1ZQHGV1ACZT05087ZTPRZAQ,0xcf113f35955fe7895feba5eaaf9d91ce45df2db3d62a957623aaf1b2c7468eff,true,7071291 +SP2ASZVDCGMZXC9RF8ZD3ED2JBMDM4TX87CGV8EN7,0xd033bdd2970bb12cdddae6b0abce892b72f8cfaae144cc776e4b963f13a0ac5b,true,8923415 +SP2F0DP9Z3KSS0DABDBJN0DA0SHMCVWHXPVTH3PJJ,0xd04c803133cd880144efe75ad58b9f20b53f2fdc6fc910e78b21df411132c16b,true,71094069 +SP1PHAGEQ5RWM8G84DFGMRPENKQGFC4QJ9YWXAYKF,0x83a4e75f67f6d3e1ee3a87659155895159ff0ba63d86406875cc6dfc3b33097f,true,23000000 +SP36P3B159T3KFD8KM63HQXR3G2TW6AA1114Z8ZVJ,0xcec102199bb47dedf9a397e64bdb6073ed28243345f1acdf0537d53fd3bfaa30,false,3820540 +SP1E4NAGDG5C42694ZZNQJDK7VJ41CVCYV1W1W148,0xddbfa143e4e489f9611a2a67cf339051bb4d824b1cb727887f4d24648b3f20e0,true,1876631 +SP65J08Y7DX8FTDJKQVWCPPN8BRSQF5KMT2K4CD5,0xc5f031f3b53e31cfa79f2c6b119f6a89db7c0b44486f83380aaeb2914d81a0a8,true,1000021 +SP25RK61425QBXW105M85SY22WJ46T6T6G5D1XJ9,0x22432a7819db13468e80329cff322610dfe48ca2c7436a95f4fbb16fc7768375,true,1077000 +SP284MQ5HZJ22NQRWVMT2MB9YXCF7S1DDZRDPXB7Z,0xe85ce3e74512f154d992b3af7376a2ae526ae4aec82224652d153fd18ce3d56c,true,1819651 +SP779SC9CDWQVMTRXT0HZCEHSDBXCHNGG7BC1H9B,0x5fc22b2580e027d3256b0e1a2fe32b4fb03a61e7f3bd742db2340c0c3c6181a1,true,5111448 +SP16JSP1JMTBNV3GN5Y3JYEEPG5WK3SGSYDZSM7VJ,0xb22b20fce8d9581965fab81f94eee1832b3ce7950c655e33a41b5b8587f42258,true,1000000 +SP3GGNDQASTXH0SVTSWVSNS7BP3RZ4MDXX25YW80J,0xe0c146e39e2ccef3d89424688f0f154265fdea1c568d70d60a71509e1d707062,true,17625139 +SP12VTBRY3M9X3HKZH1ST668METTXR452V29XF7QJ,0x3944e08b6831555d79e6dc7542f256e581d21da0004ede2f9a031c76b943b5ca,true,89580230 +SPFW2GN3FJPZRS7G2WS3VHJSGKKAWX2TS9BHKVHW,0xff251277c3c7854d27492b5014319e1bb8509148373b71c24f84064e29342e17,true,5787160 +SPBGX7PWC5719ZSPCMA8YJGXM08HVV93SR5PQ102,0xaa6a94c0e505176e94e845ed3d5d814acdeedc741f41090c2cc69c9df10ff0d6,true,9213316 +SP1ERZZ0G7KERNCXQDJF4GTHCF8DGZB8001YCNPQG,0xb11b5daebdfa16a75bcaf93baa0de25dffe16d8beac47a0087c310c3e6716d37,true,1457459 +SPZ0JWFD70SD70QQ5YP9AHNFHCJXZG7ZB3QN6FYP,0xcf525fbbfbac298ca6f867d2a769c953335638aef7cc839024c40446b049ef29,false,13072584 +SP25ZD9H455D2DMMPVGBADB0JDBFHJS1BTSGD9KYS,0x59d4647a239ca1cb172a359aa99857772592c4cb5d043a84de4596c8b85158dd,true,202099056 +SP1NXBK3K5YYMD6FD41MVNP3JS1GABZ8TRTH2ZTMX,0x5e6497f0cf3ae2dedd5c2bacac403b7f3123b354df0188a67966235b6f9ba8d1,true,35783412 +SP3JP0N1ZXGASRJ0F7QAHWFPGTVK9T2XNXDB908Z,0x5f4e75f7cf952b117c8053b4efb42d0049d80b8779f1de4d86da20e8c965a8c8,true,106531197 \ No newline at end of file diff --git a/sips/sip-027/results/multisig-pool-votes.csv b/sips/sip-027/results/multisig-pool-votes.csv new file mode 100644 index 00000000..68d9530e --- /dev/null +++ b/sips/sip-027/results/multisig-pool-votes.csv @@ -0,0 +1,74 @@ +voter,txid,for,power +SP2Z2CBMGWB9MQZAF5Z8X56KS69XRV3SJF4WKJ7J9,0xfcb85e802e3fb55a712589f27771b0ba06807e2dfde5bb63123dee2cc0f0d446,true,1999000000 +SP39ZYHN0GRAA9FBE43QGQ2HFS3PRWZGE1JCQRWYH,0x722c3009c9446f1ad01b6f542100ba359afd35033d751e691704a98bf2b6e459,true,298000000 +SP1NX4J8WPXR8KYVYMV2AF97Q5R6XJ8VVFSXMEDQ3,0xb22895e5ac0e2aecb8fd9ef16aa347a0836a52e2b281d271336b82c50e9a0464,true,24822000000 +SP2JCF3ME5QC779DQ2X1CM9S62VNJF44GC23MKQXK,0x6e490a6cdb58a6ab885927abe09300a549bac71f331e8b77decf12713cf55d47,true,279996000000 +SPKS1G7EQHP6FCFPFQW9S1913EAHHGHX0493F14V,0xe78ab7a0da4b986c83c25bf3d1709b793459054fa8991101f7703c2717bae279,true,62954000000 +SPQZ94RC1JB4YQYDD17WSH397G83RP21G8Z9CHSM,0xbb1c26ff2d339cea72eeff51ea4cc2585c35deac7af5c0d7a329381915f03f2d,true,20398000000 +SP760GCSGE6K8EX9EMW9QE12NY6QAPVAHFHNVZYA,0x221da41fefb27565dc682efbcc04a0e5ed3d905ec9d138ea2eaa23819512073e,true,4665000000 +SP26HQEB01J47QGKGSDP6XJ6Z5TCM7ZEGAB6TXQPN,0xd983591ab70d8c91aa50bd172e24f2b4613ee16a00441b73bfb008d9ae2bcecc,true,4665000000 +SPP74WS833MY99FXA1H2QC64RFMVCNZ37765FM3R,0x9616daa15b9676689587b5ad3cd9459ecdfbbd262751d116a7524c2f535e5aab,true,119000000 +SP2F0DP9Z3KSS0DABDBJN0DA0SHMCVWHXPVTH3PJJ,0xb732b3a063a788ef076859a833cdfeb4eb89614d30adc5e6578719c29645af90,true,99000000 +SP3S3X4WCNPTDZW0623D5MGFK6K8WR8PSQAXTY505,0x679962316ec535cb60c97d247fa49cee3d765f57893fc624343bb5c5ec927877,true,1053996000000 +SP3N2RARPZ4FZP7JHJTXF30NAHQ0T9EYG4QZG4DJ5,0xbdf0a3d6fcb284a13d5cf1c18160d3d19d829fb63ded4a909de780bf6304df54,true,1680000000 +SP2CM2RVAAKEJ4BF8AD5KV7B84FN2KPRM0A578AE6,0x93dad6e055d2fd40553acb6157f69ca94fd5ea200983b18b7a4e8839db3ac294,true,499999999519 +SP2W7WXBSVXGQGDBM03C691T5ZGTV9EQ7NVJH9H19,0x1d6695f3b2bfd5e3f21c42ff71e705fc6da639b8a6ebc025118915e70050d168,true,1044412696452 +SP2KW6DXVTR0SJGY3GN8GMPRP0KK2J8B9T4PMJWEP,0xd9f9198c3b3b361e131dbf36c3def9c5b3e019016cc7ef7e619e7d7df7ebb847,true,799999000000 +SPZFXRQMCWCYJWM0MCJ6RVRX1AX6297SJ50VE41R,0x812ea10afd1254f220362d9053f4fec22e277b94e8f8dabce8aa68fba35c4d5f,true,5048000000 +SP329M6CS0S3738Z0T268FXQXBSX0ZD1FZVBZS037,0x26690a514edd9bb8f928589fd5c5d5cef1b40133a70b98e2ff6f9ee7f12c0cd5,true,747000000 +SPSTE5R54386QDCDNJJWH2EXQFST44QYZW3RPMD3,0x9a5cd39860cc26634377562d4b8719e32e10ebb4b1bddc2e13e9bb2e2402e8c5,true,299000000 +SP12RR3Q6P9RAM5C4MJNFQ2PP17QRNNJ81VC9MEW2,0x48d58940464170fe2ecfae5b07624508b2f07422237fbec6dfde309d59030ca7,true,198000000 +SP2Q5WHA9NAGWQV500HSV93SEG8PJDNC6FAH88EP4,0x9996688c703ba74ca7def85b6f196520ae9dbd1b12ee1a24ca0bf26435953666,true,219999000000 +SPGTGMQWQ24S4SDZE9QV7TH6J2M9PEPQX6DKRTX4,0x5c4b4179ff3e009eb6e45546c95d7f7afa455afbd43a36fcc453d6bc29a073c8,true,970741646 +SP30JZHPM23NN4KRNBZWCKRW6HGKN7EYKFKP9HBBN,0x5cb28fbcf7157ef4598c07ae242ae0641ac874cef7cb8f38e3819b581b1eed07,true,59997000000 +SP3BNT6YEYFMVTT9V8MMY8ZKM4P9M3SY9X9PDJVEB,0xa1cd335ea715d27d035792e9b88df71e59ad56a0a4b6234e7ba535653bb34a98,true,11998000000 +SP1WYMS04HEP4V5RQQ51JJ4D9S1Z15RTJ3GPR0HDK,0x5d34743e97b3c9f15277c714f7b6dd95221c5fec7496c6c716960aea2ee79cdf,true,303982000000 +SP9XX1CEWA7JVG98P888VMYD4X5YBQ6H3ST516HG,0x2562412014bfcde5be7e58084f464c67ee819a0446071b0a6544aad1f6118e39,true,498000000 +SP8R8AT0HS12MRKHMZ22J05DMTBDHRW9XJBKE5DG,0x689847ef5774f935758bd1c6a2edab820cad72683ce3d572f329053af03de927,true,579000000 +SP3N0TH3N7BDG4WBSYV6FE2ASSAPEGWK47EEWD9TV,0x986513eb0bac134231cf1066f6e95577bb4081f64fb792fb402c59cd294199e3,true,1749000000 +SP2TZE09GHARKG0B8NTT9X77QXBTQPQ2J1579T0D8,0x12e413f9aac2902816bb051ed4459feb5feff858abc108f760b968984887f514,true,49999000000 +SP27Z5KCV5QGFH255ZWGMF0RVSRGZ9RTNAEE1X28,0x356ce4cdb75e3065f082b2e62bf52375d80b54c3635eeb76e076656fd9df551b,true,299000000 +SP20D7NAJPTDS8AVTFE88VWQ5QQTYB29HYNEHZZGA,0xed50aa5e6de4ffe26c5301cb79300d4c309b096fb16e2fcd48bc5f57332a5f8c,true,128999000000 +SP2EJSKCAD26AKPNYBQACSX9AY2JX6V27D3F9BW56,0x19b766dfaffc506f48fd62c2c907e9030fe4a8f923bdf8d39e1e74d2047dd045,true,740000000 +SPP3HM2E4JXGT26G1QRWQ2YTR5WT040S5NKXZYFC,0xf880b92b162e387c4ba7bced7fbc494de7a18f10d61852c294150f8d3c56c72a,true,5399000000 +SP39DC776TVRWSPSXNXCCM80APY6EBV4J1Y3HAZYJ,0xca79dae630eec22105e5ce819a223aa96b3faa60601f96adaf6384f640aeabf5,true,600049000000 +SP2G67CTZDK869T8E25W3M6AAF1MNJ5GNEJVZA6A4,0x6e64dcf5b82e97a15c05dce1421a83e6455b08b5a7c0e11c424612a6d32f41a9,true,103000000 +SP35MER4PHM6XGB99YDRQAK0M0JQ8F9CVF04VZ1VX,0x00dbd5315926e62fcf29222d4803443d4dcc41e67a9f166efbfbd07e9c925056,true,11999000000 +SP29902VVK134BEFGP0F3QT7W2H5CFY2BVWAKSN7E,0xfbaedaecbadd396b0e43491f849286c690c214801eda8825f1a52fdf5910b1a9,true,2000000000 +SP2ZRF8JCSA852P2K4ZB7RS21M43NYFKPSQ7DG1N8,0xdc3b4efdd644f2a291f5217f851563f8e67862785571d50ebc2b27a51aca93bf,true,6993000000 +SP2DC8W3DB139SWGHCZ173ZRQJKY05BCXMC2KGXX7,0x7a58649ecc03e4ce143ae6650b120c48b06e9df66ad5c01820bed9838b2a740c,true,2799000000 +SPF4682V9B3SNAYRTGWX6H3MWDRVM1VC4ETDC3MS,0x62f3c199fe1b0ee6db9a713282e26ea9aace4fc560c293d775a4695c965d0ba4,true,9999000000 +SP10Y2X7RMBZPDH64Y49KFDPG4WK3YY6QN7XE8KHD,0xcb5c8e7ad2a51155fee1ed48bf9e251fb1539bf2875b3f8c62e614785fa4f38d,true,24005930751 +SP3J9J71T02XB5C4PJJT3FZ1FASYJ4V8XMR6QY8D0,0x9620034d7ddce6a3410d719dcca63d73e058a832c0d9de4c825fbab9a3b88303,true,599000000 +SP1RJC76DDEGTXEA21MNVDAV40Y4HW845C9J46RJS,0xe0f1680ed983daa208f4f0c53e34629b3c72976681ac7ee92b3118d32d261e19,true,101000000 +SP22B1M07CY1TTC683V4P6VPTCCWCX21BES7DD35M,0x3a14072db68af796f7a15e0ccf91969f3125caca3be950699a48a7597929644f,true,39404300660 +SP3CHC5CKZGPZ3W4Q4JASMM5ZSMD3P7TQWNSE6BQ8,0x5e4b7e919b6ddc8f2119bec977ce051a003d98d40023c97c57e4c056d91b3f1a,true,36198000000 +SMX5RPBHKPF4M2WG14K8W8D9M7Y58A20N6GY9VBB,0xbe16eda8ff0dc9d726aabd730d28574a809be3ea7f4fc59509d0214456456b14,true,125000000000 +SM375112TJX2XDBKV31HTS7Y96681KDSJ9VV4PQKV,0xd5a4a61768251919163d70ed0b17e1243b9382b9fa6f8039d8168fd38e9ea55c,true,150000000000 +SM28MZMVW2W1PK9EGY0MWVTKKW5C8H8FGPNZY3Z6H,0x40c09fc8f40a56ffa4a477a5a8c9f91b8b849a580e90dac97310f1b7ec49c2da,true,125000000000 +SMSTT1YVA10J7PFKWT9C8C4Y0TRQX14KGKQDXJX6,0x0941b7e05981cbe36f524a40047bf997fd4fb3df623253e94dbbe64991e57401,true,120000000000 +SM11TJG7ZZJMERTMFZBRQF26WJBHJ1ES5TXWDEKJM,0xb06da129bf654fdbe3e3042986bea17f2293fc2d036859e9147d793dcc297ed3,true,125000000000 +SM43APJS7JJXJVF53RDH8AAA1561QZ127NWG6AQX,0xe664ad4a6f223457a9cd27d33f838d9428a10709bbdb7ec96ebbfb3babfe01bd,true,19000000000000 +SM4AETMATXSD8XKGV0J39JJ088XVEQXGD8287P8H,0x9ff5a426248dc98592088370382d381871fbdc302bbe61d1fefbc6a4e770e49f,true,120000000000 +SM2VPH5Q2S14DY67M0NBSW6GSY47Z5WRHRWDGB0RK,0xd72c6980c46e4c3b2bab532432dfa93daec3b1b9f858d4b1f7c1e088b5beef3a,true,125000000000 +SMFZTYFFXVZJNBX21ZZB0FZFTTBQT9RBNEZ5FZ01,0x7d8a010fa1024539690f56da86962a43a8b9c142cdea003d40046c62c6c2d16a,true,120000000000 +SM2BMD7QNSDDZXQXXGFNPD8EGSQ69GZF2CQ8Z1XN9,0x253ba5316e8c923fb2e581aa43b4a0e14837072955d6b711565e6a3f2132deb2,true,120000000000 +SM1JFZTVCX1RZCCHWMGWCZ3TY37KVEJZJKFEWP8F7,0xc9046bab41eeead77ac6b916c4818bb43731cbb535de21ab7d2e698ed46de331,true,15000000000000 +SM17AB7JPYHX1BJ0NGPR8TJ8GAQ5E7R65RJPX9EM,0xe44f2b14fbf2f1e80a2fe87d55b9ccd0278613b8999afec6fe90661c94d60ebe,true,5390000000000 +SM39S3W3ADQ5NP68N9R4FWMWBC1NQAS4VWXWWTZYM,0x772fee8ddaa0ad78d3e272b4bf205e91061e94333916836c99484ec6ba224eb4,true,3000000000000 +SP2NHZDAMMEEASE4DKHYYCVAG8RF8PA7YHPPW40BX,0x34383c87108696b62980ba95575bad6d2f41121ed888fcbe11ae284e2d59d902,true,5199000000 +SP3TA7SMY7APYR9SFKDT0527NC0GWR84S3AHEM0NE,0xe21ea78992fc21282803bbededfcd8a215341c83890a531040a790551aea9509,true,50054927941 +SP2C7E0N4PNV1E55SZ0QBHHXYTHHKJ7GTD5T17JGW,0x81100751b3cfdc00716e8d34f4eb0ae0b453830f0e675906bc4645ed55db912d,true,50052337860 +SP6WS2G1W2XHYXHX30PSPS25GDNB3DF7610SFZJC,0xf4b30ba2a3a19649063688fef392e5de32bee0a243ee0cdabf518504006beb91,true,140799000000 +SPG34S51QV6YTZQGVRPZY9323MY4BTCFAFP1HR25,0xf89bd1db3860ae92b1d2ac696ead1c729af49329862ca2ef7dcb1e75a8c2a2ec,true,1204000000 +SP37Q561WR22AXA3EC9GJDN9QGK9K97Z3H940EV9Z,0xff332cb55ca0e6b9e7ab417c052b43f7abbbb485b25261bc33b313e983a9e603,true,59999000000 +SM2CDAXV570733P3K1HAF54C6D63FXQ7X24SJTHVC,0x5c2dc7b668f8d87a2b0545dd0e26afeffb69d9c5ce67cfc04fb3e7f50fbacfab,true,15000000000000 +SP1G2V19PMG1HDAXZP7DY4Z59VSG2SR1BRGDZEGGG,0x0e5896916d38a201f7675bb6bde19abb1a5a66bd1548f9f3326d7f6d8f45aa09,true,238848000000 +SPTF7TRK58APKSPTRFK7N66RSCWE7MZ559A0A88J,0x06409ed827b0875d8d6a24c6ece78b4e59c25c2e36ca27a0b8a37587312ae97e,true,299000000 +SP1SJ7PGM3M7D7J60C39FGXJ29ES1JWVJGJ3XCX75,0x504ead937c63f2bfe790aac500218bbf079d7a3c03ea3e307fdfade45a6c54a0,true,79999000000 +SP103BZSXCX2YF8HXMN8DDP5Z46DN4A0HPRDYJXDD,0xfa3a1312e5d074c8b6d261234f0f53bb3041839c3a69ec65d24c4d9b6fc7e2b1,true,100000000 +SP3N4E7VQVRZVPVARD6QTYCCM3VBMDPNP53TM39AN,0x1cfeb40246c0a76797f29f3fe58863c44bda58c091a0a9a8ad8dc252faa319c2,true,76999000000 +SPETRC149CY5PSKEK1K2Q160MR8YQ924GETDJRSS,0xe52371e373ad1ba353cf9e8a3e7eb953d6c7056dc0f0c4b9efa5794ff6c9466f,true,419998000000 +SP3H4VWAJ9A2468RVKWCGMV33PGJC1Z8CFZZ19ZTR,0xc8ea0db9a9bd10da9fc8a9ac987b85a253149a7d9be2710c9e23735f01fb7194,true,30666000000 +SP2EM86AM2AYGGNJX562AY6BDTKWXQMQVQ0T863M6,0x5be52b38bf9c1270dd6977bd60a597a1965bb47556ea5f1cfe1399e68d11b3d1,true,92490000000 +SP2HCKXC6GAWMAHWH06XGJBTS7JVA6YFRJJB2PCWA,0xac40e60f38d4c8c467066861a149f9f85c0e9a11513eb565303827573624e995,true,2996000000 \ No newline at end of file diff --git a/sips/sip-027/results/multisig-solo-votes.csv b/sips/sip-027/results/multisig-solo-votes.csv new file mode 100644 index 00000000..d2ae72ff --- /dev/null +++ b/sips/sip-027/results/multisig-solo-votes.csv @@ -0,0 +1,2 @@ +voter,txid,for,power +SP3573HMB9SPCTMT85YS85KEPYCX33E6MZGQ5QB2A,0x0bd70b5b1c95c87790644beedaa1b0141aed4e1f8a154f075771049d74bce1e1,true,3449000000000 \ No newline at end of file diff --git a/sips/sip-027/scripts/validate-and-count-votes/index.js b/sips/sip-027/scripts/validate-and-count-votes/index.js new file mode 100644 index 00000000..446eb7c0 --- /dev/null +++ b/sips/sip-027/scripts/validate-and-count-votes/index.js @@ -0,0 +1,845 @@ +import { poxAddressToBtcAddress, poxAddressToTuple } from '@stacks/stacking'; +import axios from 'axios'; +import { cvToJSON } from '@stacks/transactions'; +import { writeFileSync } from 'fs'; + +const MULTISIG_POOL_VOTES_FILE = 'multisig-pool-votes.csv'; +const MULTISIG_SOLO_VOTES_FILE = 'multisig-solo-votes.csv'; + +function convertVotesToCsv(votes) { + const headers = 'voter,txid,for,power\n'; + const rows = votes.map(vote => + `${vote.voter},${vote.txid},${vote.for},${vote.power}` + ).join('\n'); + + return headers + rows; +} + +const YES_STX_ADDRESS = "SPA17ZSXKXS4D8FC51H1KWQDFS31NM29SKZRTCF8"; +const NO_STX_ADDRESS = "SP39DK8BWFM2SA0E3F6NA72104EYG9XB8NXZ91NBE"; + +const YES_BTC_ADDRESS = "399iMhKN9fjpPJLYHzieZA1PfHsFxijyVY"; +const NO_BTC_ADDRESS = "31ssu69FmpxS6bAxjNrX1DfApD8RekK7kp"; + +const CYCLE_TO_CHECK_FOR = 90; + +const GET_EVENTS_API_URL = `https://api.mainnet.hiro.so/extended/v1/tx/events`; +const POX_INFO_URL = `https://api.mainnet.hiro.so/v2/pox`; +const SIGNERS_IN_CYCLE_API_URL = (cycle) => `https://api.hiro.so/extended/v2/pox/cycles/${cycle}/signers`; +const POX_4_ADDRESS = 'SP000000000000000000002Q6VF78.pox-4'; +const LIMIT = 100; + +async function fetchData(offset) { + try { + const response = await axios.get(GET_EVENTS_API_URL, { + params: { + address: POX_4_ADDRESS, + limit: LIMIT, + offset: offset, + }, + }); + + return response.data.events; + } catch (error) { + if (error.response) { + if (error.response.status !== 404) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + return fetchData(offset); + } else { + console.error(`Error: ${error}`); + } + } else { + console.error(`Error: ${error}`); + } + return null; + } +} + +async function fetchAddressTransactionsStacks(offset, address) { + try { + const response = await axios.get(`https://api.hiro.so/extended/v2/addresses/${address}/transactions?limit=50&offset=${offset}`); + + return response.data.results; + } catch (error) { + if (error.response) { + if (error.response.status === 429) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + return fetchAddressTransactionsStacks(offset, address); + } else { + console.error(`Error: ${error}`); + } + } else { + console.error(`Error: ${error}`); + } + return null; + } +} + +async function fetchAddressTransactionsBitcoin(address) { + try { + const response = await axios.get(`https://mempool.space/api/address/${address}/txs`); + + return response.data; + } catch (error) { + if (error.response) { + if (error.response.status === 429) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + return fetchAddressTransactionsBitcoin(address); + } else { + console.error(`Error: ${error}`); + } + } else { + console.error(`Error: ${error}`); + } + return null; + } +} + +async function fetchPoxInfo() { + try { + const response = await axios.get(POX_INFO_URL); + return response.data; + } catch (error) { + if (error.response) { + if (error.response.status === 429) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + return fetchPoxInfo(); + } else { + console.error(`Error fetching PoX info: ${error}`); + } + } else { + console.error(`Error fetching PoX info: ${error}`); + } + return null; + } +} + +async function fetchSignersInCycle(cycle) { + try { + const response = await axios.get(SIGNERS_IN_CYCLE_API_URL(cycle)); + return response.data; + } catch (error) { + if (error.response) { + if (error.response.status === 429) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + return fetchPoxInfo(); + } else { + console.error(`Error fetching signers info: ${error}`); + } + } else { + console.error(`Error fetching signers info: ${error}`); + } + return null; + } +} + +function parseStringToJSON(input) { + function parseValue(value) { + if (value.startsWith('(tuple')) return parseTuple(value); + if (value.startsWith('(some')) return parseSome(value); + if (value === 'none') return null; + if (value.startsWith('u')) return parseInt(value.slice(1), 10); + if (value.startsWith('0x')) return value; + if (value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1); + if (value.startsWith("'")) return value.slice(1); + if (value.startsWith('"') && value.endsWith('"')) return value.slice(1, -1); + if (value.startsWith('"')) return value.slice(1); + return value; + } + + function parseTuple(value) { + const obj = {}; + const tupleContent = value.slice(7, -1).trim(); + const entries = splitEntries(tupleContent); + + entries.forEach((entry) => { + const spaceIndex = entry.indexOf(' '); + const key = entry.slice(1, spaceIndex); + const val = entry.slice(spaceIndex + 1).trim().slice(0, -1); + obj[key] = parseValue(val); + }); + + return obj; + } + + function parseSome(value) { + const someContent = value.slice(5, -1).trim(); + return parseValue(someContent); + } + + function splitEntries(content) { + const entries = []; + let bracketCount = 0; + let startIdx = 0; + + for (let i = 0; i < content.length; i++) { + if (content[i] === '(') bracketCount++; + if (content[i] === ')') bracketCount--; + if (bracketCount === 0 && (content[i] === ' ' || i === content.length - 1)) { + entries.push(content.slice(startIdx, i + 1).trim()); + startIdx = i + 1; + } + } + + return entries; + } + + function parseMain(input) { + const mainContent = input.slice(4, -1).trim(); + if (mainContent.startsWith('(tuple')) return parseTuple(mainContent); + const entries = splitEntries(mainContent); + const result = {}; + + entries.forEach((entry) => { + const spaceIndex = entry.indexOf(' '); + const key = entry.slice(1, spaceIndex); + const val = entry.slice(spaceIndex + 1).trim().slice(0, -1); + result[key] = parseValue(val); + }); + + return result; + } + + return parseMain(input); +} + +function getEventsForAddress(address, allEvents) { + let events = []; + let isDelegator = false; + let delegatedTo = []; + let isSoloStacker = false; + + for (const entry of allEvents) { + if (entry.contract_log.value.repr.includes(address)) { + const result = parseStringToJSON(entry.contract_log.value.repr); + if (result.name == "stack-stx") { + events.push({ + name: result.name, + stacker: result.stacker, + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + signerKey: result.data["signer-key"], + amountUstx: result.data["lock-amount"], + }); + isSoloStacker = true; + } else if (result.name == "stack-extend") { + events.push({ + name: result.name, + stacker: result.stacker, + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + }); + } else if (result.name == "stack-increase") { + events.push({ + name: result.name, + stacker: result.stacker, + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + amountUstx: result.data["total-locked"], + }); + } else if (result.name == "delegate-stx") { + events.push({ + name: result.name, + stacker: result.stacker, + amountUstx: result.data["amount-ustx"], + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + }); + if (result.stacker === address) { + isDelegator = true; + delegatedTo.push(result.data["delegate-to"]); + } + } else if (result.name == "revoke-delegate-stx") { + events.push({ + name: result.name, + stacker: result.stacker, + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + }); + } else if (result.name == "delegate-stack-stx") { + events.push({ + name: result.name, + stacker: result.data.stacker, + amountUstx: result.data["lock-amount"], + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + }); + } else if (result.name == "delegate-stack-extend") { + events.push({ + name: result.name, + stacker: result.data.stacker, + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + }); + } else if (result.name == "delegate-stack-increase") { + events.push({ + name: result.name, + stacker: result.data.stacker, + startCycle: result.data["start-cycle-id"], + endCycle: result.data["end-cycle-id"], + increaseBy: result.data["increase-by"], + totalLocked: result.data["total-locked"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + }); + } else if (result.name == "stack-aggregation-commit-indexed" || result.name == "stack-aggregation-commit") { + events.push({ + name: result.name, + amountUstx: result.data["amount-ustx"], + cycle: result.data["reward-cycle"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + signerKey: result.data["signer-key"], + }); + } else if (result.name == "stack-aggregation-increase") { + events.push({ + name: result.name, + amountUstx: result.data["amount-ustx"], + cycle: result.data["reward-cycle"], + rewardCycleIndex: result.data["reward-cycle-index"], + poxAddress: result.data["pox-addr"] != null ? + poxAddressToBtcAddress( + parseInt(result.data["pox-addr"].version, 16), + Uint8Array.from(Buffer.from(result.data["pox-addr"].hashbytes.slice(2), 'hex')), + 'mainnet', + ) : + null, + }); + }; + }; + }; + + return {events, isDelegator, delegatedTo, isSoloStacker}; +} + +function getStackerForBtcAddress(address, allEvents) { + let print = false; + if (address == "bc1p7l2cywf6qr9gwca3vsv6mwdlkfl3f7agw9kdm98re7jmn087q86suc2lpk" || address == "bc1p6dm28490l7yxl935yplp2pd92psj5yt82sfp2tpqc93ah3u6gges97q9sw") { + print = true; + }; + const addressDeserialized = cvToJSON(poxAddressToTuple(address)); + const version = addressDeserialized.value.version.value; + const hashbytes = addressDeserialized.value.hashbytes.value; + + for (const entry of allEvents) { + if (entry.contract_log.value.repr.includes(version) && entry.contract_log.value.repr.includes(hashbytes)) { + if (print == true) { + console.log(address, entry); + } + const result = parseStringToJSON(entry.contract_log.value.repr); + if (result.name == "stack-stx") { + return result.stacker; + } + } + } + + return "Could not find BTC address"; +} + +async function fetchAllData() { + const poxInfo = await fetchPoxInfo(); + if (poxInfo === null) return; + + let offset = 0; + let moreData = true; + let allEvents = []; + + while (moreData) { + const data = await fetchData(offset); + + if (data && data.length > 0) { + for (const entry of data) { + allEvents.push(entry); + } + offset += LIMIT; + } else { + moreData = false; + } + } + + offset = 0; + moreData = true; + const ADDRESSES = []; + + // 854,950 until 857,050 + + while (moreData) { + const data = await fetchAddressTransactionsStacks(offset, YES_STX_ADDRESS); + + if (data && data.length > 0) { + for (const entry of data) { + if (entry.tx.burn_block_height >= 854950 && entry.tx.burn_block_height < 857050) { + ADDRESSES.push({ + address: entry.tx.sender_address, + time: entry.tx.burn_block_time, + nonce: entry.tx.nonce, + vote: "yes", + txid: entry.tx.tx_id, + }); + }; + } + offset += 50; + } else { + moreData = false; + } + } + + offset = 0; + moreData = true; + + while (moreData) { + const data = await fetchAddressTransactionsStacks(offset, NO_STX_ADDRESS); + + if (data && data.length > 0) { + for (const entry of data) { + if (entry.tx.burn_block_height >= 854950 && entry.tx.burn_block_height < 857050) { + ADDRESSES.push({ + address: entry.tx.sender_address, + time: entry.tx.burn_block_time, + nonce: entry.tx.nonce, + vote: "no", + txid: entry.tx.tx_id, + }); + }; + } + offset += 50; + } else { + moreData = false; + } + } + + const btcYesData = await fetchAddressTransactionsBitcoin(YES_BTC_ADDRESS); + if (btcYesData && btcYesData.length > 0) { + for (const entry of btcYesData) { + if (entry.status.confirmed == true) { + if (entry.status.block_height >= 854950 && entry.status.block_height < 857050) { + ADDRESSES.push({ + btcAddress: entry.vin[0].prevout.scriptpubkey_address, + address: getStackerForBtcAddress(entry.vin[0].prevout.scriptpubkey_address, allEvents), + time: entry.status.block_time, + nonce: null, + vote: "yes", + txid: entry.txid, + }); + }; + }; + } + } + + const btcNoData = await fetchAddressTransactionsBitcoin(NO_BTC_ADDRESS); + if (btcNoData && btcNoData.length > 0) { + for (const entry of btcNoData) { + if (entry.status.confirmed == true) { + if (entry.status.block_height >= 854950 && entry.status.block_height < 857050) { + ADDRESSES.push({ + btcAddress: entry.vin[0].prevout.scriptpubkey_address, + address: getStackerForBtcAddress(entry.vin[0].prevout.scriptpubkey_address, allEvents), + time: entry.status.block_time, + nonce: null, + vote: "no", + txid: entry.txid, + }); + }; + }; + } + } + + ADDRESSES.sort((a, b) => { + if (a.time === b.time) { + return a.nonce - b.nonce; + } + return a.time - b.time; + }); + + // SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9 and SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ are counted as valid votes - voted with pool reward address, no time left to do STX + + let totalVotes = 2; // SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9 + SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ + let validVotes = 2; // SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9 + SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ + let yesVotes = 2; // SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9 + SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ + let noVotes = 0; + let yesVotesInvalid = 0; + let noVotesInvalid = 0; + let notStacking = 0; + let notStackingInCycle = 0; + + let soloStackerVotes = 0; + let delegatorVotes = 2; // SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9 + SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ + let totalSoloStackerAmountYes = 0; + let totalDelegatedAmountYes = 29819000000000 + 20000000000000; // SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9 + SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ + let totalSoloStackerAmountNo = 0; + let totalDelegatedAmountNo = 0; + + let soloStackerVotesForCsv = []; + let poolStackerVotesForCsv = []; + + const verifiedAddresses = []; + + for (const {address, btcAddress, vote, txid} of ADDRESSES) { + console.log("Processing PoX data for", btcAddress !== undefined ? btcAddress : address + ":"); + + if (address == "SM3QS5GHTHQ7HZ1P04XWQJXK5B5HN1V24BEMWM7Q9" || address == "SM14HV23Z50KK8WBK84C3KPJG78EZWPHYHQB584NQ") { + continue; + }; + + if (verifiedAddresses.includes(address)) { + console.log("This address already voted!"); + console.log(); + continue; + }; + + if (address !== "Could not find BTC address") { + verifiedAddresses.push(address); + }; + + let {events, isDelegator, delegatedTo, isSoloStacker} = getEventsForAddress(address, allEvents); + + let wasStacking = false; + let stackingSignerKey = null; + let delegatedAmount = 0; + let stackedAmount = 0; + + totalVotes++; + + if (isDelegator === true) { + for (const delegator of delegatedTo) { + events = getEventsForAddress(delegator, allEvents).events; + events.reverse(); + + let delegations = new Map(); + let acceptedDelegations = new Map(); + let committedDelegations = new Map(); + + let wasAccepted = false; + let acceptedToAddress; + let wasCommitted = false; + + let delegatedAmountLocal = 0; + + for (const event of events) { + const { name, stacker, startCycle, endCycle, poxAddress, amountUstx, increaseBy, totalLocked, cycle, signerKey } = event; + + switch (name) { + case 'delegate-stx': + delegations.set(stacker, { startCycle, endCycle, poxAddress, amountUstx }); + break; + case 'revoke-delegate-stx': + delegations.delete(stacker); + break; + case 'delegate-stack-stx': + acceptedDelegations.set(stacker, [{ startCycle, endCycle, poxAddress, amountUstx }]); + break; + case 'delegate-stack-extend': + if (acceptedDelegations.has(stacker)) { + const existingList = acceptedDelegations.get(stacker); + const lastEntry = existingList[existingList.length - 1]; + + lastEntry.endCycle = endCycle; + acceptedDelegations.set(stacker, existingList); + } + break; + case 'delegate-stack-increase': + if (acceptedDelegations.has(stacker)) { + const existingList = acceptedDelegations.get(stacker); + const lastEntry = existingList[existingList.length - 1]; + + if (lastEntry.amountUstx + increaseBy === totalLocked) { + if (lastEntry.startCycle === startCycle) { + lastEntry.amountUstx += increaseBy; + } else { + const newEntry = { + startCycle: startCycle, + endCycle: lastEntry.endCycle, + poxAddress: lastEntry.poxAddress, + amountUstx: lastEntry.amountUstx + increaseBy, + }; + + lastEntry.endCycle = startCycle; + existingList.push(newEntry); + } + acceptedDelegations.set(stacker, existingList); + } + } + break; + case 'stack-aggregation-commit': + case 'stack-aggregation-commit-indexed': + if (poxAddress) { + if (!committedDelegations.has(poxAddress)) { + committedDelegations.set(poxAddress, [{ startCycle: cycle, endCycle: cycle + 1, amountUstx, signerKey }]); + } else { + const existingList = committedDelegations.get(poxAddress); + existingList.push({ + startCycle: cycle, + endCycle: cycle + 1, + amountUstx, + signerKey, + }); + committedDelegations.set(poxAddress, existingList); + } + } + break; + case 'stack-aggregation-increase': + if (poxAddress) { + const existingList = committedDelegations.get(poxAddress); + if (existingList) { + const entry = existingList.find(e => e.startCycle === cycle); + if (entry) { + entry.amountUstx += amountUstx; + } + } + } + break; + } + } + + acceptedDelegations.forEach((value, key) => { + if (key == address) { + for (const acceptation of value) { + if (acceptation.startCycle <= CYCLE_TO_CHECK_FOR && acceptation.endCycle > CYCLE_TO_CHECK_FOR) { + wasAccepted = true; + acceptedToAddress = acceptation.poxAddress; + delegatedAmountLocal += acceptation.amountUstx; + break; + } + } + } + }); + + committedDelegations.forEach((value, key) => { + if (key === acceptedToAddress) { + for (const commitment of value) { + if (commitment.startCycle == CYCLE_TO_CHECK_FOR) { + wasCommitted = true; + stackingSignerKey = commitment.signerKey; + break; + } + } + } + }); + + if (wasAccepted === true && wasCommitted === true) { + wasStacking = true; + delegatedAmount += delegatedAmountLocal; + } + } + } else if (isSoloStacker === true) { + events.reverse(); + + let soloStacking = new Map(); + + for (const event of events) { + const { name, stacker, startCycle, endCycle, poxAddress, signerKey, amountUstx } = event; + + switch (name) { + case 'stack-stx': + if (!soloStacking.has(stacker)) { + soloStacking.set(stacker, [{ startCycle, endCycle, poxAddress, signerKey, amountUstx }]); + } else { + const existingList = soloStacking.get(stacker); + existingList.push({ startCycle, endCycle, poxAddress, signerKey, amountUstx }); + soloStacking.set(stacker, existingList); + } + break; + case 'stack-extend': + if (soloStacking.has(stacker)) { + const existingListExtend = soloStacking.get(stacker); + const lastEntryExtend = existingListExtend[existingListExtend.length - 1]; + + if (lastEntryExtend.endCycle === startCycle) { + lastEntryExtend.endCycle = endCycle; + soloStacking.set(stacker, existingListExtend); + } + } + break; + case 'stack-increase': + if (soloStacking.has(stacker)) { + const existingList = soloStacking.get(stacker); + const lastEntry = existingList[existingList.length - 1]; + + if (lastEntry.startCycle === startCycle) { + lastEntry.amountUstx = amountUstx; + } else { + const newEntry = { + startCycle: startCycle, + endCycle: lastEntry.endCycle, + poxAddress: lastEntry.poxAddress, + signerKey: signerKey, + amountUstx: amountUstx, + }; + + lastEntry.endCycle = startCycle; + existingList.push(newEntry); + } + soloStacking.set(stacker, existingList); + } + break; + } + } + + soloStacking.forEach((value, key) => { + for (const stack of value) { + if (stack.startCycle <= CYCLE_TO_CHECK_FOR && stack.endCycle > CYCLE_TO_CHECK_FOR) { + wasStacking = true; + stackingSignerKey = stack.signerKey; + stackedAmount += stack.amountUstx; + break; + } + } + }); + } else { + console.log("This address is neither a solo stacker, nor a delegator"); + notStacking++; + if (vote === "yes") { + yesVotesInvalid++; + } else if (vote === "no") { + noVotesInvalid++; + }; + console.log(); + continue; + } + + if (wasStacking === true) { + console.log("This address was a stacker in cycle", CYCLE_TO_CHECK_FOR); + } else { + console.log("This address was not a stacker in cycle", CYCLE_TO_CHECK_FOR); + notStackingInCycle++; + if (vote === "yes") { + yesVotesInvalid++; + } else if (vote === "no") { + noVotesInvalid++; + }; + continue; + }; + + let wasActive = false; + + const signersInCycle = (await fetchSignersInCycle(CYCLE_TO_CHECK_FOR)).results; + for (const signer of signersInCycle) { + if (signer.signing_key === stackingSignerKey) { + wasActive = true; + } + } + + if (wasActive === true) { + console.log("The vote of this address is valid"); + console.log(delegatedAmount, stackedAmount); + validVotes++; + + if (vote === "yes") { + yesVotes++; + totalDelegatedAmountYes += delegatedAmount || 0; + totalSoloStackerAmountYes += stackedAmount || 0; + } else if (vote === "no") { + noVotes++; + totalDelegatedAmountNo += delegatedAmount || 0; + totalSoloStackerAmountNo += stackedAmount || 0; + }; + + if (isDelegator === true) { + delegatorVotes++; + poolStackerVotesForCsv.push({ + voter: btcAddress !== undefined ? btcAddress : address, + txid: txid, + for: vote === "yes" ? true : false, + power: delegatedAmount || 0 + stackedAmount || 0, + }); + }; + + if (isSoloStacker === true) { + soloStackerVotes++; + soloStackerVotesForCsv.push({ + voter: btcAddress !== undefined ? btcAddress : address, + txid: txid, + for: vote === "yes" ? true : false, + power: delegatedAmount || 0 + stackedAmount || 0, + }); + } + } else { + if (vote === "yes") { + yesVotesInvalid++; + } else if (vote === "no") { + noVotesInvalid++; + }; + console.log("This vote is invalid"); + }; + + console.log(); + } + + console.log("Blocks left of cycle", poxInfo.current_cycle.id + ":", poxInfo.next_cycle.blocks_until_prepare_phase); + console.log("Total number of votes (unique addresses):", totalVotes); + console.log("Number of invalid votes:", totalVotes - validVotes); + console.log("Number of valid votes:", validVotes); + console.log("Number of valid YES votes:", yesVotes); + console.log("Number of valid NO votes:", noVotes); + console.log("Number of invalid YES votes:", yesVotesInvalid); + console.log("Number of invalid NO votes:", noVotesInvalid); + console.log("Number of invalid votes (address not stacking at all):", notStacking); + console.log("Number of invalid votes (address not stacking in cycle 90):", notStackingInCycle); + console.log("Out of the valid votes,", delegatorVotes, "were delegators, and", soloStackerVotes, "were solo stackers."); + console.log("Amount delegated YES:", totalDelegatedAmountYes / 1000000 + " STX"); + console.log("Amount solo stacked YES:", totalSoloStackerAmountYes / 1000000 + " STX"); + console.log("Amount delegated NO:", totalDelegatedAmountNo / 1000000 + " STX"); + console.log("Amount solo stacked NO:", totalSoloStackerAmountNo / 1000000 + " STX"); + + const poolVotesCsv = convertVotesToCsv(poolStackerVotesForCsv); + const soloVotesCsv = convertVotesToCsv(soloStackerVotesForCsv); + + writeFileSync(MULTISIG_POOL_VOTES_FILE, poolVotesCsv); + writeFileSync(MULTISIG_SOLO_VOTES_FILE, soloVotesCsv); + + console.log('CSV files have been saved successfully.'); +} + +fetchAllData(); diff --git a/sips/sip-027/scripts/validate-and-count-votes/nonStackerVotes.js b/sips/sip-027/scripts/validate-and-count-votes/nonStackerVotes.js new file mode 100644 index 00000000..8c0287f5 --- /dev/null +++ b/sips/sip-027/scripts/validate-and-count-votes/nonStackerVotes.js @@ -0,0 +1,99 @@ +import axios from "axios"; +import { writeFileSync } from "fs"; + +const STX_ADDRESS = "SP3JP0N1ZXGASRJ0F7QAHWFPGTVK9T2XNXDB908Z.bde001-proposal-voting"; +const MULTISIG_DAO_VOTES_FILE = 'multisig-dao-votes.csv'; + +async function fetchAddressTransactionsStacks(offset, address) { + try { + const response = await axios.get(`https://api.hiro.so/extended/v2/addresses/${address}/transactions?limit=50&offset=${offset}`); + + return response.data.results; + } catch (error) { + if (error.response) { + if (error.response.status === 429) { + await new Promise((resolve) => setTimeout(resolve, 10000)); + return fetchAddressTransactionsStacks(offset, address); + } else { + console.error(`Error: ${error}`); + } + } else { + console.error(`Error: ${error}`); + } + return null; + } +} + +function convertVotesToCsv(votes) { + const headers = 'voter,txid,for,power\n'; + const rows = votes.map(vote => + `${vote.voter},${vote.txid},${vote.for},${vote.power}` + ).join('\n'); + + return headers + rows; +} + +async function fetchAllData() { + let moreData = true; + let offset = 0; + + let noAmount = 0; + let noCount = 0; + + let yesAmount = 0; + let yesCount = 0; + + let daoVotesForCsv = []; + + while (moreData) { + const data = await fetchAddressTransactionsStacks(offset, STX_ADDRESS); + + if (data && data.length > 0) { + for (const entry of data) { + if (entry.tx.burn_block_height >= 854950 && entry.tx.burn_block_height < 857050) { + if (entry.tx.tx_status == "success" && entry.tx.tx_type == "contract_call" && entry.tx.contract_call.function_name == "vote" && entry.tx.contract_call.function_args[2].repr == "'SP3JP0N1ZXGASRJ0F7QAHWFPGTVK9T2XNXDB908Z.sip-027-multisig-transactions") { + if (entry.tx.contract_call.function_args[1].repr == "true") { + const amount = parseInt(entry.tx.contract_call.function_args[0].repr.slice(1)); + yesAmount += amount; + yesCount++; + daoVotesForCsv.push({ + voter: entry.tx.sender_address, + txid: entry.tx.tx_id, + for: true, + power: amount, + }); + } else if (entry.tx.contract_call.function_args[1].repr == "false") { + const amount = parseInt(entry.tx.contract_call.function_args[0].repr.slice(1)); + noAmount += amount; + noCount++; + daoVotesForCsv.push({ + voter: entry.tx.sender_address, + txid: entry.tx.tx_id, + for: false, + power: amount, + }); + } else { + console.log("Wrong data:", entry.tx.contract_call); + }; + }; + }; + } + offset += 50; + } else { + moreData = false; + } + } + + console.log("Amount against:", noAmount); + console.log("Amount for:", yesAmount); + console.log("Count against:", noCount); + console.log("Count for:", yesCount); + + const daoVotesCsv = convertVotesToCsv(daoVotesForCsv); + + writeFileSync(MULTISIG_DAO_VOTES_FILE, daoVotesCsv); + + console.log('CSV files have been saved successfully.'); +} + +fetchAllData() \ No newline at end of file diff --git a/sips/sip-027/scripts/validate-and-count-votes/package-lock.json b/sips/sip-027/scripts/validate-and-count-votes/package-lock.json new file mode 100644 index 00000000..d5e4fd7e --- /dev/null +++ b/sips/sip-027/scripts/validate-and-count-votes/package-lock.json @@ -0,0 +1,386 @@ +{ + "name": "validate-and-count-votes", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validate-and-count-votes", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@stacks/stacking": "^6.15.0", + "@stacks/transactions": "^6.15.0", + "axios": "^1.7.2", + "dotenv": "^16.4.5" + } + }, + "node_modules/@noble/hashes": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.5.tgz", + "integrity": "sha512-LTMZiiLc+V4v1Yi16TD6aX2gmtKszNye0pQgbaLqkvhIqP7nVsSaJsWloGQjJfJ8offaoP5GtX3yY5swbcJxxQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip39": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", + "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@stacks/common": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.16.0.tgz", + "integrity": "sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "@types/node": "^18.0.4" + } + }, + "node_modules/@stacks/encryption": { + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.16.1.tgz", + "integrity": "sha512-DtVNNW/iipyxxRDz73S9DbLfRmBMqQCCog89F1Q1i6JUnl2kBB1PR9SPQfYv9zcAJ37oHoNB4i4b2tJWYr01vg==", + "dependencies": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@scure/bip39": "1.1.0", + "@stacks/common": "^6.16.0", + "@types/node": "^18.0.4", + "base64-js": "^1.5.1", + "bs58": "^5.0.0", + "ripemd160-min": "^0.0.6", + "varuint-bitcoin": "^1.1.2" + } + }, + "node_modules/@stacks/network": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.16.0.tgz", + "integrity": "sha512-uqz9Nb6uf+SeyCKENJN+idt51HAfEeggQKrOMfGjpAeFgZV2CR66soB/ci9+OVQR/SURvasncAz2ScI1blfS8A==", + "dependencies": { + "@stacks/common": "^6.16.0", + "cross-fetch": "^3.1.5" + } + }, + "node_modules/@stacks/stacking": { + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.16.1.tgz", + "integrity": "sha512-Bv7TSyoMrb1wYOfKrPxwDQPSjsohyKCduN1HYMlKL9hHF0J8+MvlJFw9eIj1c2SEOyYaElT+Ly3CI56J/acVxw==", + "dependencies": { + "@noble/hashes": "1.1.5", + "@scure/base": "1.1.1", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.16.1", + "@stacks/network": "^6.16.0", + "@stacks/stacks-blockchain-api-types": "^0.61.0", + "@stacks/transactions": "^6.16.1", + "bs58": "^5.0.0" + } + }, + "node_modules/@stacks/stacks-blockchain-api-types": { + "version": "0.61.0", + "resolved": "https://registry.npmjs.org/@stacks/stacks-blockchain-api-types/-/stacks-blockchain-api-types-0.61.0.tgz", + "integrity": "sha512-yPOfTUboo5eA9BZL/hqMcM71GstrFs9YWzOrJFPeP4cOO1wgYvAcckgBRbgiE3NqeX0A7SLZLDAXLZbATuRq9w==" + }, + "node_modules/@stacks/transactions": { + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.16.1.tgz", + "integrity": "sha512-yCtUM+8IN0QJbnnlFhY1wBW7Q30Cxje3Zmy8DgqdBoM/EPPWadez/8wNWFANVAMyUZeQ9V/FY+8MAw4E+pCReA==", + "dependencies": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.16.0", + "c32check": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.19.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.42.tgz", + "integrity": "sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", + "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "dependencies": { + "base-x": "^4.0.0" + } + }, + "node_modules/c32check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/c32check/-/c32check-2.0.0.tgz", + "integrity": "sha512-rpwfAcS/CMqo0oCqDf3r9eeLgScRE3l/xHDCXhM3UyrfvIn7PrLq63uHh7yYbv8NzaZn5MVsVhIRpQ+5GZ5HyA==", + "dependencies": { + "@noble/hashes": "^1.1.2", + "base-x": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/varuint-bitcoin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", + "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "dependencies": { + "safe-buffer": "^5.1.1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } +} diff --git a/sips/sip-027/scripts/validate-and-count-votes/package.json b/sips/sip-027/scripts/validate-and-count-votes/package.json new file mode 100644 index 00000000..7d87f49c --- /dev/null +++ b/sips/sip-027/scripts/validate-and-count-votes/package.json @@ -0,0 +1,18 @@ +{ + "name": "validate-and-count-votes", + "version": "1.0.0", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@stacks/stacking": "^6.15.0", + "@stacks/transactions": "^6.15.0", + "axios": "^1.7.2", + "dotenv": "^16.4.5" + } +} diff --git a/sips/sip-027/sip-027-non-sequential-multisig-transactions.md b/sips/sip-027/sip-027-non-sequential-multisig-transactions.md new file mode 100644 index 00000000..fa9826e1 --- /dev/null +++ b/sips/sip-027/sip-027-non-sequential-multisig-transactions.md @@ -0,0 +1,413 @@ +# Preamble + +SIP Number: 027 + +Title: Non-sequential Multisig Transactions + +Authors: Jeff Bencin , Vlad Bespalov + +Consideration: Technical + +Type: Consensus + +Status: Draft + +Created: 2023-08-30 + +License: BSD 2-Clause + +Sign-off: + +Discussions-To: https://github.com/stacksgov/sips + +# Abstract + +This SIP proposes a new multisig transaction format which is intended to be easier to use than the current format described in SIP-005. +It does not remove support for the current format, rather it is intended to co-exist with the old format and give users a choice of which format to use. + +The issue with the current format is that it establishes a signer order when funds are sent to multisig account address, and requires signers to sign in the same order to spend the funds. +In practice, the current format has proven difficult to understand and implement, as evidenced by the lack of Stacks multisig implementations today. + +This new format intends to simplify the signing algorithm and remove the requirement for in-order signing, without comprimising on security or increasing transaction size. +It is expected that this will lead to better wallet support for Stacks multisig transactions. + +# Introduction + +Currently, a multisig transaction requires the first signer to sign the transaction itself, and subsequent signers to sign the signature of the previous signer. +For a transaction with *n* signers, the final signature is generated in the following way: + +``` +signature_n(...(signature_2(signature_1(tx)))) +``` + +There are a few drawbacks to doing it this way: + +- The order in which the signers must sign is fixed as soon as funds are sent to a multisig account, which limits flexibility when creating a spending transaction from a multisig account +- The process of signing a transaction requires each signer to validate the entire signature chain before signing, in order to make sure it matches the transaction. + This means the time to fully sign a transaction is `O(n^2)` +- This does not reduce the size of a transaction, as each intermediate signature must still be included +- The algorithm for doing this is complex, and several developers have a hard time understanding and implementing it correctly + +This document proposes having each signer sign the transaction directly: + +``` +signature_1(tx), signature_2(tx), ..., signature_n(tx) +``` + +This would address all of the concerns listed above, and would not increase transaction size or make it easier to forge a signature + +## Examples + +Imagine a DAO that has a management team comprised of five members. +They create a 3 out of 5 multisig account on Stacks. +The existing multisig standard mandates that all transactions from this account be signed in an order which is established upon account creation. +The ordering requirement creates a hierarchy where keys near the start of the sequence have more flexibility than those near the end. +To illustrate some of the limitations this creates: + +- In a scenario where the 1st member initiates a transaction and the 4th signs it, it prohibits the 2nd and 3rd members from signing. The responsibility then falls solely on the 5th member to finalize the transaction. +- Once the 5th member has signed a transaction, no further signatures are possible. +- If the 3rd member initiates a transaction, only the 4th and 5th members are eligible to provide subsequent signatures. +- Initiating a transaction by the 4th or 5th member is impossible, as there are insufficient subsequent members to complete the signing process. + +While such a multisig setup might suffice for smaller teams, as the number of required signers increases, it becomes increasingly difficult to create a transaction. This SIP aims to remove these limitations. + +# Specification + +This is intended to be an update and replacement for the existing +"[Transaction Authorization](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-authorization)" and +"[Transaction Signing and Verifying](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-signing-and-verifying)" sections of SIP-005. +For anything not mentioned here, the rules from SIP-005 still apply. + +### Transaction Encoding + +#### Transaction Authorization + +Each transaction contains a transaction authorization structure, which is used +by the Stacks peer to identify the originating account and sponsored account, to +determine the fee that the spending account will pay, and to +and determine whether or not it is allowed to carry out the encoded state-transition. +It is encoded as follows: + +* A 1-byte **authorization type** field that indicates whether or not the + transaction has a standard or sponsored authorization. + * For standard authorizations, this value MUST be `0x04`. + * For sponsored authorizations, this value MUST be `0x05`. +* One or two **spending conditions**, whose encoding is described below. If the + transaction's authorization type byte indicates that it is a standard +authorization, then there is one spending condition. If it is a sponsored +authorization, then there are two spending conditions that follow. + +_Spending conditions_ are encoded as follows: + +* A 1-byte **hash mode** field that indicates how the origin account authorization's public + keys and signatures should be used to calculate the account address. Four +modes are supported, in the service of emulating the four hash modes supported +in Stacks v1 (which uses Bitcoin hashing routines): + * `0x00`: A single public key is used. Hash it like a Bitcoin P2PKH output. + * `0x01`: One or more public keys are used. Hash them as a Bitcoin multisig P2SH redeem script. + * `0x02`: A single public key is used. Hash it like a Bitcoin P2WPKH-P2SH + output. + * `0x03`: One or more public keys are used. Hash them as a Bitcoin + P2WSH-P2SH output. +* A 20-byte **public key hash**, which is derived from the public key(s) according to the + hashing routine identified by the hash mode. The hash mode and public key +hash uniquely identify the origin account, with the hash mode being used to +derive the appropriate account version number. +* An 8-byte **nonce**. +* An 8-byte **fee**. +* Either a **single-signature spending condition** or a **multisig spending + condition**, described below. If the hash mode byte is either `0x00` or +`0x02`, then a single-signature spending condition follows. Otherwise, a +multisig spending condition follows. + +A _single-signature spending condition_ is encoded as follows: + +* A 1-byte **public key encoding** field to indicate whether or not the + public key should be compressed before hashing. It will be: + * `0x00` for compressed + * `0x01` for uncompressed +* A 65-byte **recoverable ECDSA signature**, which contains a signature +and metadata for a secp256k1 signature. + +A _multisig spending condition_ is encoded as follows: + +* A length-prefixed array of **spending authorization fields**, described + below. +* A 2-byte **signature count** indicating the number of signatures that + are required for the authorization to be valid. + +A _spending authorization field_ is encoded as follows: + +* A 1-byte **field ID**, which can be `0x00`, `0x01`, `0x02`, or + `0x03`. +* The **spending field body**, which will be the following, + depending on the field ID: + * `0x00` or `0x01`: The next 33 bytes are a compressed secp256k1 public key. + If the field ID is `0x00`, the key will be loaded as a compressed + secp256k1 public key. If it is `0x01`, then the key will be loaded as + an uncompressed secp256k1 public key. + * `0x02` or `0x03`: The next 65 bytes are a recoverable secp256k1 ECDSA + signature. If the field ID is `0x02`, then the recovered public + key will be loaded as a compressed public key. If it is `0x03`, + then the recovered public key will be loaded as an uncompressed + public key. + +A _compressed secp256k1 public key_ has the following encoding: + +* A 1-byte sign byte, which is either `0x02` for even values of the curve's `y` + coordinate, or `0x03` for odd values. +* A 32-byte `x` curve coordinate. + +An _uncompressed secp256k1 public key_ has the following encoding: + +* A 1-byte constant `0x04` +* A 32-byte `x` coordinate +* A 32-byte `y` coordinate + +A _recoverable ECDSA secp256k1 signature_ has the following encoding: + +* A 1-byte **recovery ID**, which can have the value `0x00`, `0x01`, `0x02`, or + `0x03`. +* A 32-byte `r` curve coordinate +* A 32-byte `s` curve coordinate. Of the two possible `s` values that may be + calculated from an ECDSA signature on secp256k1, the lower `s` value MUST be +used. + +The number of required signatures and the list of public keys in a spending +condition structure uniquely identifies a standard account. +and can be used to generate its address per the following rules: + +| Hash mode | Spending Condition | Mainnet version | Hash algorithm | +| --------- | ------------------ | --------------- | -------------- | +| `0x00` | Single-signature | 22 | Bitcoin P2PKH | +| `0x01` | Multi-signature | 20 | Bitcoin redeem script P2SH | +| `0x02` | Single-signature | 20 | Bitcoin P2WPK-P2SH | +| `0x03` | Multi-signature | 20 | Bitcoin P2WSH-P2SH | + +In addition to the hash modes specified in SIP-005, this SIP adds two new hash modes: `0x05` and `0x07`. +These numbers were chosen in order to maintain the following relationships: + - `is_multisig = hash_mode & 0x1` + - `is_p2wsh_p2sh = hash_mode & 0x2` + - `is_non_sequential_multisig = hash_mode & 0x4` + +| Hash mode | Spending Condition | Mainnet version | Hash algorithm | +| --------- | ------------------ | --------------- | -------------- | +| `0x05` | Non-sequential multi-signature | 20 | Bitcoin redeem script P2SH | +| `0x07` | Non-sequential multi-signature | 20 | Bitcoin P2WSH-P2SH | + +The corresponding testnet address versions are: +* For 22 (`P` in the c32 alphabet), use 26 (`T` in the c32 alphabet) +* For 20 (`M` in the c32 alphabet), use 21 (`N` in the c32 alphabet). + +The hash algorithms are described below briefly, and mirror hash algorithms used +today in Bitcoin. This is necessary for backwards compatibility with Stacks v1 +accounts, which rely on Bitcoin's scripting language for authorizations. + +_Hash160_: Takes the SHA256 hash of its input, and then takes the RIPEMD160 +hash of the 32-byte + +_Bitcoin P2PKH_: This algorithm takes the ECDSA recoverable signature and +public key encoding byte from the single-signature spending condition, converts them to +a public key, and then calculates the Hash160 of the key's byte representation +(i.e., by serializing the key as a compressed or uncompressed secp256k1 public +key). + +_Bitcoin redeem script P2SH_: This algorithm converts a multisig spending +condition's public keys and recoverable signatures +into a Bitcoin BIP16 P2SH redeem script, and calculates the Hash160 +over the redeem script's bytes (as is done in BIP16). It converts the given ECDSA +recoverable signatures and public key encoding byte values into their respective +(un)compressed secp256k1 public keys to do so. + +_Bitcoin P2WPKH-P2SH_: This algorithm takes the ECDSA recoverable signature and +public key encoding byte from the single-signature spending condition, converts +them to a public key, and generates a P2WPKH witness program, P2SH redeem +script, and finally the Hash160 of the redeem script to get the address's public +key hash. + +_Bitcoin P2WSH-P2SH_: This algorithm takes the ECDSA recoverable signatures and +public key encoding bytes, as well as any given public keys, and converts them +into a multisig P2WSH witness program. It then generates a P2SH redeem script +from the witness program, and obtains the address's public key hash from the +Hash160 of the redeem script. + +The resulting public key hash must match the public key hash given in the +transaction authorization structure. This is only possible if the ECDSA +recoverable signatures recover to the correct public keys, which in turn is only +possible if the corresponding private key(s) signed this transaction. + +#### Transaction Signing and Verifying + +A transaction may have one or two spending conditions. The act of signing +a transaction is the act of generating the signatures for its authorization +structure's spending conditions, and the act of verifying a transaction is the act of (1) verifying +the signatures in each spending condition and (2) verifying that the public key(s) +of each spending condition hash to its address. + +Signing a transaction is performed after all other fields in the transaction are +filled in. The high-level algorithm for filling in the signatures in a spending +condition structure is as follows: + +0. Set the spending condition address, and optionally, its signature count. +1. Clear the other spending condition fields, using the appropriate algorithm below. + If this is a sponsored transaction, and the signer is the origin, then set the sponsor spending condition + to the "signing sentinel" value (see below). +2. Serialize the transaction into a byte sequence, and hash it to form an + initial `sighash`. +3. Calculate the `presign-sighash` over the `sighash` by hashing the + `sighash` with the authorization type byte (0x04 or 0x05), the fee (as an 8-byte big-endian value), + and the nonce (as an 8-byte big-endian value). + +For sequential hash modes `0x00`, `0x01`, `0x02`, and `0x03`: + +4. Calculate the ECDSA signature over the `presign-sighash` by treating this + hash as the message digest. Note that the signature must be a `libsecp256k1` + recoverable signature. +5. Calculate the `postsign-sighash` over the resulting signature and public key + by hashing the `presign-sighash` hash, the signing key's public key encoding byte, and the + signature from step 4 to form the next `sighash`. Store the message + signature and public key encoding byte as a signature auth field. +6. Repeat steps 3-5 for each private key that must sign, using the new `sighash` + from step 5. + +For non-sequential hash modes `0x05` and `0x07`: + +4. Calculate the ECDSA signature over the `presign-sighash` by treating this + hash as the message digest. Note that the signature must be a `libsecp256k1` + recoverable signature. Store the message signature and public key encoding byte as a signature auth field. +5. Repeat step 4 until the signer threshold is reached. + +The algorithms for clearing an authorization structure are as follows: +* If this is a single-signature spending condition, then set the fee and + nonce to 0, and set the signature bytes to 0 (note that the address is _preserved_). +* If this is a multi-signature spending condition, then set the fee and + nonce to 0, and set the vector of authorization fields to the empty vector + (note that the address and the 2-byte signature count are _preserved_). + +While signing a transaction, the implementation keeps a running list of public +keys, public key encoding bytes, and signatures to use to fill in the spending condition once signing +is complete. For single-signature spending conditions, the only data the +signing algorithm needs to return is the public key encoding byte and message signature. For multi-signature +spending conditions, the implementation returns the sequence of public keys and +(public key encoding byte, ECDSA recoverable signature) pairs that make up the condition's authorization fields. +The implementation must take care to preserve the order of public keys and +(encoding-byte, signature) pairs in the multisig spending condition, so that +the verifying algorithm will hash them all in the right order when verifying the +address. + +When signing a sponsored transaction, the origin spending condition signatures +are calculated first, and the sponsor spending conditions are calculated second. +When the origin key(s) sign, the set the sponsor spending condition to a +specially-crafted "signing sentinel" structure. This structure is a +single-signature spending condition, with a hash mode equal to 0x00, an +address and signature of all 0's, a fee and a nonce equal to 0, and a +public key encoding byte equal to 0x00. This way, the origin commits to the +fact that the transaction is sponsored without having to know anything about the +sponsor's spending conditions. + +When sponsoring a transaction, the sponsor uses the same algorithm as above to +calculate its signatures. This way, the sponsor commits to the signature(s) of +the origin when calculating its signatures. + +When verifying a transaction, the implementation verifies the sponsor spending +condition (if present), and then the origin spending condition. It effectively +performs the signing algorithm again, but this time, it verifies signatures and +recovers public keys. + +0. Extract the public key(s) and signature(s) from the spending condition. +1. Clear the spending condition. +2. Serialize the transaction into a byte sequence, and hash it to form an + initial `sighash`. +3. Calculate the `presign-sighash` from the `sighash`, authorization type byte, + fee, and nonce. +4. Use the `presign-sighash` and the next (public key encoding byte, + ECDSA recoverable signature) pair to recover the public key that generated it. + +For sequential hash modes `0x00`, `0x01`, `0x02`, and `0x03`: + +5. Calculate the `postsign-sighash` from `presign-sighash`, the signature, public key encoding + byte, +6. Repeat steps 3-5 for each signature, so that all of the public keys are + recovered. +7. Verify that the sequence of public keys hash to the address, using + the address's indicated public key hashing algorithm, and the number of signatures + matches **exactly** the required number of signatures. + +For non-sequential hash modes `0x05` and `0x07`: + +5. Repeat step 4 for each signature, so that all of the public keys are + recovered. +6. Verify that the sequence of public keys hash to the address, using + the address's indicated public key hashing algorithm, and the number of signatures + is **at least** the required number of signatures. + +When verifying a sponsored transaction, the sponsor's signatures are verified +first. Once verified, the sponsor spending condition is set to the "signing +sentinel" value in order to verify the origin spending condition. + +#### Additional Recommendations + +While this SIP allows signers to sign in any order, the ordering of public keys in the transaction auth fields still affects multisig account address generation. +When funding a multisig account or creating a transaction, it is strongly recommended, but not required, to order public keys from least to greatest (equivalant to lexographically sorting the hex-encoded strings). +This will remove the requirement to remember key order and result in consistent address generation. + +# Related Work + +[PR #139](https://github.com/stacksgov/sips/pull/139): This draft SIP was created earlier but lacked the technical specifications for implementation. The author has since closed this PR in favor of this draft + +# Layer + +Consensus (hard fork) + +# Requires + +[SIP-005](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md) + +# Backwards Compatibility + +The Stacks Blockchain will continue to treat multisig transactions using the current format as valid. +Existing multisig accounts will be able to use the new transaction types to spend previously recieved funds. + +# Activation + +Since this SIP requires a change to the stacks consensus rules a community vote is additionally required. + +## Process of Activation +Users can vote to approve this SIP with either their locked/stacked STX or with unlocked/liquid STX, or both. The criteria for the stacker and non-stacker voting is as follows. + +## For Stackers: + +In order for this SIP to activate, the following criteria must be met by the set of Stacked STX: + +- At least double the amount of Stacked STX locked by the largest Stacker in the cycle preceding the vote must vote at all to activate this SIP. +- Of the Stacked STX that vote, at least 70% of them must vote "yes." + +The voting addresses will be: + +- Bitcoin **YES** Address: 399iMhKN9fjpPJLYHzieZA1PfHsFxijyVY +- Bitcoin **NO** Address: 31ssu69FmpxS6bAxjNrX1DfApD8RekK7kp +- Stacks **YES** Address: SPA17ZSXKXS4D8FC51H1KWQDFS31NM29SKZRTCF8 +- Stacks **NO** Address: SP39DK8BWFM2SA0E3F6NA72104EYG9XB8NXZ91NBE + +which encode the hashes of the following phrases into Bitcoin / Stacks addresses: + +- **YES** to Non-sequential Multisig Transactions +- **NO** to Non-sequential Multisig Transactions + +Stackers (pool and solo) vote by sending a dust stacks to the corresponding stacks address **from the account where their STX are locked**. + +Solo stackers only, can also vote by sending a Bitcoin dust transaction (6000 sats) to the corresponding bitcoin address. + +## For Non-Stackers: + +Users with liquid STX can vote on proposals using the Ecosystem DAO. Liquid STX is the users balance, less any STX they have locked in PoX stacking protocol, at the block height at which the voting started (preventing the same STX from being transferred between accounts and used to effectively double vote). This is referred to generally as "snapshot" voting. + +For this SIP to pass, 66% of all liquid STX committed by voting must be in favour of the proposal. + +The act of not voting is the act of siding with the outcome, whatever it may be. We believe that these thresholds are sufficient to demonstrate interest from Stackers -- Stacks users who have a long-term interest in the Stacks blockchain's successful operation -- in performing this upgrade. + +If the majority vote is **YES**, order-independent multisig transactions will be enabled upon reaching Stacks Epoch 3.0. + +# Reference Implementations + +To be implemented in Rust. See https://github.com/stacks-network/stacks-blockchain/pull/3710.