From 0be3c6b5f448ccf7380bc60db3abb644db42e88e Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 10 Mar 2023 12:46:21 +0200 Subject: [PATCH] Main Code --- README.md | 3 + __pycache__/config.cpython-310.pyc | Bin 0 -> 918 bytes __pycache__/config.cpython-39.pyc | Bin 0 -> 432 bytes __pycache__/functions.cpython-310.pyc | Bin 0 -> 2295 bytes __pycache__/functions.cpython-38.pyc | Bin 0 -> 1754 bytes __pycache__/functions.cpython-39.pyc | Bin 0 -> 2104 bytes __pycache__/main.cpython-310.pyc | Bin 0 -> 4145 bytes __pycache__/main.cpython-38.pyc | Bin 0 -> 1875 bytes __pycache__/main.cpython-39.pyc | Bin 0 -> 2697 bytes __pycache__/meta.cpython-310.pyc | Bin 0 -> 838 bytes __pycache__/models.cpython-310.pyc | Bin 0 -> 758 bytes __pycache__/models.cpython-38.pyc | Bin 0 -> 943 bytes __pycache__/models.cpython-39.pyc | Bin 0 -> 754 bytes __pycache__/rpcs.cpython-310.pyc | Bin 0 -> 2465 bytes __pycache__/rpcs.cpython-38.pyc | Bin 0 -> 1553 bytes __pycache__/rpcs.cpython-39.pyc | Bin 0 -> 1543 bytes __pycache__/segwit_addr.cpython-38.pyc | Bin 0 -> 4670 bytes config.py | 88 +++++++++ .../__pycache__/bchconvert.cpython-310.pyc | Bin 0 -> 4167 bytes .../__pycache__/bchconvert.cpython-38.pyc | Bin 0 -> 4210 bytes .../__pycache__/bchconvert.cpython-39.pyc | Bin 0 -> 4181 bytes .../__pycache__/crypto.cpython-310.pyc | Bin 0 -> 2066 bytes .../__pycache__/crypto.cpython-38.pyc | Bin 0 -> 2049 bytes .../__pycache__/crypto.cpython-39.pyc | Bin 0 -> 2048 bytes .../__pycache__/moneropy.cpython-310.pyc | Bin 0 -> 3922 bytes .../__pycache__/moneropy.cpython-38.pyc | Bin 0 -> 3925 bytes .../__pycache__/moneropy.cpython-39.pyc | Bin 0 -> 3904 bytes .../__pycache__/segwit_addr.cpython-310.pyc | Bin 0 -> 4694 bytes .../__pycache__/segwit_addr.cpython-38.pyc | Bin 0 -> 4683 bytes .../__pycache__/segwit_addr.cpython-39.pyc | Bin 0 -> 4662 bytes dependencies/bchconvert.py | 129 ++++++++++++ dependencies/crypto.py | 70 +++++++ dependencies/moneropy.py | 185 ++++++++++++++++++ dependencies/segwit_addr.py | 139 +++++++++++++ functions.py | 58 ++++++ main.py | 139 +++++++++++++ meta.py | 24 +++ models.py | 15 ++ requirements.txt | 18 ++ rpcs.py | 66 +++++++ scratch_file | 183 +++++++++++++++++ sql_app/database.py | 15 ++ sql_app/models.py | 25 +++ sql_app/schemas.py | 0 sub.py | 136 +++++++++++++ test.py | 7 + 46 files changed, 1300 insertions(+) create mode 100644 README.md create mode 100644 __pycache__/config.cpython-310.pyc create mode 100644 __pycache__/config.cpython-39.pyc create mode 100644 __pycache__/functions.cpython-310.pyc create mode 100755 __pycache__/functions.cpython-38.pyc create mode 100644 __pycache__/functions.cpython-39.pyc create mode 100644 __pycache__/main.cpython-310.pyc create mode 100755 __pycache__/main.cpython-38.pyc create mode 100644 __pycache__/main.cpython-39.pyc create mode 100644 __pycache__/meta.cpython-310.pyc create mode 100644 __pycache__/models.cpython-310.pyc create mode 100755 __pycache__/models.cpython-38.pyc create mode 100644 __pycache__/models.cpython-39.pyc create mode 100644 __pycache__/rpcs.cpython-310.pyc create mode 100755 __pycache__/rpcs.cpython-38.pyc create mode 100644 __pycache__/rpcs.cpython-39.pyc create mode 100755 __pycache__/segwit_addr.cpython-38.pyc create mode 100755 config.py create mode 100644 dependencies/__pycache__/bchconvert.cpython-310.pyc create mode 100755 dependencies/__pycache__/bchconvert.cpython-38.pyc create mode 100644 dependencies/__pycache__/bchconvert.cpython-39.pyc create mode 100644 dependencies/__pycache__/crypto.cpython-310.pyc create mode 100755 dependencies/__pycache__/crypto.cpython-38.pyc create mode 100644 dependencies/__pycache__/crypto.cpython-39.pyc create mode 100644 dependencies/__pycache__/moneropy.cpython-310.pyc create mode 100755 dependencies/__pycache__/moneropy.cpython-38.pyc create mode 100644 dependencies/__pycache__/moneropy.cpython-39.pyc create mode 100644 dependencies/__pycache__/segwit_addr.cpython-310.pyc create mode 100755 dependencies/__pycache__/segwit_addr.cpython-38.pyc create mode 100644 dependencies/__pycache__/segwit_addr.cpython-39.pyc create mode 100755 dependencies/bchconvert.py create mode 100755 dependencies/crypto.py create mode 100755 dependencies/moneropy.py create mode 100755 dependencies/segwit_addr.py create mode 100755 functions.py create mode 100755 main.py create mode 100644 meta.py create mode 100755 models.py create mode 100644 requirements.txt create mode 100755 rpcs.py create mode 100644 scratch_file create mode 100644 sql_app/database.py create mode 100644 sql_app/models.py create mode 100644 sql_app/schemas.py create mode 100644 sub.py create mode 100644 test.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..4402136 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# fastapi +# yes + diff --git a/__pycache__/config.cpython-310.pyc b/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a611641cba959eab090fc62c5ea6791869ab65c4 GIT binary patch literal 918 zcmbV~Pj3=I7{-U4DNx#CYis=*QL|o-D;I)33T<0-=PNDt{k-yQGutaWd1NqibNL`6V)a6Jt65D;Z z003TCS~3%fxT;oFOI?X3EmN)5YxPtrkup=uB$~u`TSr>5q$jA=BW1m9Y^d2Du4nfv zJ*>C(_nyUS2O3?I5kpOzx(sz}hqFs9hwCb(Ue6fs*)IU#87ep2#StUUjpm&ZV<{5z z-d^U(&n8bUG+no|swl&)BqH%uH5pCDm6z0Rzi>LH3>_c;Jq{E=9CCocY&pjeN14GQ zmoS^t8N_*RYL5$f26r|MHr}$$YD;Wm_xmIO3^}&#;&9JuG~=%_8;4r4YIGZ~=Z*_s zk3OV_!c8|$ZomEU9G2nv@EfJkuOw=83PA5^F~h3l*%O;^3`=r$|NnzVBNAl0%um# z68LpbsqpisO3kh*nr(LXthP&)!g@KMQP!%|&1|hJrroaZHX@xv7JRU0lWxm;C{B&O o=a7)(6M@d8!2c=q$NxpTKls*vCWQv-BBE1i<|2RKq0`XMzh08r{Qv*} literal 0 HcmV?d00001 diff --git a/__pycache__/config.cpython-39.pyc b/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9baa7ef11c28ef3972762aa1d19035afd92cf106 GIT binary patch literal 432 zcmYjNO>f#j5M8qi2?ToTIf^3Xz{O^b`LI+qi6MbRDQbvOs=e7eYl;LId4W)RP5%Xd zpckax_$|Iwxh2Qkl1j;fnyT|OZ{8b?G}7~OxeQWu=RWdZnwo3#f2EW;QY|e-fIx!; zU?7lOkeinRl%tj_daW+Ogl5y>`w>RrhikH zr+E^Sub~{rWE4h>MD)RW`m&u4~i@NgLPy87r_y!~Mi!lW-gl6AiOiW1si P{2?zS^QKejfBWZG5@~R` literal 0 HcmV?d00001 diff --git a/__pycache__/functions.cpython-310.pyc b/__pycache__/functions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..024a406cd4051faa9404ac83e2bf06ec5effb08f GIT binary patch literal 2295 zcmZ8i&2Jnv6t~CowVT~^+omL?AR*MtNY$pB&`+VNpMgkigp?p)q$=7SPm^hOXM*jd z&1!N$g(FCa8y7a>#J}V#r~L~+T*}X$&34nVY(GES&+p^+-W1Jdo#6ZP2gd(s5c0QK z%zh3Q_tE7L11FsJ$$-X`RB>J?Z>`78^nQ~!#K2aEw0(Q9@n|U*^eZi zs}b&U4^)HuJiy%KA+KSc=XE}Z`5dR4Bx;QDKG{g9nI@l)+4M)~@(_a}BU+LZI&x0P zF)b-4ik0*Y<#dVs`vj6^z2tJ)w|RgEaU1 zPfJ$1MtdV^&k=XHyGghQ-TaMlh}XwPw=u)8wHDR2-|Ncs#_hP)yK$SRNx@UicGK6I z_0wE?qMPreI@s;X-G0{7zTEAu+_VU#ZG4>c2>HWSJ$>8CIYZ^I4JT|6tKXrEQlO2Z*HD5gYiZ+ESSR+ zBcItTAAuv031rEsJ1qv|nEQ{o0>&Bhj4xbtYu+y)IOUGXjboD=KwjTDc7QdQOo?(w zo;8ty!wjcnKoT>ij(meItS6@1wTCsbV!H2R?M?6+D5iqaExkoj`iqcnUtkJot!U%6 zDA=%0im3MY(j@8bi6tmGeuyFa_wC!aYf&wpdnAtbRna!E5yoyYhe3P$BFmMyY#1LJ zhM(pYe5De?BwQ5gpyKhFdoJ&)t_}_XF~BDdCqV5?sTI*OGT-z5r7A$%Rm8R@w<4UB zM&$+#Y3S53wpa^jYtRL!LEVP9ip|7e;Pf-}G$eNck&=wa30MYmq7A1bM8FmU0v9H< zi=8EfQt<{w#_%eqb07R`${8^pl=Q^0_sAX-*LVm#);5jQI?ilQr9zT?GLbqrLpN}0 z{mctZi|~2ypW7GeXI^+d^TIitDW@+$Z&6q%p(t%yQ1Mnt7m+(W#NKe`=6S4to8G(t zeSV(kb`d+jp6X*P;S1pWuKdaeD97MMmo_x(sl;MP(~hRA!nihOy`-a^Ub3}@I;Ij$ zpK1DZY`0vjJGhnX4ja8pB}JAe0M=d2hA9pzO^2Gj9*8K=UcY#i3R^SuoJ@CKWop~R zy@FdEB9bBpj+72FxqaB}XWWK6aaQajtRt;}dU}>tVE$)W8BNd$&_RY??ir;T|C7e*oYdCV z5lK7HPqj;qF#qASiz6)T!mH`nUtZlHpZ+I3&i-?cM|kJ%`7S}*!MQ#!m_8?smhVlc z)fYOoAm_U>$8?I*r_kw3kVCjz^agtexZh=URMR^~edGUD=IMDlmE##y#0V#447e^D zu5SyjOWG6H3h%Osef__#6WJNOuug=3RqE3{r=Nk!X;5PE6*zJD5D)#_r!z*|AF@8u z=K~Mz+=jE$&}%xn0H-X-1A4`D^9-z6gMMD}LjKE!@vVQ&pEH;nWtKU02yWOb50urG zF~@M56mBWJH1@$9Ykv%v3vJv9t#;f}q#Y}(Cu4;_RQUebhEQmO--7(Ob5Lz3GR~4T zjzs5OWgRd8N`()Uwb$q4P0gk+aY$N=Az6&ZkHAr+wKPAe+;$|`@=6%Amsco@Gs=|J zVS7-GrOM$^y3Lf=0p4EHR<7toi_32-zn!F!h?7JGyD6Z1$=1FKz@W)C6H-kGw*4fL zn-Qg4xdm+nl*U>5m~k2UiP(G`^%AQ5ewH$x4fd7O%bqYkUr}zK$xcRBD;nP}c-qARmO^Zvb!57t&cYTk*2TwS}@Txf3Xrm;-2R4jnHT3PFst{DKE z_#6g=ecZrxdP4Pru_0sb?-|5} zdCgVCr$#jx0QIBw}ro^qnFP`%kAN> tLyS-BVO9@w8fwFNSTaS;`kooCL0I`W`x)KsvG??O7W!oCMXBPe&YwaBv84b2 literal 0 HcmV?d00001 diff --git a/__pycache__/functions.cpython-39.pyc b/__pycache__/functions.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..913e62cb5fbadeee022c7d33ff973837a5f0ee23 GIT binary patch literal 2104 zcmcH)OKc-G)b@OnCfQQ9zukhC3sRO<(xkK$v_e!{%B}7hET&VT+S};Uak((>!4!8bgi`RnL-@}rreqdTYlnziL)?b_ zFD2^X6rbT9IYV8N5{jgik`qjw8T2V=bb-3qp@Tg;wYrY9sY|^RvWh;M>AKSCxzg+T zsdJ{SWx$%VM^ig>AO}ZV0&ibXe*@9X2GS8wPw&z!?EfUQy)illageT;dL~jW|D%@G zI*F~ZQ<5|wpWF^P#r%hhEKaeohg4qk&Z&ZtJpNB|yz$RDp5ndxSF?oJI#=?%X7U_2 zv3zeb%{`T=1v=l2bWEl=IfhK10Ug5KVQx@6ko#5UdU;(j>Kpp;NKfz6i4;$xA&+n} z;(@JajjeBowytYR+!<1nhWGXVdQN0-_o;It{HsxXI_Kmwh;j-dvG_7{96rHaKlSOf ziS18W=;{8zT|2d*cV_gN_O3yfWzr0tHQD?D*bO87WMmigZyJj)|EvC-k(nQ9nXW@{ z!=77LR!v46!);QyqVPiB2ehy0K3p!exfWQpsG>+MQdUz&3csW9+kG2Yfemy8^rJ>6 zSBquTj*}=9jn|abVIU|K?kMZ9#rs>@n!dyVsZ;|}4f_uV#6odgxwTNR#pNJVTU@3r zYE!1H20H|AEKv>*lR8sg1MD{AnsP-WtS&AozZNH+9d*>-%mlF<7QQQ$`n7VU`rma=t(3Lge8xCIZ&h4AaLp&TJYF26ziHl+Nd zQhrY`F3Pobt-RWf_FF8GqWso_%{N!dYoU-U?>;D(%G>)%B;$4>N)T0ksZ_ za{vhYcm@~nbr?3RQ+OO!8(_l``aaybn*KrDPW|>hrr)J z^XA=zckwtSJ@_NQJ-6Wnbq)|;)qHC8;I+Qsoa62+suPg*KsV8n@Xq_7)iGKGGo7ZB<<)Abvb0>Z04=I^IIbjG_%4*p7CXRQbB@ z5g}_wN!Vgg=G|s2mHiMdLD5o}DqK@IG*usfm%xkiP0y_+f&(Sy03bL+V$RpaK2${4 z=tY=5OuhvCVlJ4WY?mdJB~i>o=~8R+=RqKtzQVp}a(+v5C$Dfv&CXu{9-q`;R)d=w mlr_+mG>$LDu6vgc61dxH)BPrUUDsOV0O)qhK`Z*UAO8icmiKl5 literal 0 HcmV?d00001 diff --git a/__pycache__/main.cpython-310.pyc b/__pycache__/main.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4e0df8b3b07abc481b01e86597e2bba40683e27 GIT binary patch literal 4145 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 BG06Y` literal 0 HcmV?d00001 diff --git a/__pycache__/main.cpython-38.pyc b/__pycache__/main.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..fc8190707fe625970c3e0d404bf6152645842a82 GIT binary patch literal 1875 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 IEE+|B0GvVGumAu6 literal 0 HcmV?d00001 diff --git a/__pycache__/models.cpython-310.pyc b/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9caba6c766e427f3c1c9638ba2eacb0088f77d7 GIT binary patch literal 758 zcma)4y^ho{5VqrWoZZWEThQgP?i@iAO$}*jMQP9z zleDa2QD@`_V(M)XYc&qQF(8CzpPn38*O2{kky z!KW<@?|SWp(%OP^KC6{6TUEc`6sgao>{JU<`h}EjuSXN~T*?olGB-EO4b~q@sk*Ko zR4Cg?X+vpWiM@kcgr5(}D+kt<+kRV~^!3<6H@Ncb;`Qlq`AoUt_~k{38Nj%QyS?S; z7naKq79^t?UD0^@ZxSBi)Bhs@QY2$`Ll8$&QY1zA^b&^Ac2-~@f1tq)O&1&T`EOF> zXpLuY0Eu(h?C3UyuycHG!|2$90C|9AfIxyx0{r1&(hkGf3L$v8;4t-=W1l&VH=82! zLQfMBWB7E~@0#vyj9O*8y;j}O)HY0IWG1@(EtAjI)89SDsU|Mu%t?-kR>@ud3*)?@ A&Hw-a literal 0 HcmV?d00001 diff --git a/__pycache__/models.cpython-38.pyc b/__pycache__/models.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..675b4630f1267ea4cac968805ff81a988200635e GIT binary patch literal 943 zcma)5J#W-77AMi;FS(H?y^yN*6K^*RWDmM|0w7Tp2~@>PB(Y3HG#|zoMk4Ve z1UWp10^yUy(KA`g=CgEZEA6LVILd|4(ioT3T&WMdzFZWk%NXl;D;aYm#@b%2m5(Qk zU9Gvgd4rABZig}6b-m@jY{QuLrF}>G9t;6~KP%hLmUX!_Qk&9jbZ^Q7X)bNQDqkPJ zJv`liU%ukT?w=l)yCr-}Dzm%VXaYO0zl))2n+s$|m6aUW)nSv?FjZp;5Nx>ZI z(lcq-y3-Uka$_NlZMq=LP5zq0)>=9IQG$U6M6b=FpgM>7+FvO>_Av1<_2A9Wv4?+t z4AG9y%>eu=<6%%Z@hW|OyUNG#cDqV}K}q8BLCMMak$wR49c|%=`Gs5*WP7!D)%Xxr z--mAeKjCZCKC>utN5yb!gFctq&8q1xf?}7gHiCDyskL7fPA!NEYwxncW%J>Zy@20w N@M99e6VJ$u{s9w*zRCaq literal 0 HcmV?d00001 diff --git a/__pycache__/models.cpython-39.pyc b/__pycache__/models.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad7bd0e3be90fe3c56763e4c8fdee1f51375b419 GIT binary patch literal 754 zcma)4v5wR*5Vhkt$?j#jYx#swY_NJABAl4}ACQbjlOnc&HR-6iN_8+;I6$$fqWEp#8i zXFa&Lqw={_%7C@LXroxU0{{cIshpw!XN0_4urQBCR`naapfxyaTjd?+=D! zX4p1ESkeMl^!=NJ`xy9tBtV8_q&Ea{Bqc*qa-Us+o6KNxEaZScWcxe_ItkSMxl? u3O;j(eK)*`HJf68P;zixYr;%MUSitc?(xND{&Np-rim>ON{TBv;lBXBi=pWN literal 0 HcmV?d00001 diff --git a/__pycache__/rpcs.cpython-310.pyc b/__pycache__/rpcs.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d034b6abda765b406afd0b518f466daec923f21b GIT binary patch literal 2465 zcma)8&2JM&6rb5IuN~VlA$+x{Y(G?R8*BszD5@%GAV4Kj1gYBYp{vC+A#2vVW@el; z>H5-e?SIe%Ip*K!iN9g4Jw@sbPOd8Ty>XnFFSR?G-+a%TH}AdQY+kEX2z-A$|EI&N zg#3w(>Cb`2HOTTd03(d1BpjDCq^50!7L-$g`{?%hZpajC8k)LIAor#}lC*C4+*4ZsP?1bLKMPf2KxC4~-i zVNXw&?%!LyolDihMUxNfm=__-4*(Q-Mt4X-BCDW)Hg1++&0z$#v6r{1ojg-KQ|HxY zpKmqdem_k*u}bo+-IaOPbhR(|lK~uA>e2%)C5&i4lKV9$8i*9yYdmIL$fl(o$lAuze%%40<3=wr|~8xp}?46vJKIyVGv9MZY6k{Y}^_O0q;n zk&8-r02S)dI^AmQYuuVlct!OxO!Oh&!c~6(py~xxR$*;ZRQq>(hYsNuhYoXwZkcS= z3(~c_4xkI!D{SVm(r?bt`<`ThLsY5jcgve!QG%&(n16)~9Vp9>EpbUzSY@03N|`$> zsTnr&tXeobbemH0Bgy;?Qn=zK^jEPbqfZ)z*R8SIIu#+TtgAY zBJRnsgjR&R-Lv6NmR9y=p=jE=v~Mu&uvo>qq>>)b2WpSPus|3sEX7I6S)lR&TqNTi z6|CkW5WJTw9`r@t;cOsy(23KuHA)uqLCUhT>c1y11RF`31~TQmZ?;q$c_29mVKRs_ zkhsRPK#9#DeiSEJaPF63(91!R5($^h(S^nFao}w4JWvp?DvpPRZCbn5-gD3>c?o)r zPJ$Or&Iqm?tb&%H#?@d%1MPAlaxpr36N><3o5`Ty)j)fK%R#D|4ej8SYL^XqeW{%^ zkxG=k9tAp~KyMW2z`DYJ?(jawlhm{OCx?cSpvyNWgWBzjBvaZ0m3pz#Gg8HB zAfrysxVB+ilpllK-LgOu3(H{ByT;UF4&{{k@n)LGEOgB^g~!%nb|?;Q30g`FX4!|c z@Nga`j7@wvO@`IU_%{!}T{hu6h8oIn(AKD$Yyljn4kQcGY1*K^Ne-Q(*58irWB-dv z{WSE>L-OfXbrQa~$?`7nN)%;rk4KTNL{TqigB0u4D0(u8)A5L?gB)=Y0hwe9@H_(f z8na;upZK)un7(%stH2-t^7P;=Kis|F!Nrpg>j&KVDKuW^&cZ_8ENnnGK~D7yhtlO{ z$(ULoR~b(*KA_!b0JH~1KbF#XMAI?06EiSTJ7(0!!Hrz7*L6e9KY=XK+Q@*IDs*dh zeDp&SM3pArgaj9%L%swUlVD*Ukv9l%9%#?%f=YRuc`F&NPm$p|tUChh-bIE2 zSxz(%jsh&Lh5E-a~jF0iR)k&!{+q5FmVr@DV_B zPJE1YG}74W=rmK|kIp2nAbf#|_P-nlJG`tQ3F-1AsnUiuf978^C_W|t literal 0 HcmV?d00001 diff --git a/__pycache__/rpcs.cpython-38.pyc b/__pycache__/rpcs.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..5afee60359aa8dab881a433c2de2a87d9368e244 GIT binary patch literal 1553 zcmahJO>f*pbjBWgKeC&oX(4S@MZT3qVYjL{pbDW@At^;AM5Gne7i;iLhT#)z=`~ZH#TscL`F{hq*&zn`l0d=hR=DnFW@B8^>x7#MLF8+8JUwVZ6 zgUt2CfO!m{HvtJEXiCEQPD5JrPUt)(!V&HX5w3KP-H-{oPkQVeUXa}w@%7~Z^B6$i z10)G*2^~R&b3#H_xPrmXga;aY+xTX0>x*2Q7#}Sb(g<4sdIOLlr}T_eByuVW*hOUt zQcMs~%9=y~bG0;aU*MrZc9+|utJb(6Ld+*7s z!4B8v$=eL#e^sZYz*tH}Ecf&ZicEj9t30_aOXn1YHL zr*e)dhX1>JMrV-C853;gm3J#LbcYPE2jEw(@P2b={B*mj#Qp{4H6x^o4lTE zRQ_;9bVm*K7wA|vtH>YIbs|>Q3D7sz3F@uJxlf%QwZ^9W3n4-O_#7f6#NSKbGb&7uGMh;$x^GRuyu54lPY~pk9ru(pe_B;pY^N z6{2!;hbO5Nfyo2tkxa%WILK9?B>D`x`aS3TZ+MtoLU`qE=%R(E(9*#H1PjqT3f|DbdQz!el{dF>3&4R|7~*^s zSYJs!O-*mjGEAlQ#B^L}%hE&}g}rK70duJ^zY5z{xp>%?KgY7bxzcv!%5z|93%0er zxU^oOlFV2iLK<^pnMuaddUdMok~Z8-brk19S{H1fGaRS1r5a!)Y(Zhas_U(~XtYuA zqcrCt^yzSS-EQ4iOf1Eh| zAs|BEr;IYkp?B#TZPp*7%XHOYKr@)&d$8Yvuk0-57!~Z|k0y#TK9*5r+fg*m#WY2_ z6Gf9LPvf*pbjBWgKe9=-ACR`HBHzlQup4ng6+*2-5?YC+B1H&atchnry!G17%xqwd z_tNx=#GywH*&}~}U%+peE2mWAf^zDK_q6udEd``b+t`k{c`zNeCZML zClc2e1L6^Ey#+uJK~oYgP8!mhc0y;L2uHZDh;XHQ=7vnr1JYv`@PZ6ugx8k?#3R`H zJ^)EjOXvtHoL3}tg)11GOn9Kdw~eo#?R=4I6XT=hLLB!FY`qDJk_)MH&#_F)^vJq!{Top&@Zs&&;2RCR!C`(l_&kp%V=$)&`%j+lJ|66GZ5}^+ zGUyLf5$k?21zk~+B_@h6zuE^tXq)=9>|RCOUkdyybhOljy$@Ue4FE&0sBtRijAGco zx^p^%EY6r@~CRXNveMe3yM>5&V}_0uJ{-#hqZ(ZUqB<1J*ZOSs$iB0ZukX-YlWcP+T%$o zMPTv(IwO;@3663VC^^oJ3<{OUQcRQ#VxFe`=jCW8pQIvtVE$ivEBGNv(?F+E7PZc! zmJAXtdzVepm)){{!*s=T#}M*t4g!Vu@f!1_w+NosmG zEyGk=PfW&zwk%DwQP`=L6)=qo^Q*9Fm5Y~c`C}{#oF;A8uRI5$wqRSkOQ!V-m1M^H z5Ym_%%Sq%Y!EQ4iOf1Ee{Apk<(r;IYk zq4#K)HtUbkHQIF;;0)&XKAgAVD?7_6Mg>Fsy+l#Q$1;j+JBr4+n52kzqUdD8(*;MZ zfC=>g0gm}KfW9dF<6*Wn)&Y#O`ljcp0O-07Y6CFq=Z7Qc=bC#>N3F6Bs`=@{{%1G| J8r9x${sCuRpIHC^ literal 0 HcmV?d00001 diff --git a/__pycache__/segwit_addr.cpython-38.pyc b/__pycache__/segwit_addr.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..44c6dc22ed06a4b259219aef6f71180f5aacdf4e GIT binary patch literal 4670 zcmb7IO>Y~=8J^iME+tBqT}2;`>uzE^{Reh?sjls%haP$eiu{CPfu4HeALzjs_jzYYN~E1bm)QB**_n6W z=lytwpHEDTF~+G&DejabMi9KS;8IcqY$jf1Q%MJH?*S0*(Xfs!g$7n;c16@ zQ5R;>5LVF?DPccjMN6c`80wT57a7#Hm=Kew)8dqvLOmuZAERT&fuh^&%vp&AJ+j zLe`4yQptB4Ua1t1l}e4K*sD`JQ!4H5x%J+YRH-DIWei()S63cfzZR#G`lm-sX0VPb zUVfZ!_+h@B|2*(ykPi-IGsxfbf?C*Y9d2sXThn1~s;l6mX5M1B!e{`d^UG{$5*mFOqSO2u|&E+zE zQ~#nROx!EDgH04JIA|sO=>t(u*w8msv*((LUsu z<8;hOi;T#;!-TcObkp^hS+czHip(lN}?riP(Wn~-Twi`O- zW}~$idV#_vF%hS{?Uif6UL#li%g=W{t~P$Z_Fnbn{EPF|e_y|QyZYD7=}VIAzB`Yi z`s&py-lgx6^pP+jQ@Vb|19sNFTi^47I9>64GKHor>gDZPY^w2Chvs8mJ%&h5V1amY zQ<-b2)vO-?@Cz6Vrcf|#5?Z(Mo8lSna5;mqA;r@E1e8+jyJ(PNpD|MAAs2du&%zUr zM`jt>Z2QLQ(-ye|+2w;rYfjaNr6!Uq@98U}rzvI8xuJc@R!JZ0xRr-gu;-Uk9UiiX zV`p}U{XyF$58?6@<{a@@Z%T2b#aeD5=1)g8Fm{U^g@9SSN=wq(7SmY!`#sfc%T~!# zQs-{fn`O5iETYkWN8#}Q3Ai*6u=_o1CTFQ2bVo#!=P))TlbQg~b;vX_IX?ZGxOu!D zkh+*AX``}gQy&*WH-K*eosfk*0(238JLK>Rgq)ft&xhKMzRn^oG|;<(p1IBhS-IZ+ z=&>iOTL+FiuwkcC-S>QjETLR(`um=WIKmBSmMh&d93#jnlSarDeRFQCZ8v?ZH%N*CZZOBD;Rb>a zEKO6cAis;bi4EaPsQng-BVJ7P+&|GM1qNk%chNZZhf6*6mZj&0-ax%?a*8fV2XK{n zlR_1S(xDaw5=kK@Ybr?PJ7~v7(DKUiG(CHl3YAGNQcH!YKC~ly-^PT1Kx0~lpW)}Y z`~liSu#!6u;{O$NA_^2JBanny256xtgevWM0vTdH!Sw=TDqvmfL+17}y92{R&K@@dhyq#3lhOlf9XN_ak%l9x`v=IO|tG+k7S3EJa@@juq@+Fx=Zz%MU zq6fV-l<{t)vM0+K?jTSW2g!jp4D_(?)8WHqZNEV&Xd$V;@; zn-U!*IhD`*!WCZIg3L-yp)FLr!zLjNCW5af317Jh?EErj#KuPrx>Y%11W{~$K&%_p9WP0(qoB<&RIbv@?9{l}5KlOl*u_1S30-JHyYSN4!|x!n}<#X{~=z0v)*EH|S8Z!fjSq z#}dfui->h|tdl|;F_0qP9P5qQ5i#M%oph8&?q|Wh2rhGn$xk_sR&Y-v;^4&TyDYMo zh$ov7|A2uLgB90Ixj^-Y)VH3~T(IOQwZvX<*z4x*LZr(-N2dI`_f(5a+P6Q$KS!(8 z%-|n*^Tadxwc6Q&0U7NJpD1cucUlC%`^~NQuQ{7;;PrS$fFoE=Wy>DB;IZWbBVT04 zRF)~)Tavya=)FS_Qa_ASy6hC%e0uH7XywFTM3nThDQO#6sAoh?9ic57SJnX z`9}7XOrsea9{zohl*AGtDE>-^3X0VU3A{ipA|Q!i$1sv~YQ+-*97|!}O8$jdq?Hsl ZhMv);On8}QXKd3>+cwHGW3%?@{{b6u=FR{B literal 0 HcmV?d00001 diff --git a/config.py b/config.py new file mode 100755 index 0000000..ab0738e --- /dev/null +++ b/config.py @@ -0,0 +1,88 @@ +### +# RPC Lists +rpcs = { + 'BTC': { + 'host': '172.16.0.2', + 'port': 8332, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'BTCT': { + 'host': '172.16.2.2', + 'port': 18332, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'LTC': { + 'host': '172.16.1.2', + 'port': 9332, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'BCH': { + 'host': '172.16.3.2', + 'port': 8552, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'ZEC': { + 'host': '172.16.5.2', + 'port': 8552, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'DOGE': { + 'host': '172.16.6.2', + 'port': 25555, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'XMR': { + 'host': 'http://172.16.4.3:18083/json_rpc', + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, +} + +DB = { + 'host': 'localhost', + 'port': 3306, + 'user': 'root', + 'pass': 'xegh3kAJyDLaRu' + +} + +fee = { + "REGULAR": { + 'BTC': 0.02, + 'BTCLN': 0.02, + 'BTCT': 0.005, + 'LTC': 0.02, + 'BCH': 0.02, + 'DCR': 0.02, + 'DASH': 0.02, + 'XRP': 0.02, + 'DOGE': 0.02, + 'XMR': 0.06, + 'ZEC': 0.06, + 'USDT': 0.02, + 'ETH': 0.06, + 'XHV': 0.06 + }, + "MERCHANT": { + 'BTC': 0.01, + 'BTCLN': 0.01, + 'BTCT': 0.005, + 'LTC': 0.01, + 'BCH': 0.01, + 'DCR': 0.01, + 'DASH': 0.01, + 'XRP': 0.01, + 'DOGE': 0.01, + 'XMR': 0.01, + 'ZEC': 0.01, + 'USDT': 0.01, + 'ETH': 0.01, + 'XHV': 0.01 + } +} diff --git a/dependencies/__pycache__/bchconvert.cpython-310.pyc b/dependencies/__pycache__/bchconvert.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6568ee9af6d4f167d3302c201196db1b1d7817e1 GIT binary patch literal 4167 zcmZ`+&2t+`6`$_;(CEXmV>@x2EFgAS*r7;Vl@K;;!B$M-Y|Ikjip>HlU}`))j+ICn zrKgodVsu%BJAVKNdvEzaIPw?Fm6H#gmJ6w(!teErY{^-qnm4aMrl;TU{oZ>$@xnsI z!0)gB{#ST>!7%2e4sEGyKE5h70y!r{&H$0ZHA9_4n+`n~OL}4r< zKRk@Wr@ABRopm%rnm+quXxzb-)F2|G#e~t~f?;W%)wg@kgHBs)3L&E;X?kYn`hG9y zM!ug_e7_ruL5K93?>`#^oqXiAAt_)QYYWMe;0j$u@GGe;prL{(>?DPVPfwrbdI;_O^ESnp=A(e@E{gdKdJh)9zSzV=YOJI&tY)S%*Z=B5ra80?$dX(a=lp z!GlgGdK`qq%nF0#uvOh}t1xc&bfW~MRg|b^NZ3w)q|Kw>5JS#7gSSNAH zK}nHH#BKN5%J;9Ll@M?abC|^{Y?;?sjgOWJe_fwW49P#!AL-;ijms(&!Hx{rNcIDp zC+0ClBX5r0FKqjy@#k@+FfZ4&g`{G~&Ot1@fjYNmkI8Rg>GNAJ`F^6L?|&a-2|>8Z zMvG^=)njv;r8%dY{Rj|phX(!58F>S2fd#qvixZZtMEf4_S>bxoSoR3ondstA1_A@#@1EW1B=c)WI z7S;hJ7ofdipLp(hEQn}XwMbQntE9CY2Ay!w2~?4MlR;NAF)Q!iypbni&&nPA0j;lB zaCM%hspt4wqadB)bPe+pqVX~VSMdj0t5dXQC(dDI;(=4Feu;(xUj=(=$xDh)j4@n) z&-i0`%u}X#${&LQAEWnKB?T1(FUDOxZUVP_^a_oFC>}qd7wA-z8Q`>;43n&O=KO;= zv-gKcF_{@2O3!SSPnnZB@j&$l3V8{&>YVBFeJuN9T*)#-g*(h;OU$yZ|GKP>h#g%$ zwVVpwJQG9W{`5!tqw6lNo<3UF>da-JVNJX;S?nR9tPg#w^ek5X@%c@^&J=)#=b<=;ixua_r zaHth?b$Zj0m6f_dzfXZQ&jKBLcWC$I{5ro3DEM2Kk1kFjm@-7KHRpW_VX6|^_&ZQW zjzY$ou(9!5qgS;I#fBFc3}pt)gzvv(FW~jmc+TWi%IztVg3j`Y8`9wO(dDg|{U}tC zXyk$42$Dv-2T#fm@dnQU36#vrTQ9??uaM!j$vF~rzX@X^W?mzmjfs8CuwMdc8Uk*k0N;R0k>feat66v&uU zWR!Je109?s)~Vh>BBMBnA`^XL~it4f*Gmn8lJR?ta!qqC;q_4Na#r9 zh}5yATmWuOc(RFk4$V{L)S}}aN`MU~Rzx|qXPk(FfHzg~##ZWx3KF1$aZ6Omq2m%9 z=%gqT6Dseu=IHiaq~)o<8c6>tX!nxF0H{mw8F`>58lCt>(FzX(86aL{q66g2x1*ci zyihlmQ9~UDy+(|r62_gl*En5dwEl}gG$?G&c0k8`Dj!s+@{&a-t&uxDIJV!sef!p{ zWwzd8X6wCa?qqft4^W~hPs#TnGCS#a+Dg}}oHwmSq_g(HF#npM*U%XxKM~M53T2UK z)(k0@MBE;6RzZY5SO`&*skdGPg=cb z)!3@;rPx0!gR|-6HEViH(!mIy-U(jB&#JVQ0=fAsl!<4 zI+WY`Q<^~$B58v&o7U-?ayR@ zsuO*FqCWBAa-M~MkGiyLyr2rShYzNlvD$jdHS(Lb^=9~bC=)E z&XyTI*Z%Q|e{_bie^Y1jW218ySKLA)ndBX|MZcoMyP_q!R?Fhlw>oyqe#oRP3$K_g z1cjm1a?p2V5&hy&w2HDMXI`;ZNtR^=zcaEbXYpH>)+TGzjh)C_^ny@g!|fnm-S&6=DEu){`g-p`6|f{-u|QMervHvJ zG~q5y`YW0fXQYspw4VZFSU?t5>2IQC$(fcd%dLX^nZcB|99ffdz_uvou+PaQV^?7>%N1kK!agrA7`q1hqI}=jbFu<3FQvsCMSy5;+}M0{ zOq+esuv&$U8yjCgQWOYu-&E=5wXL)U+@jo%Th0$3vX*?Wd!-|4-T*{tQHT6aljiV%_wKvZD{#blt}l-$j$~gt;sc zXnA6(<-~#|!pqt^v?cC6V@E=Y6{bFgT`>1bupF`^0{~W2En=Nx3SXm`77^FD9ffJJ z=N)t+Po_>!1v~8*s)7mWtm|c*bM-+lNNYJ9?#AP_2kSqiwQujOHvv!HZ`i3F2b~>t z4$rD3YL=-P(@;^e5_j8STf6QB^kPDbaR*8%%CH`dB^ zui&1^0LJ@sC%ZNGrZ!73k2iZ29nB8836#hJHQ?I9n4R#ajmV@7jJD!~IIW(9 zekV!`+XoPr)be)~lx}9so79Q+b#Grokx;BoIj(+=Wk1CglZY`TvtU;V1 ze~FR^V%SaNsUb%H!~4;GN7lng*JYps)oq7C-OD7ao+Hq(GA*lozxH@@{kKi`+j|?P zY@q^F^SMUeOlGCUuGi~PB2BZv`Z-;Ve@d zp_7fALL{y1sHmIE&O^K_lX4-D6g7NHB;{vE_)N^5LWjh0j7~`C%xfS*_y8fEBP4*( z$2mgQBtqIg#9<=g(psU)hZgGMAfqgd*^>PQbOOz413R$}i-~>2IeWfET9jBr0Xh|$ z{Y#T1qCBW)u#AXgbohjHjS^%8>EtQp9VjApTK?Ya><4Q~Md}1z!Pl`?pM*|H4pTb!E3ez9sis?MTfbG1&b`hyK51dbgdODO-5EH!P8uTx8 z5_ZUr(C%5P4x5kc5&5#Q0nM|dI6@c*VC3Xi+I|MOmv9G?&cb;D86wuglLewJo^a@i z--`jH9g>c`9oV`Axb2~cUt*p^^Ylz&OPr`t3UG@uN-@*2jzVSAOHkIwj7@4(QBJg@j60R=nt((l3q9 zjqNvY-@a{B(}LMzS}=Pv%t;G=w2xv(M!^Row;{H*e(G`~`+mlmc_K4<@*HnuDKV;vaFvBq&TQ zBeRj)xaN&zG96ZxFPc%Xa$FFn1*O@TR}Pj?MQVta>Jw_nPeof-?^AP$nh&YDiYBeb z+S6^n8|d9gnwpgP`fHj&`Jrfo6Pq@|O(oi(NWGY*l`O%{_rIbzw*KSPY;KEkrDT=t z62{9FTn?^sW}7vp(uwq(vfk)9onGnOLz;Xjj!>XpbNoNc;%9b9KD_2>G1tDQjYYp2h4FD710RqCA=Q@o7NAHyJ( z&b;QRV)Q>1b&OQ{N~Y3JP`fr6Dj1b)tGR`LR1=tx8mXV!R;eAk=C5vo8Tl~_ae&&@ zxcVAnjY{k6%*zoh0CHRf$5p$Je#&Y86)Fd0)OE#1lf UO@BdQHWkhAT+G|GJut-nA2F|;IsgCw literal 0 HcmV?d00001 diff --git a/dependencies/__pycache__/bchconvert.cpython-39.pyc b/dependencies/__pycache__/bchconvert.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25a280f275530db81ca4d2b233957913e6f6cc35 GIT binary patch literal 4181 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 Bmb(A| literal 0 HcmV?d00001 diff --git a/dependencies/__pycache__/crypto.cpython-38.pyc b/dependencies/__pycache__/crypto.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..8dfee760f6df93d9db5a2c0c2cc4a8fa114baa76 GIT binary patch literal 2049 zcmZuyOK%)S5bo}I?Cd6X9Agq&1Sf&;SP6NJ4M~t9KNCa{T1D6i!ct_7r^oAMA2aTm zHQuOKIV2Ki{(*A~|A1RK_`rc*(A+?Zw0{AF!dGptV;g4GUHz!;`s%Cd+WSL8C5G>V z7avFe_>BEYljEO*$pTuogif+GCb<+(*&3IQbRmWGqz~!Hf(#&CS(GJ6Po9xyA$@sX z4$E^-`C37atg!N^xw4%;Qr*vXZ`L+v@*Vm8bT<24`_oSvTTy(y)d_DjBMwu8515#T zwv3i-pp(1@1Z15o*Swz4>^6J2)N?eKg?ZL$}B!2XqW9PY-ED2x8l${!QIw_kFsxC5R2 z*%$gZ2P?r~<@v@p4}YdpBZHMx{xI2P{dWiRSC3ykzRddMVIPhC#LB+$cfw{T&Wsan zHB7M@VJvC1l0S0!2HcAPb!So!Mi>YaOw z-&Q^kvwZR1-O5x&#%bJ^aXYHVStU~4G*70|t|_ERv)f7}`IB8DFx(Y_AO8M!{eTC2 z#I_NxMzMb)P{bIKV*@pY!9k)>aGoGpYWyNm>sC)3q61`a1uYv#S7Vwz9O?0#X^vxT zf&D19T^!{7%h)b+<0ML!g%MNJhVQ=SK%K|7Dcx$;vph;#>D&dnlJ52a>(SLz#hdlr z^>{Z8+j8nwGl{}xHiyALUlpNi?}HKlK>hUfLnm%|lPr)2jH?OsksZ?p8h2#S@O4okT7>d#<+GuHA7q#^#yy7T7b++4hWf zz>8l!08aK4C0@Tkqc_l%JsTy9&A8;K@l@EZ#l{a)N&zSk=ZJjRZ6={yb14PDa3@!k zv8UZ11!qyG8RqeNv=v8y*W}N4- zIt{b9F*_sUD3S4d(8?%63`7Ndl&kkK{trw_Sqqb#mMC@>M80u)sP zl7-%7o0q{ zr}nL7AE9*)pADrZ7^L`?OU9L99-3fNC9REmo*6$+taQ>)8Yhe*;~vaaoEx_l?(UcZ z`gQE6VO(*V?K4r*Mw;eyXcqe!MI2?-{?76-TTFdhRH?XLu<-o@G u^`o%wOHqp31hQeX+Q+Qhw_+<|a0?~9(~Re+K4%2db%OJO8w6;Dpztrl#gx_n literal 0 HcmV?d00001 diff --git a/dependencies/__pycache__/crypto.cpython-39.pyc b/dependencies/__pycache__/crypto.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f6babba52a7d4018282d7b3a5b607b0d55a7e24 GIT binary patch literal 2048 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 literal 0 HcmV?d00001 diff --git a/dependencies/__pycache__/moneropy.cpython-38.pyc b/dependencies/__pycache__/moneropy.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..476f93e758a0112f6690ec4fe93e0fdc6df82859 GIT binary patch literal 3925 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 literal 0 HcmV?d00001 diff --git a/dependencies/__pycache__/segwit_addr.cpython-310.pyc b/dependencies/__pycache__/segwit_addr.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cd864fbbbd665f07024b7ac1d16e89c021fa10d GIT binary patch literal 4694 zcmb7IOLG(16~4D$YS}V29^(f?NDq&h2pF3&Oy&_VHpVaICdCv+M#Qw3 zL48CVUt`4+&82((hA;iV^POtFQS<> z6+-$^^qoCdR>R%MiFO-}P{zJ+AiG)!N$9Y)hGMm7rFOX- zxOKl=PKV0ndMI{l)Gn0EJG*YJ^Cnj=i_pWcb$w;|_NDnWm(@Rg$z%chsN&Va+%F^63{(KCf)d$9v-O#pu#j@ag64P0#;feb@c0R{hJxZ_j)5VcnmF zhKXkxPxKH)1(x#-Z^3$6TEcFyN2gnQq6z&PYZ<7GMJCJzmgq~YrNwCPbIciQnTeJd ziFu6)ZIQ{35}uedEa1Xg#k`&4J9eT0nOyVoognsQ;MSat-M~|(5pTM&xo*8h0-!|JP<7bmO#ymb9)^>6DF=Oh_^dj>`I_3PKX zP2VEv17Sm^bc2cy@T@(zw(Cb}zTyXD3!yCO-sW~{s_|5h!$!)h2N=l_Y>*yVSN2+N zgtezY{4~a*aTK;j8n^ivFYuFGdu?cP62pCJB?$;9rPfnukUKtOq|kjX^a`JXGaigg zF*4ic<&`H5@(MD|+xPA|)d0qt$*vrztB{Vilu^(2olE9Q8d<}moTP#?AK5J)vxMVh zc8&d6+aV~p9L1cMJk>)fUTUc}dokrt26ZrWg?xp;S@;Cg|3mvvv*y{3YBpt~>?@gP zuhc@%twjrHbXO=G{y*^+d*ZdfkE7%i6@>19VDbdUNFw>Y?n?l!L!N<&>Crbtox_TV zKID`p9aJ8*yFUW02i!$;VixlRpe2B8pTj2*Z?-i#8f#nn8cVd;KyMN~a}Bl+#p=y3 zANaDm@zim97VK22dw!rWC49Xw*z;Am5pGPgTu`47GGZgq5kj+ zYyv(Zc+cbzfeK-@wy+m*UorGcr$^?{QiUDhA2~kUXo?(d;K(Xuv##HQ@?_%k8 z^1K5}LD^MejDD#`nA0|a}KW>RA-tOiBnK=JY;43}&~!u4w451y2c^zFPt zXVQ0!X(za(c++Q;q~@Ng|A7wj=%Mtm&!b}rd(K}#{oA^nLR;&$1;rfou0=JR>IHIj z!iBlbqIuNT6oU%_m~A7P&srk4ZOF^C67FYbNrzSd%>3`P8I_W7=1R7=$S0geTbdXW z!<4cH=eG3NLbliUH8280o7GBs7DMb4j7^ zzDHnof0Rpm?)P_eC~x60E39P+B=`kHxoOtQp^fNAF>ji6#_WVB@oX!fibSimN=*5nGe=8II=wf~!YSBw+l&NuIP_L-C<*YsXf#jXQcSnzGzfx^!;O#Uopm?z zJJch>m25W4prn~qa3{+JN`WX2sXSA%Hzb9+I4W6jNHq|0fu8Gmsgd=iAD4`}`(&?_ zLs`Zf`5rbKgl)LPc4!e@Fd{NK100%wnovC20+%L6Z38g-JMAk&H;|(Yefm3^C6}?F zkEHcoTE4~G%vWF4oG&} zHiG3jT1mkSYlhIDKh)2I?cD6F8%B8UwhPoAnD_IicDtg(dw{Ax?7eku;)q`EBsZuOLLj4y^-y#Y+MCmB1cESAPF%?VQMHxyr9~W zLTMk*Ab}}B5~$G)6i6>bsBS0onZ&UBRiUzUrYI7*!?{um|4x86mvX2ZGOQ@Q zNMd_~W^QGq;u&5=6k#T`?_%S6AMIJ8#>zIW%rh6^{N7 DKy2tJ literal 0 HcmV?d00001 diff --git a/dependencies/__pycache__/segwit_addr.cpython-38.pyc b/dependencies/__pycache__/segwit_addr.cpython-38.pyc new file mode 100755 index 0000000000000000000000000000000000000000..b568bb34e619e33a2b47c7cce17cd7c309070525 GIT binary patch literal 4683 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 b5;lgO*QQKZnU>9G&1^241wA!3lRf!A (3, 0): + output = bytes() + for code in code_list: + output += bytes([code]) + else: + output = '' + for code in code_list: + output += chr(code) + return output + + @staticmethod + def _address_type(address_type, version): + for mapping in Address.VERSION_MAP[address_type]: + if mapping[0] == version or mapping[1] == version: + return mapping + raise InvalidAddress('Could not determine address version') + + @staticmethod + def from_string(address_string): + try: + address_string = str(address_string) + except Exception: + raise InvalidAddress('Expected string as input') + if ':' not in address_string: + return Address._legacy_string(address_string) + else: + return Address._cash_string(address_string) + + @staticmethod + def _legacy_string(address_string): + try: + decoded = bytearray(b58decode_check(address_string)) + except ValueError: + raise InvalidAddress('Could not decode legacy address') + version = Address._address_type('legacy', decoded[0])[0] + payload = list() + for letter in decoded[1:]: + payload.append(letter) + return Address(version, payload) + + @staticmethod + def _cash_string(address_string): + if address_string.upper() != address_string and address_string.lower() != address_string: + raise InvalidAddress('Cash address contains uppercase and lowercase characters') + address_string = address_string.lower() + colon_count = address_string.count(':') + if colon_count == 0: + address_string = Address.MAINNET_PREFIX + ':' + address_string + elif colon_count > 1: + raise InvalidAddress('Cash address contains more than one colon character') + prefix, base32string = address_string.split(':') + decoded = b32decode(base32string) + if not verify_checksum(prefix, decoded): + raise InvalidAddress('Bad cash address checksum') + converted = convertbits(decoded, 5, 8) + version = Address._address_type('cash', converted[0])[0] + if prefix == Address.TESTNET_PREFIX: + version += '-TESTNET' + payload = converted[1:-6] + return Address(version, payload, prefix) + + +def to_cash_address(address): + return Address.from_string(address).cash_address() + + +def to_legacy_address(address): + return Address.from_string(address).legacy_address() + + +def is_valid(address): + try: + Address.from_string(address) + return True + except InvalidAddress: + return False diff --git a/dependencies/crypto.py b/dependencies/crypto.py new file mode 100755 index 0000000..2e32f9e --- /dev/null +++ b/dependencies/crypto.py @@ -0,0 +1,70 @@ +CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' + + +def polymod(values): + chk = 1 + generator = [ + (0x01, 0x98f2bc8e61), + (0x02, 0x79b76d99e2), + (0x04, 0xf33e5fb3c4), + (0x08, 0xae2eabe2a8), + (0x10, 0x1e4f43e470)] + for value in values: + top = chk >> 35 + chk = ((chk & 0x07ffffffff) << 5) ^ value + for i in generator: + if top & i[0] != 0: + chk ^= i[1] + return chk ^ 1 + + +def prefix_expand(prefix): + return [ord(x) & 0x1f for x in prefix] + [0] + + +def calculate_checksum(prefix, payload): + poly = polymod(prefix_expand(prefix) + payload + [0, 0, 0, 0, 0, 0, 0, 0]) + out = list() + for i in range(8): + out.append((poly >> 5 * (7 - i)) & 0x1f) + return out + + +def verify_checksum(prefix, payload): + return polymod(prefix_expand(prefix) + payload) == 0 + + +def b32decode(inputs): + out = list() + for letter in inputs: + out.append(CHARSET.find(letter)) + return out + + +def b32encode(inputs): + out = '' + for char_code in inputs: + out += CHARSET[char_code] + return out + + +def convertbits(data, frombits, tobits, pad=True): + acc = 0 + bits = 0 + ret = [] + maxv = (1 << tobits) - 1 + max_acc = (1 << (frombits + tobits - 1)) - 1 + for value in data: + if value < 0 or (value >> frombits): + return None + acc = ((acc << frombits) | value) & max_acc + bits += frombits + while bits >= tobits: + bits -= tobits + ret.append((acc >> bits) & maxv) + if pad: + if bits: + ret.append((acc << (tobits - bits)) & maxv) + elif bits >= frombits or ((acc << (tobits - bits)) & maxv): + return None + return ret diff --git a/dependencies/moneropy.py b/dependencies/moneropy.py new file mode 100755 index 0000000..a05aaed --- /dev/null +++ b/dependencies/moneropy.py @@ -0,0 +1,185 @@ +# MoneroPy - A python toolbox for Monero +# Copyright (C) 2016 The MoneroPy Developers. +# +# MoneroPy is released under the BSD 3-Clause license. Use and redistribution of +# this software is subject to the license terms in the LICENSE file found in the +# top-level directory of this distribution. +# +# Modified by emesik and rooterkyberian: +# + optimized +# + proper exceptions instead of returning errors as results + +__alphabet = [ + ord(s) for s in "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" +] +__b58base = 58 +__UINT64MAX = 2 ** 64 +__encodedBlockSizes = [0, 2, 3, 5, 6, 7, 9, 10, 11] +__fullBlockSize = 8 +__fullEncodedBlockSize = 11 + + +def _hexToBin(hex_): + if len(hex_) % 2 != 0: + raise ValueError("Hex string has invalid length: %d" % len(hex_)) + return [int(hex_[i : i + 2], 16) for i in range(0, len(hex_), 2)] + + +def _binToHex(bin_): + return "".join("%02x" % int(b) for b in bin_) + + +def _uint8be_to_64(data): + if not (1 <= len(data) <= 8): + raise ValueError("Invalid input length: %d" % len(data)) + + res = 0 + for b in data: + res = res << 8 | b + return res + + +def _uint64_to_8be(num, size): + if size < 1 or size > 8: + raise ValueError("Invalid input length: %d" % size) + res = [0] * size + + twopow8 = 2 ** 8 + for i in range(size - 1, -1, -1): + res[i] = num % twopow8 + num = num // twopow8 + + return res + + +def encode_block(data, buf, index): + l_data = len(data) + + if l_data < 1 or l_data > __fullEncodedBlockSize: + raise ValueError("Invalid block length: %d" % l_data) + + num = _uint8be_to_64(data) + i = __encodedBlockSizes[l_data] - 1 + + while num > 0: + remainder = num % __b58base + num = num // __b58base + buf[index + i] = __alphabet[remainder] + i -= 1 + + return buf + + +def encode(hex): + """Encode hexadecimal string as base58 (ex: encoding a Monero address).""" + data = _hexToBin(hex) + l_data = len(data) + + if l_data == 0: + return "" + + full_block_count = l_data // __fullBlockSize + last_block_size = l_data % __fullBlockSize + res_size = ( + full_block_count * __fullEncodedBlockSize + __encodedBlockSizes[last_block_size] + ) + + res = bytearray([__alphabet[0]] * res_size) + + for i in range(full_block_count): + res = encode_block( + data[(i * __fullBlockSize) : (i * __fullBlockSize + __fullBlockSize)], + res, + i * __fullEncodedBlockSize, + ) + + if last_block_size > 0: + res = encode_block( + data[ + (full_block_count * __fullBlockSize) : ( + full_block_count * __fullBlockSize + last_block_size + ) + ], + res, + full_block_count * __fullEncodedBlockSize, + ) + + return bytes(res).decode("ascii") + + +def decode_block(data, buf, index): + l_data = len(data) + + if l_data < 1 or l_data > __fullEncodedBlockSize: + raise ValueError("Invalid block length: %d" % l_data) + + res_size = __encodedBlockSizes.index(l_data) + if res_size <= 0: + raise ValueError("Invalid block size: %d" % res_size) + + res_num = 0 + order = 1 + for i in range(l_data - 1, -1, -1): + digit = __alphabet.index(data[i]) + if digit < 0: + raise ValueError("Invalid symbol: %s" % data[i]) + + product = order * digit + res_num + if product > __UINT64MAX: + raise ValueError( + "Overflow: %d * %d + %d = %d" % (order, digit, res_num, product) + ) + + res_num = product + order = order * __b58base + + if res_size < __fullBlockSize and 2 ** (8 * res_size) <= res_num: + raise ValueError("Overflow: %d doesn't fit in %d bit(s)" % (res_num, res_size)) + + tmp_buf = _uint64_to_8be(res_num, res_size) + buf[index : index + len(tmp_buf)] = tmp_buf + + return buf + + +def decode(enc): + """Decode a base58 string (ex: a Monero address) into hexidecimal form.""" + enc = bytearray(enc, encoding="ascii") + l_enc = len(enc) + + if l_enc == 0: + return "" + + full_block_count = l_enc // __fullEncodedBlockSize + last_block_size = l_enc % __fullEncodedBlockSize + try: + last_block_decoded_size = __encodedBlockSizes.index(last_block_size) + except ValueError: + raise ValueError("Invalid encoded length: %d" % l_enc) + + data_size = full_block_count * __fullBlockSize + last_block_decoded_size + + data = bytearray(data_size) + for i in range(full_block_count): + data = decode_block( + enc[ + (i * __fullEncodedBlockSize) : ( + i * __fullEncodedBlockSize + __fullEncodedBlockSize + ) + ], + data, + i * __fullBlockSize, + ) + + if last_block_size > 0: + data = decode_block( + enc[ + (full_block_count * __fullEncodedBlockSize) : ( + full_block_count * __fullEncodedBlockSize + last_block_size + ) + ], + data, + full_block_count * __fullBlockSize, + ) + + return _binToHex(data) diff --git a/dependencies/segwit_addr.py b/dependencies/segwit_addr.py new file mode 100755 index 0000000..84c7241 --- /dev/null +++ b/dependencies/segwit_addr.py @@ -0,0 +1,139 @@ + +# Copyright (c) 2017, 2020 Pieter Wuille +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +"""Reference implementation for Bech32/Bech32m and segwit addresses.""" + + +from enum import Enum + +class Encoding(Enum): + """Enumeration type to list the various supported encodings.""" + BECH32 = 1 + BECH32M = 2 + +CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +BECH32M_CONST = 0x2bc830a3 + +def bech32_polymod(values): + """Internal function that computes the Bech32 checksum.""" + generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] + chk = 1 + for value in values: + top = chk >> 25 + chk = (chk & 0x1ffffff) << 5 ^ value + for i in range(5): + chk ^= generator[i] if ((top >> i) & 1) else 0 + return chk + + +def bech32_hrp_expand(hrp): + """Expand the HRP into values for checksum computation.""" + return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] + + +def bech32_verify_checksum(hrp, data): + """Verify a checksum given HRP and converted data characters.""" + const = bech32_polymod(bech32_hrp_expand(hrp) + data) + if const == 1: + return Encoding.BECH32 + if const == BECH32M_CONST: + return Encoding.BECH32M + return None + +def bech32_create_checksum(hrp, data, spec): + """Compute the checksum values given HRP and data.""" + values = bech32_hrp_expand(hrp) + data + const = BECH32M_CONST if spec == Encoding.BECH32M else 1 + polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const + return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] + + +def bech32_encode(hrp, data, spec): + """Compute a Bech32 string given HRP and data values.""" + combined = data + bech32_create_checksum(hrp, data, spec) + return hrp + '1' + ''.join([CHARSET[d] for d in combined]) + +def bech32_decode(bech): + """Validate a Bech32/Bech32m string, and determine HRP and data.""" + if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or + (bech.lower() != bech and bech.upper() != bech)): + return (None, None, None) + bech = bech.lower() + pos = bech.rfind('1') + if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: + return (None, None, None) + if not all(x in CHARSET for x in bech[pos+1:]): + return (None, None, None) + hrp = bech[:pos] + data = [CHARSET.find(x) for x in bech[pos+1:]] + spec = bech32_verify_checksum(hrp, data) + if spec is None: + return (None, None, None) + return (hrp, data[:-6], spec) + +def convertbits(data, frombits, tobits, pad=True): + """General power-of-2 base conversion.""" + acc = 0 + bits = 0 + ret = [] + maxv = (1 << tobits) - 1 + max_acc = (1 << (frombits + tobits - 1)) - 1 + for value in data: + if value < 0 or (value >> frombits): + return None + acc = ((acc << frombits) | value) & max_acc + bits += frombits + while bits >= tobits: + bits -= tobits + ret.append((acc >> bits) & maxv) + if pad: + if bits: + ret.append((acc << (tobits - bits)) & maxv) + elif bits >= frombits or ((acc << (tobits - bits)) & maxv): + return None + return ret + + +def decode(hrp, addr): + """Decode a segwit address.""" + hrpgot, data, spec = bech32_decode(addr) + if hrpgot != hrp: + return (None, None) + decoded = convertbits(data[1:], 5, 8, False) + if decoded is None or len(decoded) < 2 or len(decoded) > 40: + return (None, None) + if data[0] > 16: + return (None, None) + if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32: + return (None, None) + if data[0] == 0 and spec != Encoding.BECH32 or data[0] != 0 and spec != Encoding.BECH32M: + return (None, None) + return (data[0], decoded) + + +def encode(hrp, witver, witprog): + """Encode a segwit address.""" + spec = Encoding.BECH32 if witver == 0 else Encoding.BECH32M + ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5), spec) + if decode(hrp, ret) == (None, None): + return None + return ret + diff --git a/functions.py b/functions.py new file mode 100755 index 0000000..dc75481 --- /dev/null +++ b/functions.py @@ -0,0 +1,58 @@ +import dependencies.segwit_addr as segwit_addr +import dependencies.bchconvert as bchconvert +import dependencies.moneropy as moneropy +import base58, hashlib, binascii +import socket + +def decodeBase58(address): + decoded = base58.b58decode(address).hex() + prefixAndHash = decoded[:len(decoded)-8] + checksum = decoded[len(decoded)-8:] + hash = prefixAndHash + for _ in range(1,3): + hash = hashlib.sha256(binascii.unhexlify(hash)).hexdigest() + if(checksum == hash[:8]): + return True + return False + +def decodeMonero(address): + # decode monero address + if len(address) == 95 or len(address) == 106: + # Decode the address from Base58 + decoded = moneropy.decode(address) + + # Verify address type byte + if decoded[0:2] not in ["12", "2a", "13"]: + return False + + # Verify checksum + # later + return True + return False + +def checksumCheck(method, address): + match method.lower(): + case 'btc': + return decodeBase58(address) if address[0] == '1' or address[0] == '3' else True if address[0:3] == 'bc1' and segwit_addr.decode("bc", address)[0] != None else False + case 'ltc': + return decodeBase58(address) if address[0] == '3' or address[0] == 'M' or address[0] == 'L' else True if address[0:4] == 'ltc1' and segwit_addr.decode("ltc", address)[0] != None else False + case 'bch': + return bchconvert.is_valid(address) if address[0] == '1' else True if bchconvert.is_valid('bitcoincash:'+address) == True else False + case 'zec': + return decodeBase58(address) if address[0] == 't' or address[0] == 'z' else False + case 'xmr': + #needs new function to check if address is valid, a decoder maybe + return decodeMonero(address) + case _: + return False + +def validDns(d): + try: + a = socket.gethostbyname(d) + except: + return False + # ip validation + if a.split('.')[0] in ['127', '0'] or '.'.join([a.split('.')[0], a.split('.')[1]]) == '192.168' or a in ['1.1.1.1','2.2.2.2', '3.3.3.3']: + return False + else: + return True \ No newline at end of file diff --git a/main.py b/main.py new file mode 100755 index 0000000..3d4427f --- /dev/null +++ b/main.py @@ -0,0 +1,139 @@ +from typing import Optional, Union +from urllib.parse import urlparse +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse +import time, socket +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.pool import QueuePool +import uvicorn + +#local +from rpcs import RPCHost, RPCXMR +from models import Return +from meta import Queue +from functions import checksumCheck, validDns +import config + +class ErrorException(Exception): + def __init__(self, code: str, status: str, status_message: str): + self.status = status + self.code = code + self.status_message = status_message + +app = FastAPI() + +@app.get("/") +def root(): + return + +@app.exception_handler(ErrorException) +def unicorn_exception_handler(request: Request, exc: ErrorException): + return JSONResponse( + status_code=exc.code, + content={ + "status": f"{exc.status}", + "message": f"{exc.status_message}" + }, + ) + +@app.get("/api/receive") +def receive(method: str, address: str, callback: Union[str, None] = None): + if not method: + raise ErrorException(code=422,status="error",status_message='Empty method used') + if not address: + raise ErrorException(code=422,status="error",status_message='Empty destination address') + if method.lower() not in ['btc', 'btct', 'ltc', 'doge', 'zec', 'bch', 'xmr']: + raise ErrorException(code=422,status="error",status_message='Invalid method used') + if checksumCheck(method.lower(), address) == False: + raise ErrorException(code=422,status="error",status_message='Invalid Destination Address') + + if callback: + try: + data = urlparse(callback) + #scheme validation + if data.scheme == 'http' or data.scheme == 'https': + #domain validation + if validDns(data.netloc) != True: + raise ErrorException(code=422,status="error",status_message='Invalid callback: domain name does not resolve') + else: + raise ErrorException(code=422,status="error",status_message='Invalid callback: wrong url scheme, we accept http or https only') + except: + callback = 'None' + callback_req_n = 0 + else: + callback = 'None' + callback_req_n = 1 + + ## RPC connection to Demons + match method.upper(): + case 'BTC' | 'LTC' | 'ZEC' | 'BCH' | 'BTCT' | 'DOGE': + rpc = RPCHost("http://%s:%s@%s:%s" % (config.rpcs[method.upper()]['user'], config.rpcs[method.upper()]['pass'], config.rpcs[method.upper()]['host'], config.rpcs[method.upper()]['port'])) + case 'XMR': + rpc = RPCXMR(config.rpcs[method.upper()]['host'], config.rpcs[method.upper()]['user'], config.rpcs[method.upper()]['pass']) + case _: + raise ErrorException(code=422,status="error",status_message='RPC undergoing maintenance') + + ## checking if wallet is loaded + # wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,True,True,False) + + try: + match method.upper(): + case 'XMR': + wallet = rpc.call('create_address',{"account_index": 0}) + wallet = wallet['address'] + case 'LTC' | 'ZEC' | 'DOGE': + #wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,False,True) + wallet = rpc.call('getnewaddress') + case 'BTC' | 'BTCT': + #wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,True,True,False) + wallet = rpc.call('getnewaddress','', 'p2sh-segwit') + case 'BCH': + wallet = rpc.call('getnewaddress') + wallet = wallet.replace('bitcoincash:', '') + case _: + ## notify admin about the error + raise ErrorException(code=422, status="error", status_message='RPC unavailable') + except Exception as error: + ## notify admin about the error + # Failed to connect for remote procedure call. + raise ErrorException(code=422, status="error", status_message=error) + + + ## SQL Connection with SQLAlchemy + engine = create_engine( + "mysql+pymysql://%s:%s@%s:%s/dev" % (config.DB['user'], config.DB['pass'], config.DB['host'], config.DB['port']), + poolclass=QueuePool, + #echo=True, #debug sqlalchemy + pool_size=4, + max_overflow=0, + pool_timeout=15, # Wait 15s for a connection + ) + Session = sessionmaker(bind = engine) + session = Session() + + if wallet: + try: + q = Queue(txhash = 'None', time = int(time.time()), account = method.upper(), fee = config.fee['REGULAR'][method.upper()], ready = 0, confirmations =0, callbackurl = callback, generated_address = wallet, destination = address, balance_received = '0.00000000', callback_req = callback_req_n, ip = socket.gethostbyname(socket.gethostname()) , hostname = socket.gethostname(), merchantId = 'None', dateTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + session.add(q) + session.commit() + session.close() + except Exception as error: + ## notify admin about the error + raise ErrorException(code=422,status="error",status_message='Invalid response from dbServer') + else: + ## notify admin about the error + raise ErrorException(code=422,status="error",status_message='Invalid response from rpcServer') + + return Return( + address = wallet, + destination = address, + callback_url = callback, + fee = config.fee['REGULAR'][method.upper()], + status = 'success' + ) + +# Run +if __name__ == '__main__': + uvicorn.run('main:app', host='0.0.0.0') + #workers=4 (doesn't work with reload) \ No newline at end of file diff --git a/meta.py b/meta.py new file mode 100644 index 0000000..26129ae --- /dev/null +++ b/meta.py @@ -0,0 +1,24 @@ +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer, String + +Base = declarative_base() + +class Queue(Base): + __tablename__ = 'queue' + + id = Column(Integer, primary_key = True) + txhash = Column(String) + time = Column(String) + account = Column(String) + fee = Column(String) + ready = Column(String) + confirmations = Column(String) + callbackurl = Column(String) + generated_address = Column(String) + destination = Column(String) + balance_received = Column(String) + callback_req = Column(String) + ip = Column(String) + hostname = Column(String) + merchantId = Column(String) + dateTime = Column(String) \ No newline at end of file diff --git a/models.py b/models.py new file mode 100755 index 0000000..ffe52ab --- /dev/null +++ b/models.py @@ -0,0 +1,15 @@ +from decimal import Decimal +from typing import Optional +from pydantic import BaseModel + +class Receive(BaseModel): + method: str + address: str + callback: Optional[str] + +class Return(BaseModel): + address: str + destination: str + callback_url: Optional[str] + fee: Decimal + status: str diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1024b0d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,18 @@ +anyio==3.6.2 +base58==2.1.1 +certifi==2022.12.7 +charset-normalizer==3.0.1 +click==8.1.3 +fastapi==0.92.0 +greenlet==2.0.1 +h11==0.14.0 +idna==3.4 +pydantic==1.10.5 +PyMySQL==1.0.2 +requests==2.28.2 +sniffio==1.3.0 +SQLAlchemy==2.0.4 +starlette==0.25.0 +typing_extensions==4.5.0 +urllib3==1.26.14 +uvicorn==0.20.0 diff --git a/rpcs.py b/rpcs.py new file mode 100755 index 0000000..3210dd2 --- /dev/null +++ b/rpcs.py @@ -0,0 +1,66 @@ +import time, json, requests +from requests.auth import HTTPDigestAuth + +class RPCHost(object): + def __init__(self, url): + self._session = requests.Session() + self._url = url + self._headers = {'content-type': 'application/json'} + def call(self, rpcMethod, *params): + payload = json.dumps({"method": rpcMethod, "params": list(params), "jsonrpc": "2.0"}) + tries = 3 + hadConnectionFailures = False + while True: + try: + response = self._session.post(self._url, headers=self._headers, data=payload, timeout=15) + except requests.exceptions.ConnectionError: + tries -= 1 + if tries == 0: + raise Exception('Failed to connect for remote procedure call.') + hadFailedConnections = True + print("Couldn't connect for remote procedure call, will sleep for two seconds and then try again ({} more tries)".format(tries)) + #time.sleep(2) + else: + if hadConnectionFailures: + print('Connected for remote procedure call after retry.') + break + if not response.status_code in (200, 500): + raise Exception('RPC connection failure: ' + str(response.status_code) + ' ' + response.reason) + responseJSON = response.json() + if 'error' in responseJSON and responseJSON['error'] != None: + raise Exception('Error in RPC call: ' + str(responseJSON['error'])) + return responseJSON['result'] + +# class +class RPCXMR(object): + def __init__(self, url, user, password): + self._session = requests.Session() + self._url = url + self._user = user + self._pass = password + self._headers = {} + + def call(self, rpcMethod, params): + payload = json.dumps({"method": rpcMethod, "params": params, "jsonrpc": "2.0"}) + tries = 3 + hadConnectionFailures = False + while True: + try: + response = self._session.post(self._url, headers=self._headers, data=payload, auth=HTTPDigestAuth(self._user, self._pass), timeout=15) + except requests.exceptions.ConnectionError: + tries -= 1 + if tries == 0: + raise Exception('Failed to connect for remote procedure call.') + hadFailedConnections = True + print("Couldn't connect for remote procedure call, will sleep for two seconds and then try again ({} more tries)".format(tries)) + #time.sleep(2) + else: + if hadConnectionFailures: + print('Connected for remote procedure call after retry.') + break + if not response.status_code in (200, 500): + raise Exception('RPC connection failure: ' + str(response.status_code) + ' ' + response.reason) + responseJSON = response.json() + if 'error' in responseJSON and responseJSON['error'] != None: + raise Exception('Error in RPC call: ' + str(responseJSON['error'])) + return responseJSON['result'] \ No newline at end of file diff --git a/scratch_file b/scratch_file new file mode 100644 index 0000000..b315c66 --- /dev/null +++ b/scratch_file @@ -0,0 +1,183 @@ +''' + +def checksumCheck(method, address): + if method == 'btc': + if address[0] == '1' or address[0] == '3': + if decodeBase58(address): + return True + return False + elif address[0:3] == 'bc1': + witver = segwit_addr.decode("bc", address) + if witver[0] == None: + return False + return True + else: + return False + elif method == 'ltc': + if address[0] == '3' or address[0] == 'M' or address[0] == 'L': + if decodeBase58(address): + return True + return False + elif address[0:4] == 'ltc1': + witver = segwit_addr.decode("ltc", address) + if witver[0] != None: + return True + return False + else: + return False + elif method == 'bch': + if address[0] == '1': + if bchconvert.is_valid(address) == True: + return True + return False + elif bchconvert.is_valid('bitcoincash:'+address) == True: + return True + return False + elif method == 'zec': + if address[0] == 't' or address[0] == 'z': + if decodeBase58(address): + return True + return False + else: + return True + elif method == 'xmr': + length = len(address) + if length == 95: + checksum = moneropy.decode(address) + start = checksum[0:2].lower() + if start == '12' or start == '2a': + return True + return False + elif length == 106: + checksum = moneropy.decode(address) + start = checksum[0:2].lower() + if start == '13': + return True + return False + else: + return False + + else: + return False +''' + +''' + k = sha3.keccak_256() + print("First 65: " + str(address_type[:-65])) + print(hash64) + k.update(hash64) + a = k.hexdigest() + print("sha3 digest: " + a) + print("base58 decoded: " + address_type) + first4 = a[:-4] + last = address_type[-4:] + ''' + return start + + + + + ''' + valid = re.compile(r"^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,39}$") + if valid.match(address) is None: + return False + else: + return True + + + else: + return "END" + ''' + + + + + + + + + +def validDns(d): + b = False + try: + a = socket.gethostbyname(d) + b = True + except: + return False + # ip validation + if b == True: + if a.split('.')[0] in ['127', '0']: + return False + if '.'.join([a.split('.')[0], a.split('.')[1]]) == '192.168': + return False + if a in ['1.1.1.1','2.2.2.2', '3.3.3.3']: + return False + return True + + +import base58 +import hashlib + +# Modified Base58 alphabet used in Monero +MONERO_BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + +def encode_monero_address(address, version): + # Compute checksum + hash1 = hashlib.sha256(bytes.fromhex(version + address)).digest() + hash2 = hashlib.sha256(hash1).digest() + checksum = hash2[:4] + + # Concatenate version, address, and checksum + data = bytes.fromhex(version + address) + checksum + + # Encode using modified Base58 alphabet + encoded = base58.b58encode(data, alphabet=MONERO_BASE58_ALPHABET) + + return encoded.decode() + +def decode_monero_address(encoded): + # Decode using modified Base58 alphabet + data = base58.b58decode(encoded, alphabet=MONERO_BASE58_ALPHABET) + + # Extract version, address, and checksum + version = data[:2].hex() + address = data[2:-4].hex() + checksum = data[-4:] + + # Verify checksum + hash1 = hashlib.sha256(bytes.fromhex(version + address)).digest() + hash2 = hashlib.sha256(hash1).digest() + if checksum != hash2[:4]: + raise ValueError('Invalid checksum') + + return version, address + + +def decode_monero_address(encoded): + from Crypto.Hash import keccak + import binascii + # Decode using modified Base58 alphabet + print(encoded) + data = moneropy.decode(encoded) + print(data) + + # Extract version, address, and checksum + version = data[:2].encode() + address1 = data[2:66].encode() + address2 = data[66:-8].encode() + checksum = data[-8:] + + print(str(version + address1 + address2)) + print(hex(version)) + + + # Verify checksum + #keccak256 = keccak.new(digest_bits=256) + #keccak256.update(version + address1 + address2) + #print(keccak256.hexdigest()) + + + #print("Keccak256:", binascii.hexlify(keccak256)) + + #print(binascii.hexlify(keccak256), checksum) + return False \ No newline at end of file diff --git a/sql_app/database.py b/sql_app/database.py new file mode 100644 index 0000000..0093632 --- /dev/null +++ b/sql_app/database.py @@ -0,0 +1,15 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +import config + +# SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" +# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db" + +# create_engine("mysql+pymysql://%:%@%:%/dev", connect_args={"check_same_thread": False}) % (config.DB('user'), config.DB('pass'), config.DB('host'), config.DB('port')) + +engine = create_engine("mysql+pymysql://%:%@%:%/dev") % (config.DB('user'), config.DB('pass'), config.DB('host'), config.DB('port')) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() diff --git a/sql_app/models.py b/sql_app/models.py new file mode 100644 index 0000000..16420ea --- /dev/null +++ b/sql_app/models.py @@ -0,0 +1,25 @@ +from decimal import Decimal +from sqlalchemy import Boolean, Column, ForeignKey, Integer, String +from sqlalchemy.orm import relationship + +from .database import Base + + +class Queue(Base): + __tablename__ = "queue" + + id = Column(Integer, primary_key=True, index=True) + txhash = Column(String, unique=True, index=True) + accountId = Column(Integer) + method = Column(String) + fee = Column(Decimal) + status = Column(Integer) + confirmations = Column(Integer) + callback_url = Column(String) + local_address = Column(String) + remote_address = Column(String) + balance = Column(Decimal) + callback_requirement = Column(Integer) + unixtime = Column(Integer) + date = Column(String) + ip = Column(String) diff --git a/sql_app/schemas.py b/sql_app/schemas.py new file mode 100644 index 0000000..e69de29 diff --git a/sub.py b/sub.py new file mode 100644 index 0000000..2a57360 --- /dev/null +++ b/sub.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" + ZMQ example using python3's asyncio + + Litecoind should be started with the command line arguments: + litecoind -testnet -daemon \ + -zmqpubrawtx=tcp://127.0.0.1:28332 \ + -zmqpubrawblock=tcp://127.0.0.1:28332 \ + -zmqpubhashtx=tcp://127.0.0.1:28332 \ + -zmqpubhashblock=tcp://127.0.0.1:28332 \ + -zmqpubsequence=tcp://127.0.0.1:28332 + + We use the asyncio library here. `self.handle()` installs itself as a + future at the end of the function. Since it never returns with the event + loop having an empty stack of futures, this creates an infinite loop. An + alternative is to wrap the contents of `handle` inside `while True`. + + A blocking example using python 2.7 can be obtained from the git history: + https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py +""" + +import binascii +import asyncio +import zmq +import zmq.asyncio +import signal +import struct +import sys +import time, requests, json + +if (sys.version_info.major, sys.version_info.minor) < (3, 5): + print("This example only works with Python 3.5 and greater") + sys.exit(1) + +class RPCHost(object): + def __init__(self, url): + self._session = requests.Session() + self._url = url + self._headers = {'content-type': 'application/json'} + def call(self, rpcMethod, *params): + payload = json.dumps({"method": rpcMethod, "params": list(params), "jsonrpc": "2.0"}) + tries = 5 + hadConnectionFailures = False + while True: + try: + response = self._session.post(self._url, headers=self._headers, data=payload) + except requests.exceptions.ConnectionError: + tries -= 1 + if tries == 0: + raise Exception('Failed to connect for remote procedure call.') + hadFailedConnections = True + print("Couldn't connect for remote procedure call, will sleep for five seconds and then try again ({} more tries)".format(tries)) + time.sleep(10) + else: + if hadConnectionFailures: + print('Connected for remote procedure call after retry.') + break + if not response.status_code in (200, 500): + raise Exception('RPC connection failure: ' + str(response.status_code) + ' ' + response.reason) + responseJSON = response.json() + if 'error' in responseJSON and responseJSON['error'] != None: + raise Exception('Error in RPC call: ' + str(responseJSON['error'])) + return responseJSON['result'] + +ZMQ_PORT = 28442 +SERVER_IP = '172.16.0.10' +SERVER_PORT = 8442 +SERVER_USER = 'litecoinrpc' +SERVER_PASS = 'uhalalala' + +serverURL = "http://%s:%s@%s:%s" % (SERVER_USER, SERVER_PASS, SERVER_IP, SERVER_PORT) +rpc = RPCHost(serverURL) + +class ZMQHandler(): + def __init__(self): + self.loop = asyncio.get_event_loop() + self.zmqContext = zmq.asyncio.Context() + + self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) + self.zmqSubSocket.setsockopt(zmq.RCVHWM, 0) + #self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "") + #self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx") + #self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock") + #self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx") + #self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "sequence") + self.zmqSubSocket.connect("tcp://%s:%i" % (SERVER_IP, ZMQ_PORT)) + + async def handle(self) : + topic, body, seq = await self.zmqSubSocket.recv_multipart() + sequence = "Unknown" + if len(seq) == 4: + sequence = str(struct.unpack('