eth-erc20

ERC20 interface and example giftable token contract
Info | Log | Files | Refs | LICENSE

erc20.py (8888B)


      1 # standard imports
      2 import logging
      3 
      4 # external imports
      5 from chainlib.eth.constant import ZERO_ADDRESS
      6 from chainlib.eth.contract import (
      7     ABIContractEncoder,
      8     ABIContractDecoder,
      9     ABIContractType,
     10     abi_decode_single,
     11 )
     12 from chainlib.eth.jsonrpc import to_blockheight_param
     13 from chainlib.eth.error import RequestMismatchException
     14 from chainlib.eth.tx import (
     15     TxFactory,
     16     TxFormat,
     17 )
     18 from chainlib.jsonrpc import JSONRPCRequest
     19 from chainlib.block import BlockSpec
     20 from hexathon import (
     21     add_0x,
     22     strip_0x,
     23 )
     24 
     25 logg = logging.getLogger()
     26 
     27 
     28 class ERC20(TxFactory):
     29     
     30 
     31     def balance_of(self, contract_address, address, sender_address=ZERO_ADDRESS, id_generator=None, height=BlockSpec.LATEST):
     32         j = JSONRPCRequest(id_generator)
     33         o = j.template()
     34         o['method'] = 'eth_call'
     35         enc = ABIContractEncoder()
     36         enc.method('balanceOf')
     37         enc.typ(ABIContractType.ADDRESS)
     38         enc.address(address)
     39         data = add_0x(enc.get())
     40         tx = self.template(sender_address, contract_address)
     41         tx = self.set_code(tx, data)
     42         o['params'].append(self.normalize(tx))
     43         height = to_blockheight_param(height)
     44         o['params'].append(height)
     45         o = j.finalize(o)
     46         return o
     47 
     48 
     49     def balance(self, contract_address, address, sender_address=ZERO_ADDRESS, id_generator=None):
     50         return self.balance_of(contract_address, address, sender_address=sender_address, id_generator=id_generator)
     51 
     52 
     53     def symbol(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
     54         j = JSONRPCRequest(id_generator)
     55         o = j.template()
     56         o['method'] = 'eth_call'
     57         enc = ABIContractEncoder()
     58         enc.method('symbol')
     59         data = add_0x(enc.get())
     60         tx = self.template(sender_address, contract_address)
     61         tx = self.set_code(tx, data)
     62         o['params'].append(self.normalize(tx))
     63         o['params'].append('latest')
     64         o = j.finalize(o)
     65         return o
     66 
     67 
     68     def name(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
     69         j = JSONRPCRequest(id_generator)
     70         o = j.template()
     71         o['method'] = 'eth_call'
     72         enc = ABIContractEncoder()
     73         enc.method('name')
     74         data = add_0x(enc.get())
     75         tx = self.template(sender_address, contract_address)
     76         tx = self.set_code(tx, data)
     77         o['params'].append(self.normalize(tx))
     78         o['params'].append('latest')
     79         o = j.finalize(o)
     80         return o
     81 
     82     
     83     def decimals(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
     84         j = JSONRPCRequest(id_generator)
     85         o = j.template()
     86         o['method'] = 'eth_call'
     87         enc = ABIContractEncoder()
     88         enc.method('decimals')
     89         data = add_0x(enc.get())
     90         tx = self.template(sender_address, contract_address)
     91         tx = self.set_code(tx, data)
     92         o['params'].append(self.normalize(tx))
     93         o['params'].append('latest')
     94         o = j.finalize(o)
     95         return o
     96 
     97 
     98     def total_supply(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
     99         j = JSONRPCRequest(id_generator)
    100         o = j.template()
    101         o['method'] = 'eth_call'
    102         enc = ABIContractEncoder()
    103         enc.method('totalSupply')
    104         data = add_0x(enc.get())
    105         tx = self.template(sender_address, contract_address)
    106         tx = self.set_code(tx, data)
    107         o['params'].append(self.normalize(tx))
    108         o['params'].append('latest')
    109         o = j.finalize(o)
    110         return o
    111 
    112 
    113     def allowance(self, contract_address, holder_address, spender_address, sender_address=ZERO_ADDRESS, id_generator=None):
    114         j = JSONRPCRequest(id_generator)
    115         o = j.template()
    116         o['method'] = 'eth_call'
    117         enc = ABIContractEncoder()
    118         enc.method('allowance')
    119         enc.typ(ABIContractType.ADDRESS)
    120         enc.typ(ABIContractType.ADDRESS)
    121         enc.address(holder_address)
    122         enc.address(spender_address)
    123         data = add_0x(enc.get())
    124         tx = self.template(sender_address, contract_address)
    125         tx = self.set_code(tx, data)
    126         o['params'].append(self.normalize(tx))
    127         o['params'].append('latest')
    128         o = j.finalize(o)
    129         return o
    130 
    131 
    132     def transfer(self, contract_address, sender_address, recipient_address, value, tx_format=TxFormat.JSONRPC, id_generator=None):
    133         enc = ABIContractEncoder()
    134         enc.method('transfer')
    135         enc.typ(ABIContractType.ADDRESS)
    136         enc.typ(ABIContractType.UINT256)
    137         enc.address(recipient_address)
    138         enc.uint256(value)
    139         data = add_0x(enc.get())
    140         tx = self.template(sender_address, contract_address, use_nonce=True)
    141         tx = self.set_code(tx, data)
    142         tx = self.finalize(tx, tx_format, id_generator=id_generator)
    143         return tx
    144 
    145 
    146     def transfer_from(self, contract_address, sender_address, holder_address, recipient_address, value, tx_format=TxFormat.JSONRPC, id_generator=None):
    147         enc = ABIContractEncoder()
    148         enc.method('transferFrom')
    149         enc.typ(ABIContractType.ADDRESS)
    150         enc.typ(ABIContractType.ADDRESS)
    151         enc.typ(ABIContractType.UINT256)
    152         enc.address(holder_address)
    153         enc.address(recipient_address)
    154         enc.uint256(value)
    155         data = add_0x(enc.get())
    156         tx = self.template(sender_address, contract_address, use_nonce=True)
    157         tx = self.set_code(tx, data)
    158         tx = self.finalize(tx, tx_format)
    159         return tx
    160 
    161 
    162     def approve(self, contract_address, sender_address, spender_address, value, tx_format=TxFormat.JSONRPC, id_generator=None):
    163         enc = ABIContractEncoder()
    164         enc.method('approve')
    165         enc.typ(ABIContractType.ADDRESS)
    166         enc.typ(ABIContractType.UINT256)
    167         enc.address(spender_address)
    168         enc.uint256(value)
    169         data = add_0x(enc.get())
    170         tx = self.template(sender_address, contract_address, use_nonce=True)
    171         tx = self.set_code(tx, data)
    172         tx = self.finalize(tx, tx_format)
    173         return tx
    174 
    175 
    176     @classmethod
    177     def parse_symbol(self, v):
    178         return abi_decode_single(ABIContractType.STRING, v)
    179 
    180 
    181     @classmethod
    182     def parse_name(self, v):
    183         return abi_decode_single(ABIContractType.STRING, v)
    184 
    185 
    186     @classmethod
    187     def parse_decimals(self, v):
    188         return abi_decode_single(ABIContractType.UINT256, v)
    189 
    190 
    191     @classmethod
    192     def parse_balance(self, v):
    193         return abi_decode_single(ABIContractType.UINT256, v)
    194 
    195 
    196     @classmethod
    197     def parse_balance_of(self, v):
    198         return self.parse_balance(v)
    199 
    200 
    201     @classmethod
    202     def parse_total_supply(self, v):
    203         return abi_decode_single(ABIContractType.UINT256, v)
    204 
    205 
    206     @classmethod
    207     def parse_allowance(self, v):
    208         return abi_decode_single(ABIContractType.UINT256, v)
    209 
    210 
    211     @classmethod
    212     def parse_transfer_request(self, v):
    213         v = strip_0x(v)
    214         cursor = 0
    215         enc = ABIContractEncoder()
    216         enc.method('transfer')
    217         enc.typ(ABIContractType.ADDRESS)
    218         enc.typ(ABIContractType.UINT256)
    219         r = enc.get()
    220         l = len(r)
    221         m = v[:l]
    222         if m != r:
    223             raise RequestMismatchException(v)
    224         cursor += l
    225 
    226         dec = ABIContractDecoder()
    227         dec.typ(ABIContractType.ADDRESS)
    228         dec.typ(ABIContractType.UINT256)
    229         dec.val(v[cursor:cursor+64])
    230         cursor += 64
    231         dec.val(v[cursor:cursor+64])
    232         r = dec.decode()
    233         return r 
    234 
    235 
    236     @classmethod
    237     def parse_transfer_from_request(self, v):
    238         v = strip_0x(v)
    239         cursor = 0
    240         enc = ABIContractEncoder()
    241         enc.method('transferFrom')
    242         enc.typ(ABIContractType.ADDRESS)
    243         enc.typ(ABIContractType.ADDRESS)
    244         enc.typ(ABIContractType.UINT256)
    245         r = enc.get()
    246         l = len(r)
    247         m = v[:l]
    248         if m != r:
    249             raise RequestMismatchException(v)
    250         cursor += l
    251 
    252         dec = ABIContractDecoder()
    253         dec.typ(ABIContractType.ADDRESS)
    254         dec.typ(ABIContractType.ADDRESS)
    255         dec.typ(ABIContractType.UINT256)
    256         dec.val(v[cursor:cursor+64])
    257         cursor += 64
    258         dec.val(v[cursor:cursor+64])
    259         cursor += 64
    260         dec.val(v[cursor:cursor+64])
    261         r = dec.decode()
    262         return r 
    263 
    264 
    265     @classmethod
    266     def parse_approve_request(self, v):
    267         v = strip_0x(v)
    268         cursor = 0
    269         enc = ABIContractEncoder()
    270         enc.method('approve')
    271         enc.typ(ABIContractType.ADDRESS)
    272         enc.typ(ABIContractType.UINT256)
    273         r = enc.get()
    274         l = len(r)
    275         m = v[:l]
    276         if m != r:
    277             raise RequestMismatchException(v)
    278         cursor += l
    279 
    280         dec = ABIContractDecoder()
    281         dec.typ(ABIContractType.ADDRESS)
    282         dec.typ(ABIContractType.UINT256)
    283         dec.val(v[cursor:cursor+64])
    284         cursor += 64
    285         dec.val(v[cursor:cursor+64])
    286         r = dec.decode()
    287         return r