interface.py (5586B)
1 # standard imports 2 import logging 3 import copy 4 5 # external imports 6 import sha3 7 from chainlib.eth.tx import TxFactory 8 from chainlib.eth.constant import ZERO_ADDRESS 9 from chainlib.eth.contract import ( 10 abi_decode_single, 11 ABIContractEncoder, 12 ABIContractDecoder, 13 ABIContractType, 14 ) 15 from chainlib.eth.tx import ( 16 TxFormat, 17 ) 18 from chainlib.jsonrpc import JSONRPCRequest 19 from chainlib.eth.error import RequestMismatchException 20 from chainlib.eth.jsonrpc import to_blockheight_param 21 from hexathon import ( 22 add_0x, 23 strip_0x, 24 ) 25 from potaahto.symbols import snake_and_camel_s 26 27 logg = logging.getLogger().getChild(__name__) 28 29 30 class Faucet(TxFactory): 31 32 __signatures = { 33 'give_to': 'giveTo(address)', 34 'token_amount': 'tokenAmount()', 35 'token': 'token()', 36 } 37 __signatures_reverse = None 38 39 40 @classmethod 41 def method_for(self, b): 42 if type(b).__name__ == 'str': 43 b = bytes.fromhex(strip_0x(b)) 44 if len(b) < 4: 45 return None 46 return self.__signatures_reverse.get(b[:4]) 47 48 49 @classmethod 50 def signature_for(self, s): 51 return self.__signatures.get(s) 52 53 54 @classmethod 55 def build_signatures(cls): 56 if cls.__signatures_reverse != None: 57 return 58 cls.__signatures_reverse = {} 59 60 for (k, v) in copy.copy(Faucet.__signatures).items(): 61 (x, y) = snake_and_camel_s(k) 62 h = sha3.keccak_256() 63 h.update(v.encode('utf-8')) 64 z = h.digest() 65 sig = z[:4] 66 Faucet.__signatures[x] = sig 67 Faucet.__signatures[y] = sig 68 Faucet.__signatures_reverse[sig] = x 69 70 return True 71 72 73 def give_to(self, contract_address, sender_address, beneficiary_address, tx_format=TxFormat.JSONRPC): 74 enc = ABIContractEncoder() 75 enc.method('giveTo') 76 enc.typ(ABIContractType.ADDRESS) 77 enc.address(beneficiary_address) 78 data = enc.get() 79 tx = self.template(sender_address, contract_address, use_nonce=True) 80 tx = self.set_code(tx, data) 81 tx = self.finalize(tx, tx_format) 82 return tx 83 84 85 def gimme(self, contract_address, sender_address, tx_format=TxFormat.JSONRPC): 86 enc = ABIContractEncoder() 87 enc.method('gimme') 88 data = enc.get() 89 tx = self.template(sender_address, contract_address, use_nonce=True) 90 tx = self.set_code(tx, data) 91 tx = self.finalize(tx, tx_format) 92 return tx 93 94 95 @classmethod 96 def parse_give_to_request(self, v): 97 v = strip_0x(v) 98 cursor = 0 99 enc = ABIContractEncoder() 100 enc.method('giveTo') 101 enc.typ(ABIContractType.ADDRESS) 102 r = enc.get() 103 l = len(r) 104 m = v[:l] 105 if m != r: 106 raise RequestMismatchException(v) 107 cursor += l 108 109 dec = ABIContractDecoder() 110 dec.typ(ABIContractType.ADDRESS) 111 dec.val(v[cursor:cursor+64]) 112 r = dec.decode() 113 return r 114 115 116 def set_amount(self, contract_address, sender_address, amount, tx_format=TxFormat.JSONRPC): 117 enc = ABIContractEncoder() 118 enc.method('setAmount') 119 enc.typ(ABIContractType.UINT256) 120 enc.uint256(amount) 121 data = enc.get() 122 tx = self.template(sender_address, contract_address, use_nonce=True) 123 tx = self.set_code(tx, data) 124 tx = self.finalize(tx, tx_format) 125 return tx 126 127 128 def next_time(self, contract_address, address, sender_address=ZERO_ADDRESS, id_generator=None): 129 j = JSONRPCRequest(id_generator) 130 o = j.template() 131 o['method'] = 'eth_call' 132 enc = ABIContractEncoder() 133 enc.method('nextTime') 134 enc.typ(ABIContractType.ADDRESS) 135 enc.address(address) 136 data = add_0x(enc.get()) 137 tx = self.template(sender_address, contract_address) 138 tx = self.set_code(tx, data) 139 o['params'].append(self.normalize(tx)) 140 o = j.finalize(o) 141 return o 142 143 144 @classmethod 145 def parse_usable_for(self, v): 146 r = abi_decode_single(ABIContractType.UINT256, v) 147 return r == 0 148 149 150 def token(self, contract_address, sender_address=ZERO_ADDRESS, height=None, id_generator=None): 151 j = JSONRPCRequest(id_generator) 152 o = j.template() 153 o['method'] = 'eth_call' 154 enc = ABIContractEncoder() 155 enc.method('token') 156 data = add_0x(enc.get()) 157 tx = self.template(sender_address, contract_address) 158 tx = self.set_code(tx, data) 159 o['params'].append(self.normalize(tx)) 160 height = to_blockheight_param(height) 161 o['params'].append(height) 162 o = j.finalize(o) 163 return o 164 165 166 @classmethod 167 def parse_token(self, v): 168 return abi_decode_single(ABIContractType.ADDRESS, v) 169 170 171 def token_amount(self, contract_address, height=None, sender_address=ZERO_ADDRESS, id_generator=None): 172 j = JSONRPCRequest(id_generator) 173 o = j.template() 174 o['method'] = 'eth_call' 175 enc = ABIContractEncoder() 176 enc.method('tokenAmount') 177 data = add_0x(enc.get()) 178 tx = self.template(sender_address, contract_address) 179 tx = self.set_code(tx, data) 180 o['params'].append(self.normalize(tx)) 181 height = to_blockheight_param(height) 182 o['params'].append(height) 183 o = j.finalize(o) 184 return o 185 186 187 @classmethod 188 def parse_token_amount(self, v): 189 return abi_decode_single(ABIContractType.UINT256, v) 190 191 192 Faucet.build_signatures()