erc20-faucet

ERC20 token faucet
Info | Log | Files | Refs

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()