From 28f1bb11ec1b6cbb639244679d4cf3fb8e599e91 Mon Sep 17 00:00:00 2001 From: MilaSargawiNode <129453771+MilaSargawiNode@users.noreply.github.com> Date: Fri, 31 Mar 2023 04:25:25 +0700 Subject: [PATCH] milasargawi task4 --- milasargawi/api/__init__.py | 3 + .../api/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 133 bytes .../api/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 145 bytes .../api/__pycache__/cline.cpython-36.pyc | Bin 0 -> 52217 bytes .../api/__pycache__/cline.cpython-38.pyc | Bin 0 -> 11979 bytes .../api/__pycache__/keys.cpython-38.pyc | Bin 0 -> 6967 bytes .../api/__pycache__/types.cpython-38.pyc | Bin 0 -> 71019 bytes .../api/__pycache__/utils.cpython-38.pyc | Bin 0 -> 2217 bytes milasargawi/api/cline.py | 380 +++ milasargawi/api/keys.py | 239 ++ milasargawi/api/types.py | 2764 +++++++++++++++++ milasargawi/api/utils.py | 88 + milasargawi/env-example | 2 + milasargawi/inerytransfer.py | 33 + milasargawi/readme.md | 35 + milasargawi/requirements.txt | 5 + 16 files changed, 3549 insertions(+) create mode 100644 milasargawi/api/__init__.py create mode 100644 milasargawi/api/__pycache__/__init__.cpython-36.pyc create mode 100644 milasargawi/api/__pycache__/__init__.cpython-38.pyc create mode 100644 milasargawi/api/__pycache__/cline.cpython-36.pyc create mode 100644 milasargawi/api/__pycache__/cline.cpython-38.pyc create mode 100644 milasargawi/api/__pycache__/keys.cpython-38.pyc create mode 100644 milasargawi/api/__pycache__/types.cpython-38.pyc create mode 100644 milasargawi/api/__pycache__/utils.cpython-38.pyc create mode 100644 milasargawi/api/cline.py create mode 100644 milasargawi/api/keys.py create mode 100644 milasargawi/api/types.py create mode 100644 milasargawi/api/utils.py create mode 100644 milasargawi/env-example create mode 100644 milasargawi/inerytransfer.py create mode 100644 milasargawi/readme.md create mode 100644 milasargawi/requirements.txt diff --git a/milasargawi/api/__init__.py b/milasargawi/api/__init__.py new file mode 100644 index 000000000..22fe21257 --- /dev/null +++ b/milasargawi/api/__init__.py @@ -0,0 +1,3 @@ +from urllib3.exceptions import InsecureRequestWarning +import warnings +warnings.simplefilter('ignore', InsecureRequestWarning) \ No newline at end of file diff --git a/milasargawi/api/__pycache__/__init__.cpython-36.pyc b/milasargawi/api/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cac193ba7e3a0de5b9b4d2268805f25818e6fac GIT binary patch literal 133 zcmXr!<>guvx+RGL2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CUq<>F`MIh3DW%1U zdHOD?#n~nK1^StJsYR6qmAXZl1qG=o`iTXZ`tk9Zd6^~g@p=W7w>WHa^HWN5Qtd!y I6$3E?0NB|dw*UYD literal 0 HcmV?d00001 diff --git a/milasargawi/api/__pycache__/__init__.cpython-38.pyc b/milasargawi/api/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77249d4095c132114d2a135e8927174dbd373d3b GIT binary patch literal 145 zcmWIL<>g`k0)vdb$sqbMh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6vEzbHSyMBg(n zwW!j?Nk0=p>y{bmC+DOl=Eaw#78Pga=jkUFWa`JqXXa&=#K-FuRNmsS$<0qG%}KQb JnfDop82~i#Ald)` literal 0 HcmV?d00001 diff --git a/milasargawi/api/__pycache__/cline.cpython-36.pyc b/milasargawi/api/__pycache__/cline.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ef0907b1bc3770b3919b83c455f30c998451e1a GIT binary patch literal 52217 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 PoBCfC=^K1mkPplAwc2QW{Gh0qEJ?A#t&1u*(Gp zu0)hoC6^`TQ;srS*^Mi%V)7sIE%}mvFqLolkYZJSK*GpUp10?~09>k^5GXWy`h5HC z=e@e;^29_z!sq%I|J1m8Qj-3i9$xX?M{$)$Xv(i*rs-?{+f|c=avb}7I zO`}Ji?PD`+7P$gbK*#>DaBizzYq^cfycsGROVtKVnS3a(;CB{3?+}te?HX%RAlXtN zBb5UMslud7(p|YauZD)*s5RD|(6s9{&*@=I)825n=XTojTBvzWb2U_{I2V_Oy6A9M z;$;kf|HvZmbo|9P+7913cV^Lz{$Jc!UTid-T00qQvDS4_g6f6t7N)S>w(Hw=k;pWV zNOD0oIssDV$8ATvrPsjz6< zYmQ&@eQw)RDDcGaa(~~*)M=B3j5f)K^7Iq46RU}jVqP)9U0KXKK4Z?dnbWlGS#(Hd zn;Dr+R6npzJ(-F2(Z@=!VF#~a|E{Tlye97l%)e9t2?hJeiIcoU$pn&ljT3p?q$E#C zj*=NlXxoPT;L~{AhhIWjDNEVIS5M3aCCU2dEL1-!EvMI`0E{ZFf++?W|F9O zWG33-boC2(U@~?&UjL3V03Wv19qF9(@zg*Ob-*>1-#8GEuqxGl?$+VK;;p3tKy0jb zc&p}Tn6V#2f@cI0D+h4fp3g(IQ@=LGoUqW~PR)00w0RtjJ>sV%Pst^@Ecf?j7BOsh z?@2Ui5cSE2SVim?sQD2xKCOf#Q4KUEGv!Ntpa=T4vIB78A1lKe)anJIy<6k8mKSQ* zyiPmJ`EJYU^!(6(Fp>(=LX$f;dXDFNp$g1~Q@rMSj*S&#O*Oyg@h33hyb%FYfP@wz zN;y#)%6xp$ISfQAo1rC#!VVRcF~SLv_`_3SZ5WP>^cKotkf77{Ze2= zYrQJ9=VYu|rk3iq#?);cb;gdg1Bw1r{!nTwA4pLNIHG|gI#0Fix$&SaRi_k=-{Vc6bhlWYpL zCcDI@*^Dr4D=>_Eg=xDCGq)ePBD=y4u!G2z*j09jJ%-!_`+z;konN&yKN|VR#R)5XAV2f&LH;$ zJIl_Y{gZ5!U1V>f#-?Q%fUGL=L;_{J&@R?cQy zZ4|{SZ`dP)5z^EGT1SZjA=ZjPCb=xuky_(W8nIJ^Wt!tn>P6V|NmoO=?Z~&~ff}eJ z=>siLVY9SV=)A9>pJAU#srRSIyI6>cTY$nQkHguhH6yW1@qAYovKeZty>=rsu5Z@( z8uVSG#iFH*N+tgR#(s_HiB?f2-Ib440k!q$^y#1 zdI}LeLO+of7@&y}~Aar79nR*bYB@(gkux+bEswPO~$Iyqr zjKq4ZS%b=SId_CVS%-qFH#?2%cDvUCn2Gc-Peh1P^d}=NRsmy7>lJGa&8AxyxiMyk zGt@U~m^8VB5mMgI$o&H;7RDMrAdv(hA(5nMqctAGxKW0&1khqg;B2pdMwh^5lXr|oy!G=36IKg2KDugT#mM8`)VetJlJt zh2IC(UC;0EEg`$tovnmZUNtOqd-bNMHIbpJ?mh}Z8RYWXrj2?2B%%a7;|{G1VHtSFwfDZm z=iYxJdBCSnaY_)1{COtdQQ^yzx+XoL!@rNUM893A#GiNHxwKMQ+*n$SQLq?op72f6 zMz`j&@;7&KPDIviXLGB=ue+VO7v^9)=1#u2^ukjTN?|x80H4*J+cv!UXuG6KE~7BFNy^$ z_?_!cJ5=AOzCR-OCo3AWL8;*a`=M;<3n7#ju6=3tvsEa`Hc5mQw2Ap$TasbDG$rv~pK_6gf2s z)fCu!U!ZejnMNI&kw%ZAS)WbxPgZ9%I&GhKnoWldO_nvAl)CM;q9O}Z4Np8oz=HKueH5MH>C}4&AAL1uGJfCY5B-Y8KLj*&vGHt zw;C!g8!k5SGR&0x+F!}=yX%{iD%It ze56RU*T7ja%G@?{ZrZR#E?EmyqKq6Le@k?wqYacaJDU!->u^A6A5hTic1H`EZp($K zTgq6vmHB)mPb5R3E~p80K}2XKbA;tl3c_M$uCSPyC)C9p{XIkdGh|3s^Aw}dL`d#O zn3|KH%WX=2LCGhSkORr-ht6KjYww+ItjRKA?fpgGGv#BMlUV zC={UFK>(iaxts3hE_&WJIBC$AD? zvTE=XDj2eB%$1xVxk(57TeOWdpx&PyN=;hdAl4)wI^Iad<*)I8^K|vL{PpL9oG))H zL2gGLn7$gAIJL+_h3B`m9f;H&Wq@lJiueROl{J~^@JNa{f7XK{GZ66>Sq^DoM;(-c z5;H|f{uPN8g5nzD#KDAb1R6#yV{>xBL{P>_Xz@$+Dz0gcO7BVUOTWiyFa3WY(QU$f zi9#4MXQ2vjHq?dNWEt@A@OW3TbSSM3N1WjBmg~_y&0STr=XAdiPSkohZ0ByjMuL{9 z$kp98otyBdsTmBeaNF+6VZP2gHP%2_K5vE^M7bUNH%$~<>gl>`2_GH~aX1MYY=VRB zcWew88gP!@bhg5&ZqHlK>a_XENIZmLCg0yOsqd=WbV8Man-0o^P=pF!<*U>p2ltj- z_%IJbdo2gHAQVY0OGF3%3zBP13 zRuufcHU4Pi_bDZ+k^6Bd689Xz4BeKbnE4kxBzH}NT##e(K?#VFAz;dFAZ)5?<;g#@*K6K7 zxL@Zo7T4E%{_2az;gHalS;j_-bhDM;XvG(Qkpr_vmBeTofv@9t~c*f zGKMvi5JQ9iGb+8qNazaF#L>SQe+|HnzUDVZZdd5V2MWnRBYqCyj!xc%c{i~?DfURE z6ZUY%hRbZ_R|@i)D2B=xfe{!?2VNAEFC!0qh4KY~Uz86_;27F# zkoRR~2Ig-i1{5PL{7%0u!;vswk#1bPvE2R~V;3>TH|f~dM#las9sAt}$A%+9`2RP| zF_D?0Je&hHlbM?A?0>lNRonCxHg#L3yD{j;>8el`_XL2H1_u~nnHs()^q*y{x=xef z!i><{*MO=@U#UFTSLaVwETz}wbcWW?U2>XE162nq&_xw$J72-2S*6#-rIJ%QS?T94 zN7?>S+{08_Jf7>kh9x+u+ZN_R+mx1wEhbb)%wa2pGH9F%#+UE-vi!E_d5L zQ20&p9Q$6_~XyLtpL{cIYY66R; z7>^Z&keNK0@*x=|O4e+qBaOh2OsI~ZfZ-Kn1n6V|IyHhM9rZ#rX{5mD_?Hgppv2&N z&_M`Y1)y9*3&U5o)xaR72gm`MP*cV$(Wd6AoPw}W?`+})f{a>8l?n6`g*=f;5b?K8 zX2HW%U&>PcD{ApMC1YYd#yfFv5gQf_!sSuD1d~vf_b6q#OuWe)VZ<%*K0&ALj9htA zzx3GRFY!P;*^xd{1_n76SUWuN+bRr&5}0(c3qgVK-c|CJ0q0A~bzE&2Itg`ngYDaIU31Sh#YU&q<&JP5!eS=W2n%FhadnJJyiK7tnqGfj z0o zLm>|E_1g@uoM3vo2xTq~nC-|H(OIw6^{fKy#Cb6Q7f0v(Gfaj#1p>ZCKGY!2UStQp zN{He=q1-E!kUGb$q@aaU*d^?Sm0yK#)P(zTGt&B_a1q95mS8f69+C<%QfE|6DJTZS zYDQCJO;-MB7-js=Km9TN<5H(PB zC|`d7Ao0s75RKP|)8lG4hRCow%tv_~{e(x3zPajN+}c<>eWmR!AHTY^xqkZX)7|Tx zn!j=O*xMK1KJ!-l$cHDctiAQ-^2+I(OII&!c;V4Es^^cse8jo9yu7)5#ybDf)f1OC zPxt&2wbjj+8vV;F?VH}Y<7azyYwOaDV^^;E%g)x7(~&9Ma4w9TaL|z&tw`9OV<5c$ zc;W=%g%KIo%&<3f&HSm17fDLdizM+YBf7U7Xak+W@+1~%OzkB{>-gG1vl&Py|*gPO=w(i;U1VuCzIqmTgIm2uC4p@4uQW8-M`*x zGX6JIW5y?eo~3WrT;IbjeNNz{!z1_P*J#CmPl<>Q3JBwp^IQ=ikfw;^im1bNYD-4L zD%N{jEvHrA@*NLR;uLN}EgkmO;q+!x!*LOOgu1B43y^Ty*5IDiH~R&g=HpX=L73O^ zVgT>7_#bG%85ou8j@^cLj(29-zUyx#WsPnxEeoR)x>YzE6s3R(Y3u-xf*=89M%N*XoHb<#HyIBLK)-znV4@;-{B+m6ecl>o<^-+ zSdR5Vyp>f_9RUcI@`_wgX7Fx^0fVQhaZn92sQkB47#+;s|*Z&QOE zO8$-#F(L`%g?NP(K2PP(Q}SaY>ZDfxgBi;@N<4kfoJ`7=tspyW4{PzcX|OUWHdL~KuIc>EtJ8G=vbCaLTNBuDV` zXeaQtTA^UzrygXp)|0Bjt4vi}) zu}nG}^BS%j9ZTf#vho7Ogm_huvOV8zdQgMN3ip!S5i!VaREOp((TjVp(sbgbK)f%i LicKYtGgMPxbwEP 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 literal 0 HcmV?d00001 diff --git a/milasargawi/api/__pycache__/utils.cpython-38.pyc b/milasargawi/api/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25168b23e5526d095113dace80c8949b9ca0e95f GIT binary patch literal 2217 zcmah~T~8ZF6rDT!;kB^|r6fQbsi|7Eaz7xDkkAMrl=h`+L>{8PpsHx?yWkD>+RQEq zrppsie@F6|AJIQDuYK}g$Wzaqr6>-Sx~rW#-}lV9XYT&mYBdy|yS=} zy7bgdI!fGPiE1vBmDivKnHFkYhf@0Rh$q?JF}R6JNoLNmDCl$+6$thPYNfuyiCWbw zs0**u7X+>=)RQ~dqwU*zXIvz)G4a^e4$N=>!flwG7D>jA9*N2*9`}ba+o;=%(`-Lw z>vc{JK0Hh#PY?I2V9jIiyoo|-pPD+-4Vu;FCfZYMPpLu}V0x{DV?nul7XI<*?)vFD zA|D0K0JBY%`BpR%?~ z#C$3P+EUj>0zvM;HEeldE-Cm5vvcvUXr9dHuw7BkzmF(P+D=6~s0ayAjR!00@qyJV z{UufEMd=R;T?QAp0k@Dojf^A6kkn zb*vXNTROEg-t*!t|L`Dl5SZD|PdbH(y9KWAx7e!^5=D6D@J3|5L+=#n;{1yAEi{Di zqrlvT)kkD*SFvXA!h0rTKE^g-1B`9DF`q*j;~LZuxod5{#y*zLCc>GeHA@>tB5%Z5 zy8;0tn)~n=v+fuWOFkZShW!mp$z9skbJWBUnq=0{H+2Mwig7c^MIrwx*Rg8|5 zd0cAIQc25*4eK2x$sAfjL>APN+Ex#h%;x}>jw95T(n744{}GD~D%uMR2) zn#egOJ5or3bSIt24W7(MA&Nxe5Oq1|$O@F3B{Z#{#e?J;0|ogrBXLnZC*6-clh&x?Q z4i0nJ7y-`tl%^kU`q`p<`HW<#t; z#%~9fGFuao4C0abL1qe-|E(qAPk5{t{RQ)KNw30W16)S51U)UtKSQL`rrmbSMx8XP z(u&I`4v-70!z_8&;d#{IFPt-+8_`pLG4CclNENs$)? PQPgNfzN>= 7 + buf |= (((val > 0) if 1 else 0) << 7) + self._push_byte(buf) + while val: + buf = int((val) & 0x7f) + val >>= 7 + buf |= (((val > 0) if 1 else 0) << 7) + self._push_byte(buf) + return self._b_arr + + def _pop(self, buf, length): + return buf[:length], buf[length:] + + def decode(self, buf): + ''' ''' + shift = 0 + result = 0 + while True: + tmp, buf = self._pop(buf, 2) + i = hex_to_int(tmp) + result |= (i & 0x7f) << shift + shift += 7 + if not(i & 0x80): + break + return result, buf + + +class BaseObject(object): + def __init__(self, d): + ''' ''' + try: + self._obj = self._validator.deserialize(d) + except Invalid: + raise INRInvalidSchema('Unable to process schema for {}'.format(type(self))) + # instantiate the class + for k, v in self._obj.items(): + setattr(self, k, v) + # clean up + del self._obj + del self._validator + + def __repr__(self): + ''' ''' + return '{}({})'.format(self.__class__, self.__dict__) + + def _encode_buffer(self, value): + ''' ''' + return INRBuffer(value).encode() + + def _create_obj_array(self, arr, class_type): + ''' ''' + new_arr = [] + for item in arr: + new_arr.append(class_type(item)) + return new_arr + + +class Action(BaseObject): + def __init__(self, d): + ''' ''' + self._validator = ActionSchema() + super(Action, self).__init__(d) + # setup permissions + self.authorization = self._create_obj_array(self.authorization, Authorization) + + def encode(self): + ''' ''' + acct = self._encode_buffer(AccountName(self.account)) + name = self._encode_buffer(Name(self.name)) + auth = self._encode_buffer(self.authorization) + # need to figure out how to process data + # get length + data_len = self._encode_buffer(VarUInt(len(self.data) / 2)) + data = data_len + self.data + return '{}{}{}{}'.format(acct, name, auth, data) + + +class Asset: + def __init__(self, value, precision=4): + # self.amount = amt + # self.symbol = sym + # self.precision = precision + self.from_string(value) + + def __str__(self): + return '{amount:.{precision}f} {symbol}'.format(amount=self.amount, symbol=self.symbol, precision=self.precision) + + def __add__(self, other): + if self.symbol != other.symbol: + raise TypeError('Symbols must match: {} != {}', self.symbol, other.symbol) + return Asset(self.amount + other.amount, self.symbol) + + def __sub__(self, other): + if self.amount - other.amount < 0: + raise ValueError('Subtraction would result in a negative.') + if self.symbol != other.symbol: + raise TypeError('Symbols must match: {} != {}', self.symbol, other.symbol) + return Asset(self.amount - other.amount, self.symbol) + + def from_string(self, s): + splt = s.split() + try: + self.amount = float(splt[0]) + self.symbol = splt[1] + self.precision = len(splt[0].split(".")[1]) + except IndexError: + raise IndexError('Invalid string format given. Must be in the formst ') + + def _string_to_symbol(self): + ''' ''' + rslt = 0 + cnt = 0 + while cnt < len(self.symbol): + letter = self.symbol[cnt] + if letter >= 'A' or letter <= 'Z': + l = ord(letter) + rslt |= (UInt64(l) << (8 * (cnt + 1))) + else: + raise ValueError("{} contains an invalid symbol. Must be [A-Z].".format(self.symbol)) + + cnt += 1 + rslt |= UInt64(self.precision) + return INRBuffer(UInt64(rslt)).encode() + + def encode(self): + ''' ''' + power = '1'.ljust(self.precision + len('1'), '0') + amount = INRBuffer(UInt64(self.amount * UInt64(power))).encode() + symbol = self._string_to_symbol() + return '{amount}{symbol}'.format(amount=amount, symbol=symbol) + + +class AbiType(BaseObject): + def __init__(self, d): + self._validator = AbiTypeSchema() + super(AbiType, self).__init__(d) + + def encode(self): + new_type_name = self._encode_buffer(self.new_type_name) + type = self._encode_buffer(self.type) + return '{}{}'.format(new_type_name, type) + + +class AbiStructField(BaseObject): + def __init__(self, d): + self._validator = AbiStructFieldSchema() + super(AbiStructField, self).__init__(d) + + def encode(self): + name = self._encode_buffer(self.name) + type = self._encode_buffer(self.type) + return '{}{}'.format(name, type) + + +class AbiStruct(BaseObject): + def __init__(self, d): + self._validator = AbiStructSchema() + super(AbiStruct, self).__init__(d) + self.fields = self._create_obj_array(self.fields, AbiStructField) + + def encode(self): + name = self._encode_buffer(self.name) + base = self._encode_buffer(self.base) + fields = self._encode_buffer(self.fields) + return '{}{}{}'.format(name, base, fields) + + +class AbiAction(BaseObject): + def __init__(self, d): + self._validator = AbiActionSchema() + super(AbiAction, self).__init__(d) + + def encode(self): + name = self._encode_buffer(Name(self.name)) + type = self._encode_buffer(self.type) + ricardian_contract = self._encode_buffer(self.ricardian_contract) + return '{}{}{}'.format(name, type, ricardian_contract) + + +class AbiTable(BaseObject): + def __init__(self, d): + self._validator = AbiTableSchema() + super(AbiTable, self).__init__(d) + + def encode(self): + name = self._encode_buffer(Name(self.name)) + index_type = self._encode_buffer(self.index_type) + key_names = self._encode_buffer(self.key_names) + key_types = self._encode_buffer(self.key_types) + type = self._encode_buffer(self.type) + return '{}{}{}{}{}'.format(name, index_type, key_names, key_types, type) + + +class AbiRicardianClauses(BaseObject): + def __init__(self, d): + self._validator = AbiRicardianClauseSchema() + super(AbiRicardianClauses, self).__init__(d) + + def encode(self): + id = self._encode_buffer(self.id) + body = self._encode_buffer(self.body) + return '{}{}'.format(id, body) + + +class AbiErrorMessages(BaseObject): + # TODO implement encode + def __init__(self, d): + self._validator = AbiErrorMessagesSchema() + super(AbiErrorMessages, self).__init__(d) + + def encode(): + raise NotImplementedError + + +class AbiExtensions(BaseObject): + # TODO implement encode + def __init__(self, d): + self._validator = AbiExtensionsSchema() + super(AbiExtensions, self).__init__(d) + + def encode(): + raise NotImplementedError + + +class AbiVariants(BaseObject): + # TODO implement encode + def __init__(self, d): + self._validator = AbiVariantsSchema() + super(AbiVariants, self).__init__(d) + + def encode(): + raise NotImplementedError + + +class Abi(BaseObject): + _abi_map = { + # name + 'name': Name(), + 'string': str(), + # numbers + 'bool': Byte(), + 'uint8': Byte(), + 'uint16': UInt16(), + 'uint32': UInt32(), + 'uint64': UInt64(), + 'int8': Byte(), # NotImplemented + 'int16': Int16(), # NotImplemented + 'int32': Int32(), # NotImplemented + 'int64': Int64(), # NotImplemented + 'float64': Float(), # NotImplemented + # 'varuint32': VarUInt # NotImplemented + # complex + 'asset': Asset("1.0000 INR"), + # 'checksum256': str, # NotImplemented + # 'block_timestamp_type': UInt64, # NotImplemented + # 'time_point': UInt64, # NotImplemented + # 'connector': str, # NotImplemented + # 'public_key': str, # NotImplemented + # 'authority': str, # NotImplemented + # 'block_header': str, # NotImplemented + # 'bytes': str, # NotImplemented + # 'permission_level': str, # NotImplemented + # 'permission_level_weight': str, #NotImplemented + } + + def __init__(self, d): + ''' ''' + self._validator = AbiSchema() + super(Abi, self).__init__(d) + self.types = self._create_obj_array(self.types, AbiType) + self.structs = self._create_obj_array(self.structs, AbiStruct) + self.actions = self._create_obj_array(self.actions, AbiAction) + self.tables = self._create_obj_array(self.tables, AbiTable) + self.ricardian_clauses = self._create_obj_array(self.ricardian_clauses, AbiRicardianClauses) + self.error_messages = self._create_obj_array(self.error_messages, AbiErrorMessages) + self.abi_extensions = self._create_obj_array(self.abi_extensions, AbiExtensions) + self.variants = self._create_obj_array(self.variants, AbiVariants) + + def get_action(self, name): + ''' ''' + for act in self.actions: + if act.name == name: + return act + raise INRUnknownObj('{} is not a valid action for this contract'.format(name)) + + def get_actions(self): + actions = [] + for act in self.actions: + actions.append(act.name) + return actions + + def get_struct(self, name): + ''' ''' + for struct in self.structs: + if struct.name == name: + return struct + raise INRUnknownObj('{} is not a valid struct for this contract'.format(name)) + + def get_action_parameters(self, name): + ''' ''' + parameters = OrderedDict() + # get the struct + struct = self.get_struct(name) + for field in struct.fields: + f = field.type.strip('[]') + if(f in self._abi_map): + field_type = self._abi_map[f] + # check if the field is a list + if '[]' in field.type: + field_type = [field_type] + parameters[field.name] = field_type + else: + raise INRUnknownObj("{} is not a known abi type".format(field.type)) + return parameters + + def get_raw(self): + version = self._encode_buffer(self.version) + # encode types + types = self._encode_buffer(self.types) + structs = self._encode_buffer(self.structs) + actions = self._encode_buffer(self.actions) + tables = self._encode_buffer(self.tables) + ricardian_clauses = self._encode_buffer(self.ricardian_clauses) + error_messages = self._encode_buffer(self.error_messages) + abi_extensions = self._encode_buffer(self.abi_extensions) + variants = self._encode_buffer(self.variants) + return '{}{}{}{}{}{}{}{}{}'.format(version, types, structs, actions, tables, + ricardian_clauses, error_messages, abi_extensions, + variants) + + def encode(self): + ''' ''' + raw_abi = self.get_raw() + # divide by two because it is hex + length = self._encode_buffer(VarUInt(len(raw_abi) / 2)) + return length + raw_abi + + def json_to_bin(self, name, data): + # act = self.get_action(name) + params = self.get_action_parameters(name) + bin_buffer = '' + for field in data: + # create INRBuffer with value as a type of field + if isinstance(params[field], list): + field_type = type(params[field][0]) + arr = [] + for f in data[field]: + print(f) + arr.append(field_type(f)) + field_buffer = INRBuffer(arr) + else: + field_type = type(params[field]) + field_buffer = INRBuffer(field_type(data[field])) + + bin_buffer += field_buffer.encode() + return bin_buffer + + +class Authorization(BaseObject): + def __init__(self, d): + ''' ''' + # create validator + self._validator = PermissionLevelSchema() + super(Authorization, self).__init__(d) + + def encode(self): + ''' ''' + actor = self._encode_buffer(AccountName(self.actor)) + perms = self._encode_buffer(PermissionName(self.permission)) + return '{}{}'.format(actor, perms) + + +class ChainInfo(BaseObject): + def __init__(self, d): + ''' ''' + self._validator = ChainInfoSchema() + super(ChainInfo, self).__init__(d) + + +class BlockInfo(BaseObject): + def __init__(self, d): + ''' ''' + self._validator = BlockInfoSchema() + super(BlockInfo, self).__init__(d) + + +class Transaction(BaseObject): + def __init__(self, d, chain_info, lib_info): + ''' ''' + # add defaults + if 'expiration' not in d: + d['expiration'] = str((dt.datetime.utcnow() + dt.timedelta(seconds=30)).replace(tzinfo=pytz.UTC)) + if 'ref_block_num' not in d: + d['ref_block_num'] = chain_info['last_irreversible_block_num'] & 0xFFFF + if 'ref_block_prefix' not in d: + d['ref_block_prefix'] = lib_info['ref_block_prefix'] + # validate + self._validator = TransactionSchema() + super(Transaction, self).__init__(d) + # parse actions + self.actions = self._create_obj_array(self.actions, Action) + + def _encode_hdr(self): + ''' ''' + # convert + exp_ts = (self.expiration - dt.datetime(1970, 1, 1, tzinfo=self.expiration.tzinfo)).total_seconds() + exp = self._encode_buffer(UInt32(exp_ts)) + ref_blk = self._encode_buffer(UInt16(self.ref_block_num & 0xffff)) + ref_block_prefix = self._encode_buffer(UInt32(self.ref_block_prefix)) + net_usage_words = self._encode_buffer(VarUInt(self.net_usage_words)) + max_cpu_usage_ms = self._encode_buffer(Byte(self.max_cpu_usage_ms)) + delay_sec = self._encode_buffer(VarUInt(self.delay_sec)) + # create hdr buffer + hdr = '{}{}{}{}{}{}'.format(exp, ref_blk, ref_block_prefix, net_usage_words, max_cpu_usage_ms, delay_sec) + return hdr + + def encode(self): + ''' ''' + hdr_buf = self._encode_hdr() + context_actions = self._encode_buffer(self.context_free_actions) + actions = self._encode_buffer(self.actions) + trans_exts = self._encode_buffer(self.transaction_extensions) + return bytearray.fromhex(hdr_buf + context_actions + actions + trans_exts) + + def get_id(self): + return sha256(self.encode()) + + +class PackedTransaction: + def __init__(self, trx, ce): + self._cline = ce + self._packed_trx = trx + # empty header + self._is_unpacked = False + self._unpacked_trx = OrderedDict() + + def _decode_buffer(self, objType, buf): + ''' ''' + eBuf = INRBuffer("") + return eBuf.decode(objType, buf) + + def _decode_header(self, buf): + ''' ''' + buf = self._packed_trx + # get expiration buffer + (exp, buf) = self._decode_buffer(UInt32(), buf) + # get expiration in UTC + exp_dt = dt.datetime.utcfromtimestamp(exp) + self._unpacked_trx['expiration'] = exp_dt.strftime("%Y-%m-%dT%H:%M:%S") + # get ref_block + (ref_blk, buf) = self._decode_buffer(UInt16(), buf) + self._unpacked_trx['ref_block_num'] = ref_blk + # get ref_block_prefix + (ref_blk_pre, buf) = self._decode_buffer(UInt32(), buf) + self._unpacked_trx['ref_block_prefix'] = ref_blk_pre + # get net usage + (max_net_usage, buf) = self._decode_buffer(VarUInt(), buf) + self._unpacked_trx['max_net_usage_words'] = max_net_usage + # get cpu usage + (max_cpu_usage, buf) = self._decode_buffer(Byte(), buf) + self._unpacked_trx['max_cpu_usage_ms'] = max_cpu_usage + # get delay sec + (delay_sec, buf) = self._decode_buffer(VarUInt(), buf) + self._unpacked_trx['delay_sec'] = delay_sec + return buf + + def decode_actions(self, buf): + ''' ''' + # get length of action array + actions = [] + (length, act_buf) = self._decode_buffer(VarUInt(), buf) + cnt = 0 + # loop through array + while cnt < length and length: + # process action account/name + (acct_name, act_buf) = self._decode_buffer(AccountName(), act_buf) + (action_name, act_buf) = self._decode_buffer(ActionName(), act_buf) + # get authorizations + (auth, act_buf) = self.decode_authorizations(act_buf) + # get data length + (hex_data_len, act_buf) = self._decode_buffer(VarUInt(), act_buf) + # get abi information + contract_abi = self._cline.get_abi(acct_name) + abi = Abi(contract_abi["abi"]) + abi_act = abi.get_action(action_name) + # temp check need to handle this better + if abi_act["type"] != action_name: + raise INRAbiProcessingError("Error processing the {} action".format(action_name)) + abi_struct = abi.get_action_parameters(action_name) + data = OrderedDict() + # save data for hex_data + data_diff = act_buf + for a in abi_struct: + (act_data, act_buf) = self._decode_buffer(abi_struct[a], act_buf) + data[a] = act_data + act = OrderedDict({ + 'account': acct_name, + 'name': action_name, + "authorization": auth, + "data": data, + "hex_data": data_diff.rstrip(act_buf), + }) + actions.append(act) + # increment count + cnt += 1 + + return (actions, act_buf) + + def decode_authorizations(self, buf): + ''' ''' + auths = [] + (length, auth_buf) = self._decode_buffer(VarUInt(), buf) + cnt = 0 + while cnt < length and length: + # process action account/name + (acct_name, auth_buf) = self._decode_buffer(AccountName(), auth_buf) + (perm, auth_buf) = self._decode_buffer(ActionName(), auth_buf) + auth = OrderedDict({ + 'actor': acct_name, + 'permission': perm, + }) + auths.append(auth) + cnt += 1 + return (auths, auth_buf) + + # placeholder until context_free_actions are implemented. Might be able to use self.decode_actions + def decode_context_actions(self, buf): + ''' ''' + (length, ctx_buf) = self._decode_buffer(VarUInt(), buf) + if length > 0: + raise NotImplementedError("Currently inerypy does not support context_free_actions") + # get length of action array + return (length, ctx_buf) + + # placeholder until context_free_actions are implemented. Might be able to use self.decode_actions + def decode_trx_extensions(self, buf): + ''' ''' + trx_ext = [] + (length, ctx_buf) = self._decode_buffer(VarUInt(), buf) + if length > 0: + raise NotImplementedError("Currently inerypy does not support transaction extensions") + # get length of action array + return (trx_ext, ctx_buf) + + def get_id(self): + ''' ''' + return sha256(bytearray.fromhex(self._packed_trx)) + + def get_transaction(self): + ''' ''' + # only unpack once + if not self._is_unpacked: + # decode the header and get the rest of the trx back + trx_buf = self._decode_header(self._packed_trx) + # process list of context free actions + (context_actions, trx_buf) = self.decode_context_actions(trx_buf) + self._unpacked_trx['context_free_actions'] = context_actions + # process actions + (actions, trx_buf) = self.decode_actions(trx_buf) + self._unpacked_trx['actions'] = actions + # process transaction extensions + (trx_ext, trx_buf) = self.decode_trx_extensions(trx_buf) + self._unpacked_trx['transaction_extensions'] = trx_ext + # set boolean + self._is_unpacked = True + return self._unpacked_trx + + +class INRBuffer: + def __init__(self, v): + self._value = v + self._count = 0 + + def _decode_number(self, val, format='L'): + byte_val = binascii.unhexlify(val) + return convert_big_endian(byte_val, format) + + def _decode_float(self, val, format='f'): + byte_val = binascii.unhexlify(val) + return struct.unpack(">{}".format(format), byte_val) + + def _decode_name(self, val, format='Q'): + ''' ''' + num = self._decode_number(val, format) + return name_to_string(num) + + def _decode_str(self, val): + ''' ''' + # get length + vu = VarUInt() + (length, val) = vu.decode(val) + string = '' + leftover = val + # if there is data parse it + if length > 0: + (str_data, leftover) = self._splice_buf(val, length * 2) + string = binascii.unhexlify(str_data).decode() + return (string, leftover) + + def _splice_buf(self, buf, length): + return buf[:length], buf[length:] + + def _write_number(self, val, format='q'): + ''' ''' + le = convert_little_endian(val, format) + return binascii.hexlify(le).decode() + + def _write_name(self, w_str): + ''' ''' + val = string_to_name(w_str) + le = convert_little_endian(val, 'Q') + return binascii.hexlify(le).decode() + + def _write_str(self, w_str): + b = bytearray() + length = VarUInt(len(w_str)).encode() + b.extend(map(ord, w_str)) + return binascii.hexlify(length + b).decode() + + def _write_varuint(self, vuint): + buf = vuint.encode() + return binascii.hexlify(buf).decode() + + def decode(self, objType, buf=None): + leftover = "" + if not buf: + buf = self._value + if isinstance(objType, UInt32): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_number(val, 'I') + elif isinstance(objType, UInt16): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_number(val, 'H') + elif isinstance(objType, VarUInt): + (val, leftover) = objType.decode(buf) + elif(isinstance(objType, Byte) or + isinstance(objType, bool)): + (hex_str, leftover) = self._splice_buf(buf, 2) + val = hex_to_int(hex_str) + elif isinstance(objType, Float): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_float(val, 'f') + elif(isinstance(objType, int) or + isinstance(objType, long)): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_number(val, 'q') + elif (isinstance(objType, Name) or + isinstance(objType, AccountName) or + isinstance(objType, PermissionName) or + isinstance(objType, ActionName) or + isinstance(objType, TableName) or + isinstance(objType, ScopeName)): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_name(val) + elif isinstance(objType, str): + (val, leftover) = self._decode_str(buf) + elif(isinstance(objType, list)): + # get count(VarUint) + val = [] + (length, leftover) = VarUInt("").decode(buf) + while len(val) < length: + (out, leftover) = self.decode(objType[0], leftover) + val.append(out) + else: + raise INRBufferInvalidType("Cannot decode type: {}".format(type(objType))) + + return (val, leftover) + + def encode(self, val=None): + if not val: + val = self._value + if (isinstance(val, Name) or + isinstance(val, AccountName) or + isinstance(val, PermissionName) or + isinstance(val, ActionName) or + isinstance(val, TableName) or + isinstance(val, ScopeName)): + val = self._write_name(val) + return val + elif(isinstance(val, str)): + return self._write_str(val) + elif(isinstance(val, Byte) or + isinstance(val, bool)): + # return self._write_number(val, '?') + return int_to_hex(val) + elif(isinstance(val, UInt16)): + return self._write_number(val, 'H') + elif(isinstance(val, UInt32)): + return self._write_number(val, 'I') + elif(isinstance(val, UInt64)): + return self._write_number(val, 'q') + elif(isinstance(val, Float)): + return self._write_number(val, 'f') + elif(isinstance(val, VarUInt)): + # temp encoding + return self._write_varuint(val) + elif(isinstance(val, int) or + isinstance(val, long)): + return self._write_number(val, 'l') + elif(isinstance(val, Action) or + isinstance(val, AbiStruct) or + isinstance(val, AbiStructField) or + isinstance(val, AbiType) or + isinstance(val, AbiAction) or + isinstance(val, AbiTable) or + isinstance(val, AbiRicardianClauses) or + isinstance(val, AbiErrorMessages) or + isinstance(val, AbiExtensions) or + isinstance(val, AbiVariants) or + isinstance(val, Asset) or + isinstance(val, Authorization)): + return val.encode() + elif(isinstance(val, list)): + buf = self._write_varuint(VarUInt(len(val))) + for item in val: + e_item = self.encode(item) + buf = '{}{}'.format(buf, e_item) + return buf + else: + raise INRBufferInvalidType('Cannot encode type: {}'.format(type(val))) + +class InvalidKeyFile(Exception): + ''' Raised when the key file format is invalid ''' + pass + + +class INRKeyError(Exception): + ''' Raised when there is an INRKey error ''' + pass + + +class INRMsigInvalidProposal(Exception): + ''' Raised when an invalid proposal is queried''' + pass + + +class INRBufferInvalidType(Exception): + ''' Raised when trying to encode/decode an invalid type ''' + pass + + +class INRInvalidSchema(Exception): + ''' Raised when trying to process a schema ''' + pass + + +class INRUnknownObj(Exception): + ''' Raised when an object is not found in the ABI ''' + pass + + +class INRAbiProcessingError(Exception): + ''' Raised when the abi action cannot be processed ''' + pass + + +class INRSetSameCode(Exception): + ''' Raised when the code would not change on a set''' + pass + + +class INRSetSameAbi(Exception): + ''' Raised when the abi would not change on a set''' + pass + + + + +def convert_little_endian(buf, format='q'): + ''' ''' + return struct.pack('<{}'.format(format), buf) + + +def convert_big_endian(buf, format="I"): + ''' ''' + # return the first value of the tuple that is returned by unpack + return struct.unpack('<{}'.format(format), buf)[0] + +# json encoder + + +class INREncoder(json.JSONEncoder): + def default(self, o): + if isinstance(o, Action): + return o.__dict__ + if isinstance(o, Authorization): + return o.__dict__ + if isinstance(o, dt.datetime): + return o.isoformat() + + +class Name(str): + hex_str_len = 16 + + +class AccountName(Name): + pass + + +class PermissionName(Name): + pass + + +class ActionName(Name): + pass + + +class TableName(Name): + pass + + +class ScopeName(Name): + pass + + +class Byte(int): + # length of hex str + hex_str_len = 2 + + +class UInt16(int): + # length of hex str + hex_str_len = 4 + + +class UInt32(int): + # length of hex str + hex_str_len = 8 + + +class UInt64(int): + # length of hex str + hex_str_len = 16 + + +class Int16(int): + # length of hex str + hex_str_len = 4 + + +class Int32(int): + # length of hex str + hex_str_len = 8 + + +class Int64(int): + # length of hex str + hex_str_len = 16 + + +class Float(float): + # length of hex str + hex_str_len = 8 + + +if six.PY3: + class long(int): + pass + + +class VarUInt: + def __init__(self, val=""): + ''' ''' + self._val = val + self._b_arr = bytearray() + + def _push_byte(self, val): + self._b_arr.append(int(val)) + + def encode(self): + ''' ''' + # ensure value is an int + val = int(self._val) + buf = int((val) & 0x7f) + val >>= 7 + buf |= (((val > 0) if 1 else 0) << 7) + self._push_byte(buf) + while val: + buf = int((val) & 0x7f) + val >>= 7 + buf |= (((val > 0) if 1 else 0) << 7) + self._push_byte(buf) + return self._b_arr + + def _pop(self, buf, length): + return buf[:length], buf[length:] + + def decode(self, buf): + ''' ''' + shift = 0 + result = 0 + while True: + tmp, buf = self._pop(buf, 2) + i = hex_to_int(tmp) + result |= (i & 0x7f) << shift + shift += 7 + if not(i & 0x80): + break + return result, buf + + +class BaseObject(object): + def __init__(self, d): + ''' ''' + try: + self._obj = self._validator.deserialize(d) + except Invalid: + raise INRInvalidSchema('Unable to process schema for {}'.format(type(self))) + # instantiate the class + for k, v in self._obj.items(): + setattr(self, k, v) + # clean up + del self._obj + del self._validator + + def __repr__(self): + ''' ''' + return '{}({})'.format(self.__class__, self.__dict__) + + def _encode_buffer(self, value): + ''' ''' + return INRBuffer(value).encode() + + def _create_obj_array(self, arr, class_type): + ''' ''' + new_arr = [] + for item in arr: + new_arr.append(class_type(item)) + return new_arr + + +class Action(BaseObject): + def __init__(self, d): + ''' ''' + self._validator = ActionSchema() + super(Action, self).__init__(d) + # setup permissions + self.authorization = self._create_obj_array(self.authorization, Authorization) + + def encode(self): + ''' ''' + acct = self._encode_buffer(AccountName(self.account)) + name = self._encode_buffer(Name(self.name)) + auth = self._encode_buffer(self.authorization) + # need to figure out how to process data + # get length + data_len = self._encode_buffer(VarUInt(len(self.data) / 2)) + data = data_len + self.data + return '{}{}{}{}'.format(acct, name, auth, data) + + +class Asset: + def __init__(self, value, precision=4): + # self.amount = amt + # self.symbol = sym + # self.precision = precision + self.from_string(value) + + def __str__(self): + return '{amount:.{precision}f} {symbol}'.format(amount=self.amount, symbol=self.symbol, precision=self.precision) + + def __add__(self, other): + if self.symbol != other.symbol: + raise TypeError('Symbols must match: {} != {}', self.symbol, other.symbol) + return Asset(self.amount + other.amount, self.symbol) + + def __sub__(self, other): + if self.amount - other.amount < 0: + raise ValueError('Subtraction would result in a negative.') + if self.symbol != other.symbol: + raise TypeError('Symbols must match: {} != {}', self.symbol, other.symbol) + return Asset(self.amount - other.amount, self.symbol) + + def from_string(self, s): + splt = s.split() + try: + self.amount = float(splt[0]) + self.symbol = splt[1] + self.precision = len(splt[0].split(".")[1]) + except IndexError: + raise IndexError('Invalid string format given. Must be in the formst ') + + def _string_to_symbol(self): + ''' ''' + rslt = 0 + cnt = 0 + while cnt < len(self.symbol): + letter = self.symbol[cnt] + if letter >= 'A' or letter <= 'Z': + l = ord(letter) + rslt |= (UInt64(l) << (8 * (cnt + 1))) + else: + raise ValueError("{} contains an invalid symbol. Must be [A-Z].".format(self.symbol)) + + cnt += 1 + rslt |= UInt64(self.precision) + return INRBuffer(UInt64(rslt)).encode() + + def encode(self): + ''' ''' + power = '1'.ljust(self.precision + len('1'), '0') + amount = INRBuffer(UInt64(self.amount * UInt64(power))).encode() + symbol = self._string_to_symbol() + return '{amount}{symbol}'.format(amount=amount, symbol=symbol) + + +class AbiType(BaseObject): + def __init__(self, d): + self._validator = AbiTypeSchema() + super(AbiTypesSchema, self).__init__(d) + + def encode(self): + new_type_name = self._encode_buffer(self.new_type_name) + type = self._encode_buffer(self.type) + return '{}{}'.format(new_type_name, type) + + +class AbiStructField(BaseObject): + def __init__(self, d): + self._validator = AbiStructFieldSchema() + super(AbiStructField, self).__init__(d) + + def encode(self): + name = self._encode_buffer(self.name) + type = self._encode_buffer(self.type) + return '{}{}'.format(name, type) + + +class AbiStruct(BaseObject): + def __init__(self, d): + self._validator = AbiStructSchema() + super(AbiStruct, self).__init__(d) + self.fields = self._create_obj_array(self.fields, AbiStructField) + + def encode(self): + name = self._encode_buffer(self.name) + base = self._encode_buffer(self.base) + fields = self._encode_buffer(self.fields) + return '{}{}{}'.format(name, base, fields) + + +class AbiAction(BaseObject): + def __init__(self, d): + self._validator = AbiActionSchema() + super(AbiAction, self).__init__(d) + + def encode(self): + name = self._encode_buffer(Name(self.name)) + type = self._encode_buffer(self.type) + ricardian_contract = self._encode_buffer(self.ricardian_contract) + return '{}{}{}'.format(name, type, ricardian_contract) + + +class AbiTable(BaseObject): + def __init__(self, d): + self._validator = AbiTableSchema() + super(AbiTable, self).__init__(d) + + def encode(self): + name = self._encode_buffer(Name(self.name)) + index_type = self._encode_buffer(self.index_type) + key_names = self._encode_buffer(self.key_names) + key_types = self._encode_buffer(self.key_types) + type = self._encode_buffer(self.type) + return '{}{}{}{}{}'.format(name, index_type, key_names, key_types, type) + + +class AbiRicardianClauses(BaseObject): + def __init__(self, d): + self._validator = AbiRicardianClauseSchema() + super(AbiRicardianClauses, self).__init__(d) + + def encode(self): + id = self._encode_buffer(self.id) + body = self._encode_buffer(self.body) + return '{}{}'.format(id, body) + + +class AbiErrorMessages(BaseObject): + # TODO implement encode + def __init__(self, d): + self._validator = AbiErrorMessagesSchema() + super(AbiErrorMessages, self).__init__(d) + + +class AbiExtensions(BaseObject): + # TODO implement encode + def __init__(self, d): + self._validator = AbiExtensionsSchema() + super(AbiExtensions, self).__init__(d) + + + +class AbiVariants(BaseObject): + # TODO implement encode + def __init__(self, d): + self._validator = AbiVariantsSchema() + super(AbiVariants, self).__init__(d) + + + +class Abi(BaseObject): + _abi_map = { + # name + 'name': Name(), + 'string': str(), + # numbers + 'bool': Byte(), + 'uint8': Byte(), + 'uint16': UInt16(), + 'uint32': UInt32(), + 'uint64': UInt64(), + 'int8': Byte(), # NotImplemented + 'int16': Int16(), # NotImplemented + 'int32': Int32(), # NotImplemented + 'int64': Int64(), # NotImplemented + 'float64': Float(), # NotImplemented + # 'varuint32': VarUInt # NotImplemented + # complex + 'asset': Asset("1.0000 INR"), + # 'checksum256': str, # NotImplemented + # 'block_timestamp_type': UInt64, # NotImplemented + # 'time_point': UInt64, # NotImplemented + # 'connector': str, # NotImplemented + # 'public_key': str, # NotImplemented + # 'authority': str, # NotImplemented + # 'block_header': str, # NotImplemented + # 'bytes': str, # NotImplemented + # 'permission_level': str, # NotImplemented + # 'permission_level_weight': str, #NotImplemented + } + + def __init__(self, d): + ''' ''' + self._validator = AbiSchema() + super(Abi, self).__init__(d) + self.types = self._create_obj_array(self.types, AbiType) + self.structs = self._create_obj_array(self.structs, AbiStruct) + self.actions = self._create_obj_array(self.actions, AbiAction) + self.tables = self._create_obj_array(self.tables, AbiTable) + self.ricardian_clauses = self._create_obj_array(self.ricardian_clauses, AbiRicardianClauses) + self.error_messages = self._create_obj_array(self.error_messages, AbiErrorMessages) + self.abi_extensions = self._create_obj_array(self.abi_extensions, AbiExtensions) + self.variants = self._create_obj_array(self.variants, AbiVariants) + + def get_action(self, name): + ''' ''' + for act in self.actions: + if act.name == name: + return act + raise INRUnknownObj('{} is not a valid action for this contract'.format(name)) + + def get_actions(self): + actions = [] + for act in self.actions: + actions.append(act.name) + return actions + + def get_struct(self, name): + ''' ''' + for struct in self.structs: + if struct.name == name: + return struct + raise INRUnknownObj('{} is not a valid struct for this contract'.format(name)) + + def get_action_parameters(self, name): + ''' ''' + parameters = OrderedDict() + # get the struct + struct = self.get_struct(name) + for field in struct.fields: + f = field.type.strip('[]') + if(f in self._abi_map): + field_type = self._abi_map[f] + # check if the field is a list + if '[]' in field.type: + field_type = [field_type] + parameters[field.name] = field_type + else: + raise INRUnknownObj("{} is not a known abi type".format(field.type)) + return parameters + + def get_raw(self): + version = self._encode_buffer(self.version) + # encode types + types = self._encode_buffer(self.types) + structs = self._encode_buffer(self.structs) + actions = self._encode_buffer(self.actions) + tables = self._encode_buffer(self.tables) + ricardian_clauses = self._encode_buffer(self.ricardian_clauses) + error_messages = self._encode_buffer(self.error_messages) + abi_extensions = self._encode_buffer(self.abi_extensions) + variants = self._encode_buffer(self.variants) + return '{}{}{}{}{}{}{}{}{}'.format(version, types, structs, actions, tables, + ricardian_clauses, error_messages, abi_extensions, + variants) + + def encode(self): + ''' ''' + raw_abi = self.get_raw() + # divide by two because it is hex + length = self._encode_buffer(VarUInt(len(raw_abi) / 2)) + return length + raw_abi + + def json_to_bin(self, name, data): + # act = self.get_action(name) + params = self.get_action_parameters(name) + bin_buffer = '' + for field in data: + # create INRBuffer with value as a type of field + if isinstance(params[field], list): + field_type = type(params[field][0]) + arr = [] + for f in data[field]: + print(f) + arr.append(field_type(f)) + field_buffer = INRBuffer(arr) + else: + field_type = type(params[field]) + field_buffer = INRBuffer(field_type(data[field])) + + bin_buffer += field_buffer.encode() + return bin_buffer + + +class Authorization(BaseObject): + def __init__(self, d): + ''' ''' + # create validator + self._validator = PermissionLevelSchema() + super(Authorization, self).__init__(d) + + def encode(self): + ''' ''' + actor = self._encode_buffer(AccountName(self.actor)) + perms = self._encode_buffer(PermissionName(self.permission)) + return '{}{}'.format(actor, perms) + + +class ChainInfo(BaseObject): + def __init__(self, d): + ''' ''' + self._validator = ChainInfoSchema() + super(ChainInfo, self).__init__(d) + + +class BlockInfo(BaseObject): + def __init__(self, d): + ''' ''' + self._validator = BlockInfoSchema() + super(BlockInfo, self).__init__(d) + + +class Transaction(BaseObject): + def __init__(self, d, chain_info, lib_info): + ''' ''' + # add defaults + if 'expiration' not in d: + d['expiration'] = str((dt.datetime.utcnow() + dt.timedelta(seconds=30)).replace(tzinfo=pytz.UTC)) + if 'ref_block_num' not in d: + d['ref_block_num'] = chain_info['last_irreversible_block_num'] & 0xFFFF + if 'ref_block_prefix' not in d: + d['ref_block_prefix'] = lib_info['ref_block_prefix'] + # validate + self._validator = TransactionSchema() + super(Transaction, self).__init__(d) + # parse actions + self.actions = self._create_obj_array(self.actions, Action) + + def _encode_hdr(self): + ''' ''' + # convert + exp_ts = (self.expiration - dt.datetime(1970, 1, 1, tzinfo=self.expiration.tzinfo)).total_seconds() + exp = self._encode_buffer(UInt32(exp_ts)) + ref_blk = self._encode_buffer(UInt16(self.ref_block_num & 0xffff)) + ref_block_prefix = self._encode_buffer(UInt32(self.ref_block_prefix)) + net_usage_words = self._encode_buffer(VarUInt(self.net_usage_words)) + max_cpu_usage_ms = self._encode_buffer(Byte(self.max_cpu_usage_ms)) + delay_sec = self._encode_buffer(VarUInt(self.delay_sec)) + # create hdr buffer + hdr = '{}{}{}{}{}{}'.format(exp, ref_blk, ref_block_prefix, net_usage_words, max_cpu_usage_ms, delay_sec) + return hdr + + def encode(self): + ''' ''' + hdr_buf = self._encode_hdr() + context_actions = self._encode_buffer(self.context_free_actions) + actions = self._encode_buffer(self.actions) + trans_exts = self._encode_buffer(self.transaction_extensions) + return bytearray.fromhex(hdr_buf + context_actions + actions + trans_exts) + + def get_id(self): + return sha256(self.encode()) + + +class PackedTransaction: + def __init__(self, trx, ce): + self._cline = ce + self._packed_trx = trx + # empty header + self._is_unpacked = False + self._unpacked_trx = OrderedDict() + + def _decode_buffer(self, objType, buf): + ''' ''' + eBuf = INRBuffer("") + return eBuf.decode(objType, buf) + + def _decode_header(self, buf): + ''' ''' + buf = self._packed_trx + # get expiration buffer + (exp, buf) = self._decode_buffer(UInt32(), buf) + # get expiration in UTC + exp_dt = dt.datetime.utcfromtimestamp(exp) + self._unpacked_trx['expiration'] = exp_dt.strftime("%Y-%m-%dT%H:%M:%S") + # get ref_block + (ref_blk, buf) = self._decode_buffer(UInt16(), buf) + self._unpacked_trx['ref_block_num'] = ref_blk + # get ref_block_prefix + (ref_blk_pre, buf) = self._decode_buffer(UInt32(), buf) + self._unpacked_trx['ref_block_prefix'] = ref_blk_pre + # get net usage + (max_net_usage, buf) = self._decode_buffer(VarUInt(), buf) + self._unpacked_trx['max_net_usage_words'] = max_net_usage + # get cpu usage + (max_cpu_usage, buf) = self._decode_buffer(Byte(), buf) + self._unpacked_trx['max_cpu_usage_ms'] = max_cpu_usage + # get delay sec + (delay_sec, buf) = self._decode_buffer(VarUInt(), buf) + self._unpacked_trx['delay_sec'] = delay_sec + return buf + + def decode_actions(self, buf): + ''' ''' + # get length of action array + actions = [] + (length, act_buf) = self._decode_buffer(VarUInt(), buf) + cnt = 0 + # loop through array + while cnt < length and length: + # process action account/name + (acct_name, act_buf) = self._decode_buffer(AccountName(), act_buf) + (action_name, act_buf) = self._decode_buffer(ActionName(), act_buf) + # get authorizations + (auth, act_buf) = self.decode_authorizations(act_buf) + # get data length + (hex_data_len, act_buf) = self._decode_buffer(VarUInt(), act_buf) + # get abi information + contract_abi = self._cline.get_abi(acct_name) + abi = Abi(contract_abi["abi"]) + abi_act = abi.get_action(action_name) + # temp check need to handle this better + if abi_act["type"] != action_name: + raise INRAbiProcessingError("Error processing the {} action".format(action_name)) + abi_struct = abi.get_action_parameters(action_name) + data = OrderedDict() + # save data for hex_data + data_diff = act_buf + for a in abi_struct: + (act_data, act_buf) = self._decode_buffer(abi_struct[a], act_buf) + data[a] = act_data + act = OrderedDict({ + 'account': acct_name, + 'name': action_name, + "authorization": auth, + "data": data, + "hex_data": data_diff.rstrip(act_buf), + }) + actions.append(act) + # increment count + cnt += 1 + + return (actions, act_buf) + + def decode_authorizations(self, buf): + ''' ''' + auths = [] + (length, auth_buf) = self._decode_buffer(VarUInt(), buf) + cnt = 0 + while cnt < length and length: + # process action account/name + (acct_name, auth_buf) = self._decode_buffer(AccountName(), auth_buf) + (perm, auth_buf) = self._decode_buffer(ActionName(), auth_buf) + auth = OrderedDict({ + 'actor': acct_name, + 'permission': perm, + }) + auths.append(auth) + cnt += 1 + return (auths, auth_buf) + + def decode_trx_extensions(self, buf): + ''' ''' + trx_ext = [] + (length, ctx_buf) = self._decode_buffer(VarUInt(), buf) + if length > 0: + raise NotImplementedError("Currently inerypy does not support transaction extensions") + # get length of action array + return (trx_ext, ctx_buf) + + def get_id(self): + ''' ''' + return sha256(bytearray.fromhex(self._packed_trx)) + + def get_transaction(self): + ''' ''' + # only unpack once + if not self._is_unpacked: + # decode the header and get the rest of the trx back + trx_buf = self._decode_header(self._packed_trx) + # process list of context free actions + (context_actions, trx_buf) = self.decode_context_actions(trx_buf) + self._unpacked_trx['context_free_actions'] = context_actions + # process actions + (actions, trx_buf) = self.decode_actions(trx_buf) + self._unpacked_trx['actions'] = actions + # process transaction extensions + (trx_ext, trx_buf) = self.decode_trx_extensions(trx_buf) + self._unpacked_trx['transaction_extensions'] = trx_ext + # set boolean + self._is_unpacked = True + return self._unpacked_trx + + +class INRBuffer: + def __init__(self, v): + self._value = v + self._count = 0 + + def _decode_number(self, val, format='L'): + byte_val = binascii.unhexlify(val) + return convert_big_endian(byte_val, format) + + def _decode_float(self, val, format='f'): + byte_val = binascii.unhexlify(val) + return struct.unpack(">{}".format(format), byte_val) + + def _decode_name(self, val, format='Q'): + ''' ''' + num = self._decode_number(val, format) + return name_to_string(num) + + def _decode_str(self, val): + ''' ''' + # get length + vu = VarUInt() + (length, val) = vu.decode(val) + string = '' + leftover = val + # if there is data parse it + if length > 0: + (str_data, leftover) = self._splice_buf(val, length * 2) + string = binascii.unhexlify(str_data).decode() + return (string, leftover) + + def _splice_buf(self, buf, length): + return buf[:length], buf[length:] + + def _write_number(self, val, format='q'): + ''' ''' + le = convert_little_endian(val, format) + return binascii.hexlify(le).decode() + + def _write_name(self, w_str): + ''' ''' + val = string_to_name(w_str) + le = convert_little_endian(val, 'Q') + return binascii.hexlify(le).decode() + + def _write_str(self, w_str): + b = bytearray() + length = VarUInt(len(w_str)).encode() + b.extend(map(ord, w_str)) + return binascii.hexlify(length + b).decode() + + def _write_varuint(self, vuint): + buf = vuint.encode() + return binascii.hexlify(buf).decode() + + def decode(self, objType, buf=None): + leftover = "" + if not buf: + buf = self._value + if isinstance(objType, UInt32): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_number(val, 'I') + elif isinstance(objType, UInt16): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_number(val, 'H') + elif isinstance(objType, VarUInt): + (val, leftover) = objType.decode(buf) + elif(isinstance(objType, Byte) or + isinstance(objType, bool)): + (hex_str, leftover) = self._splice_buf(buf, 2) + val = hex_to_int(hex_str) + elif isinstance(objType, Float): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_float(val, 'f') + elif(isinstance(objType, int) or + isinstance(objType, long)): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_number(val, 'q') + elif (isinstance(objType, Name) or + isinstance(objType, AccountName) or + isinstance(objType, PermissionName) or + isinstance(objType, ActionName) or + isinstance(objType, TableName) or + isinstance(objType, ScopeName)): + (val, leftover) = self._splice_buf(buf, objType.hex_str_len) + val = self._decode_name(val) + elif isinstance(objType, str): + (val, leftover) = self._decode_str(buf) + elif(isinstance(objType, list)): + # get count(VarUint) + val = [] + (length, leftover) = VarUInt("").decode(buf) + while len(val) < length: + (out, leftover) = self.decode(objType[0], leftover) + val.append(out) + else: + raise INRBufferInvalidType("Cannot decode type: {}".format(type(objType))) + + return (val, leftover) + + def encode(self, val=None): + if not val: + val = self._value + if (isinstance(val, Name) or + isinstance(val, AccountName) or + isinstance(val, PermissionName) or + isinstance(val, ActionName) or + isinstance(val, TableName) or + isinstance(val, ScopeName)): + val = self._write_name(val) + return val + elif(isinstance(val, str)): + return self._write_str(val) + elif(isinstance(val, Byte) or + isinstance(val, bool)): + # return self._write_number(val, '?') + return int_to_hex(val) + elif(isinstance(val, UInt16)): + return self._write_number(val, 'H') + elif(isinstance(val, UInt32)): + return self._write_number(val, 'I') + elif(isinstance(val, UInt64)): + return self._write_number(val, 'q') + elif(isinstance(val, Float)): + return self._write_number(val, 'f') + elif(isinstance(val, VarUInt)): + # temp encoding + return self._write_varuint(val) + elif(isinstance(val, int) or + isinstance(val, long)): + return self._write_number(val, 'l') + elif(isinstance(val, Action) or + isinstance(val, AbiStruct) or + isinstance(val, AbiStructField) or + isinstance(val, AbiType) or + isinstance(val, AbiAction) or + isinstance(val, AbiTable) or + isinstance(val, AbiRicardianClauses) or + isinstance(val, AbiErrorMessages) or + isinstance(val, AbiExtensions) or + isinstance(val, AbiVariants) or + isinstance(val, Asset) or + isinstance(val, Authorization)): + return val.encode() + elif(isinstance(val, list)): + buf = self._write_varuint(VarUInt(len(val))) + for item in val: + e_item = self.encode(item) + buf = '{}{}'.format(buf, e_item) + return buf + else: + raise INRBufferInvalidType('Cannot encode type: {}'.format(type(val))) diff --git a/milasargawi/api/utils.py b/milasargawi/api/utils.py new file mode 100644 index 000000000..19aec7a9b --- /dev/null +++ b/milasargawi/api/utils.py @@ -0,0 +1,88 @@ +from binascii import hexlify +import hashlib + + +def sha256(data): + ''' ''' + return hashlib.sha256(data).hexdigest() + + +def ripemd160(data): + ''' ''' + #h = hashlib.new('ripemd160') + h = hashlib.new('rmd160') + h.update(data) + return h.hexdigest() + + +def sig_digest(payload, chain_id=None): + ''' ''' + if chain_id: + buf = bytearray.fromhex(chain_id) + else: + buf = bytearray(32) + # already a bytearray + buf.extend(payload) + buf.extend(bytearray(32)) + + return sha256(buf) + + +def int_to_hex(i): + return '{:02x}'.format(i) + + +def hex_to_int(i): + return int(i, 16) + +def str_to_hex(c): + hex_data = hexlify(bytearray(c, 'ascii')).decode() + return int(hex_data, 16) + + +def char_subtraction(a, b, add): + x = str_to_hex(a) + y = str_to_hex(b) + ans = str((x - y) + add) + if len(ans) % 2 == 1: + ans = '0' + ans + return int(ans) + + + +def char_to_symbol(c): + ''' ''' + if c >= 'a' and c <= 'z': + return char_subtraction(c, 'a', 6) + if c >= '1' and c <= '5': + return char_subtraction(c, '1', 1) + return 0 + + +def string_to_name(s): + ''' ''' + i = 0 + name = 0 + while i < len(s): + #sym = char_to_symbol(s[i]) + name += (char_to_symbol(s[i]) & 0x1F) << (64 - 5 * (i + 1)) + i += 1 + if i > 12: + name |= char_to_symbol(s[11]) & 0x0F + return name + + +def name_to_string(n): + ''' ''' + charmap = '.12345abcdefghijklmnopqrstuvwxyz' + name = ['.'] * 13 + i = 0 + while i <= 12: + c = charmap[n & (0x0F if i == 0 else 0x1F)] + name[12 - i] = c + n >>= 4 if i == 0 else 5 + i += 1 + return ''.join(name).rstrip('.') + + + diff --git a/milasargawi/env-example b/milasargawi/env-example new file mode 100644 index 000000000..6ad620a90 --- /dev/null +++ b/milasargawi/env-example @@ -0,0 +1,2 @@ +node_url="your_ip_address" +priv_key="your_inery_private_key" \ No newline at end of file diff --git a/milasargawi/inerytransfer.py b/milasargawi/inerytransfer.py new file mode 100644 index 000000000..3df4d1cb2 --- /dev/null +++ b/milasargawi/inerytransfer.py @@ -0,0 +1,33 @@ +from api.cline import Cline +from api import keys +import json + + +node_url = os.environ["node_url"] +priv_key = os.environ["priv_key"] + +action_data = { + "from": "milasargawi", + "to": "inery", + "quantity": '1.0000 CRT', + "memo": "CRT Token transfer", +} + +action_payload = { + "account": "milasargawi", + "name": "transfer", + "authorization": [{ + "actor": "milasargawi", + "permission": "active" + }] +} +data = cli.abi_json_to_bin(action_payload['account'], action_payload['name'], action_data) +action_payload['data'] = data['binargs'] + +trx = {"actions": [action_payload]} + +key = INRKey(priv_key) +out = cli.push_transaction(trx, key, broadcast=True) +print('================================================') +print(out) +print('================================================') \ No newline at end of file diff --git a/milasargawi/readme.md b/milasargawi/readme.md new file mode 100644 index 000000000..973e4c37d --- /dev/null +++ b/milasargawi/readme.md @@ -0,0 +1,35 @@ +**Requirements** +Python3 + + +**Change Directory** + +``` +cd ./milasargawi +``` + +**Install Requirements** + +``` +pip install -r requirements.txt +``` + +**Create .env and change its value** + +``` +cp .env-example .env +``` + +**change env variable with your info** + +``` +node_url="your_ip_address" +priv_key="your_inery_private_key" +``` + +**run solution** + +``` +python3 ./inerytransfer.py +``` + diff --git a/milasargawi/requirements.txt b/milasargawi/requirements.txt new file mode 100644 index 000000000..16e0b3156 --- /dev/null +++ b/milasargawi/requirements.txt @@ -0,0 +1,5 @@ +python-dotenv +pytz +colander +base58 +ecdsa \ No newline at end of file