def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'coin': int(self.coin), 'to': bytes.fromhex(MinterHelper.prefix_remove(self.to)), 'value': MinterHelper.to_pip(self.value) } }) return struct
def sign(self, private_key): """ Sign transaction. This method can be called only from instances of inherited classes. Args: private_key (string): private key Return: string """ # Get structure populated with instance data tx = self._structure_from_instance() # Remove sgnature data, it's not needed before getting Keccak tx.pop('signature_data') # Encode tx data to RLP tx['data'] = rlp.encode(list(tx['data'].values())) # Encode all tx to RLP and create Keccak hash tx_rlp = rlp.encode(list(tx.values())) _keccak = MinterHelper.keccak_hash(tx_rlp) # Signature data tx['signature_data'] = rlp.encode(ECDSA.sign(_keccak, private_key)) tx_rlp = rlp.encode(list(tx.values())) self.signed_tx = binascii.hexlify(tx_rlp).decode()
def proof(cls, address, passphrase): """ Create proof Args: address (str) passphrase (str) Returns: str """ # Get address hash address = MinterPrefix.remove_prefix( string=address, prefix=MinterPrefix.ADDRESS ) address = MinterHelper.hex2bin(address) address_hash = cls.__hash(data=[address]) # Create SHA256 from passphrase sha = hashlib.sha256() sha.update(passphrase.encode()) passphrase = sha.hexdigest() # Get signature signature = ECDSA.sign(message=address_hash, private_key=passphrase) return binascii.hexlify(cls.__lockfromsignature(signature)).decode()
def estimate_coin_buy(self, coin_to_sell, value_to_buy, coin_to_buy, height=None, pip2bip=False): """ Return estimate of buy coin transaction Args: coin_to_sell (string): coin name to sell value_to_buy (string): Amount of coins to buy in PIP. Provide `value_to_buy` in PIP, if `pip2bip` False. Provide `value_to_buy` in BIP, if `pip2bip` True. coin_to_buy (string): coin name to buy height (int): block height pip2bip (bool): Convert coin amounts to BIP (default is in PIP) """ # Convert `value_to_buy` to PIP, if needed if pip2bip: value_to_buy = MinterHelper.to_pip(value_to_buy) # Get default response response = self._request( command='estimate_coin_buy', params={ 'coin_to_sell': coin_to_sell, 'value_to_buy': value_to_buy, 'coin_to_buy': coin_to_buy, 'height': height } ) # Convert response values from PIP to BIP, if needed if pip2bip: return self.__response_processor( data=response, funcs=[self.__pip_to_bip] ) return response
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg kwargs['data'].update({ 'check': MinterPrefix.CHECK + MinterHelper.bin2hex(kwargs['data']['check']), 'proof': MinterHelper.bin2hex(kwargs['data']['proof']) }) # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg kwargs['data'].update({ 'pub_key': MinterPrefix.PUBLIC_KEY + MinterHelper.bin2hex(kwargs['data']['pub_key']), 'coin': MinterConvertor.decode_coin_name(kwargs['data']['coin']), 'stake': MinterConvertor.convert_value(value=MinterHelper.bin2int(kwargs['data']['stake']), to='bip') }) # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({'type': self.TYPE, 'data': {'txs': []}}) # Populate multi data from each single tx. for item in self.txs: struct['data']['txs'].append([ int(item['coin']), bytes.fromhex(MinterHelper.prefix_remove(item['to'])), MinterHelper.to_pip(item['value']) ]) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'txs': [] }, 'signature_type': self.SIGNATURE_SINGLE_TYPE }) # Populate multi data from each single tx. for item in self.txs: struct['data']['txs'].append([ MinterConvertor.encode_coin_name(item['coin']), MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=item['to'], prefix=MinterPrefix.ADDRESS)), MinterConvertor.convert_value(value=item['value'], to='pip') ]) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'coin_to_sell': int(self.coin_to_sell), 'value_to_sell': MinterHelper.to_pip(self.value_to_sell), 'coin_to_buy': int(self.coin_to_buy), 'min_value_to_buy': MinterHelper.to_pip(self.min_value_to_buy) } }) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'pub_key': bytes.fromhex(MinterHelper.prefix_remove(self.pub_key)), 'coin': MinterHelper.encode_coin_name(self.coin), 'stake': MinterHelper.to_pip(self.stake) } }) return struct
def sign(self, private_key): """ Sign check Args: private_key (str) """ # Prepare structure # It contains nonce, chain_id, due_block, coin, value, gas_coin, # lock, v, r, s. # lock, v, r, s appended later in code structure = [ int(str(self.nonce).encode().hex(), 16), self.chain_id, self.due_block, MinterHelper.encode_coin_name(self.coin), MinterHelper.to_pip(self.value), MinterHelper.encode_coin_name(self.gas_coin) ] # Create msg hash msg_hash = self.__hash(structure) # SHA256 from passphrase sha = hashlib.sha256() sha.update(self.passphrase.encode()) passphrase = sha.hexdigest() # Create lock from signature self.lock = self.__lockfromsignature( signature=ECDSA.sign(message=msg_hash, private_key=passphrase)) # Re-create msg hash with adding lock to structure structure.append(self.lock) msg_hash = self.__hash(structure) # Re-create signature, add it to check attrs and to structure signature = ECDSA.sign(message=msg_hash, private_key=private_key) self.signature = { 'v': signature[0], 'r': format(signature[1], 'x'), 's': format(signature[2], 'x') } structure += signature # Get RLP, which will be the check check = rlp.encode(structure).hex() return MinterHelper.prefix_add(check, PREFIX_CHECK)
def get_fee(self): """ Get fee of transaction in PIP. Returns: int """ # Commission for payload and service_data bytes payload_gas = (MinterHelper.bytes_len(self.payload) * self.PAYLOAD_COMMISSION) service_data_gas = (MinterHelper.bytes_len(self.service_data) * self.PAYLOAD_COMMISSION) # Total commission commission = self.COMMISSION + payload_gas + service_data_gas commission *= self.FEE_DEFAULT_MULTIPLIER return commission
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg kwargs['data'].update({ 'pub_key': MinterPrefix.PUBLIC_KEY + MinterHelper.bin2hex(kwargs['data']['pub_key']), 'reward_address': MinterPrefix.ADDRESS + MinterHelper.bin2hex(kwargs['data']['reward_address']), 'owner_address': MinterPrefix.ADDRESS + MinterHelper.bin2hex(kwargs['data']['owner_address']) }) # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def sign(self, private_key=None, signature=None, ms_address=None): """ Sign transaction. This method can be called only from instances of inherited classes. Args: private_key (string|list[string]): private key to sign transaction with signature (string|list[string]): signature to sign transaction with ms_address (string): Multi signature address to sign tx by """ # Check arguments validity if not private_key and not signature: raise Exception('Please, provide either `private_key(s)` or `signature(s)`') if not ms_address and private_key and type(private_key) is not str: raise Exception('Please, provide a single `private_key` or set `ms_address` argument for multisig tx') if not ms_address and signature and type(signature) is not str: raise Exception('Please, provide a single `signature` or set `ms_address` argument for multisig tx') # Set tx signature type self.signature_type = self.SIGNATURE_SINGLE_TYPE if ms_address: if type(private_key) is str: private_key = [private_key] if type(signature) is str: signature = [signature] self.signature_type = self.SIGNATURE_MULTI_TYPE # Get populated and rlp encoded tx structure tx_struct = self.generate_tx_rlp() # Signature data if self.signature_type == self.SIGNATURE_SINGLE_TYPE: # Only one of private_key or signature can be provided for single signature type tx if private_key and signature: raise Exception('Please, provide one of `private_key` or `signature` for single signature type tx') # Set signature_data signature_data = self.generate_signature(private_key) if private_key else signature signature_data = self.decode_signature(signature_data) else: # Add multisig address to signature signature_data = [ MinterHelper.hex2bin(MinterPrefix.remove_prefix(string=ms_address, prefix=MinterPrefix.ADDRESS)), [] ] # Sign by each private key and add to total signature data if private_key: for pk in private_key: _signature = self.generate_signature(pk) signature_data[1].append(self.decode_signature(_signature)) # Sign by each signature and add to total signature data if signature: for _signature in signature: signature_data[1].append(self.decode_signature(_signature)) tx_struct['signature_data'] = rlp.encode(signature_data) self.signed_tx = self.generate_signed_tx(tx_struct)
def _structure_from_instance(self): """ Override parent method. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'name': self.name, 'symbol': MinterHelper.encode_coin_name(self.symbol), 'initial_amount': MinterHelper.to_pip(self.initial_amount), 'initial_reserve': MinterHelper.to_pip(self.initial_reserve), 'crr': '' if self.crr == 0 else self.crr, 'max_supply': MinterHelper.to_pip(self.max_supply) } }) return struct
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg for index, item in enumerate(kwargs['data']['txs']): kwargs['data']['txs'][index] = { 'coin': item[0], 'to': MinterHelper.prefix_add(item[1].hex(), PREFIX_ADDR), 'value': MinterHelper.to_bip(int.from_bytes(item[2], 'big')) } # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def _structure_from_instance(self): """ Override parent method. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'coin_to_buy': MinterHelper.encode_coin_name(self.coin_to_buy), 'value_to_buy': MinterHelper.to_pip(self.value_to_buy), 'coin_to_sell': MinterHelper.encode_coin_name(self.coin_to_sell), 'max_value_to_sell': MinterHelper.to_pip(self.max_value_to_sell) } }) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'pub_key': bytes.fromhex(MinterHelper.prefix_remove(self.pub_key)), 'reward_address': bytes.fromhex(MinterHelper.prefix_remove(self.reward_address)), 'owner_address': bytes.fromhex(MinterHelper.prefix_remove(self.owner_address)) } }) return struct
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg for index, item in enumerate(kwargs['data']['txs']): kwargs['data']['txs'][index] = { 'coin': MinterConvertor.decode_coin_name(item[0]), 'to': MinterPrefix.ADDRESS + MinterHelper.bin2hex(item[1]), 'value': MinterConvertor.convert_value(value=MinterHelper.bin2int(item[2]), to='bip') } # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def from_raw(cls, rawcheck): """ Create check instance from raw check Args: rawcheck (str) Returns: MinterCheck """ # Remove check prefix and RLP decode it rawcheck = MinterHelper.prefix_remove(rawcheck) rawcheck = bytes.fromhex(rawcheck) decoded = rlp.decode(rawcheck) # Create MinterCheck instance kwargs = { 'nonce': int(decoded[0].decode()), 'chain_id': int.from_bytes(decoded[1], 'big'), 'due_block': int.from_bytes(decoded[2], 'big'), 'coin': int.from_bytes(decoded[3], 'big'), 'value': MinterHelper.to_bip(int.from_bytes(decoded[4], 'big')), 'gas_coin': int.from_bytes(decoded[5], 'big'), 'lock': decoded[6].hex(), 'signature': { 'v': int.from_bytes(decoded[7], 'big'), 'r': decoded[8].hex(), 's': decoded[9].hex() } } check = MinterCheck(**kwargs) # Recover owner address msg_hash = cls.__hash(data=[ int(str(check.nonce).encode().hex(), 16), check.chain_id, check.due_block, check.coin, MinterHelper.to_pip(check.value), check.gas_coin, bytes.fromhex(check.lock) ]) public_key = ECDSA.recover(msg_hash, tuple(check.signature.values())) public_key = MinterHelper.prefix_add(public_key, PREFIX_PUBKEY) check.owner = MinterWallet.get_address_from_public_key(public_key) return check
def _structure_from_instance(self): """ Override parent method. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'address': bytes.fromhex(MinterHelper.prefix_remove(self.address)), 'pub_key': bytes.fromhex(MinterHelper.prefix_remove(self.pub_key)), 'commission': '' if self.commission == 0 else self.commission, 'coin': int(self.coin), 'stake': MinterHelper.to_pip(self.stake) } }) return struct
def get_fee(self): """ Get fee of transaction in PIP. Returns: int """ # Multiplied gas comission in PIP gas_price = MinterHelper.pybcmul(self.COMMISSION, self.FEE_DEFAULT_MULTIPLIER) # Comission for payload and service_data bytes comission = MinterHelper.pybcadd( MinterHelper.pybcmul(len(self.payload), self.FEE_DEFAULT_MULTIPLIER), MinterHelper.pybcmul(len(self.service_data), self.FEE_DEFAULT_MULTIPLIER)) return int(MinterHelper.pybcadd(gas_price, comission))
def __hash(data): """ Create service hash by RLP encoding and getting keccak hash from rlp result Args: data (list) Returns: hash (str) """ return MinterHelper.keccak_hash(rlp.encode(data))
def _structure_to_kwargs(cls, structure): """ Works with already populated structure and prepare **kwargs for creating new instance of tx. """ structure.update( {'gas_coin': MinterHelper.decode_coin_name(structure['gas_coin'])}) return structure
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'check': MinterHelper.hex2bin( MinterPrefix.remove_prefix(self.check, MinterPrefix.CHECK)), 'proof': MinterHelper.hex2bin(self.proof) }, 'signature_type': self.SIGNATURE_SINGLE_TYPE }) return struct
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg kwargs['data'].update({ 'pub_key': MinterHelper.prefix_add(kwargs['data']['pub_key'].hex(), PREFIX_PUBKEY), 'coin': kwargs['data']['coin'], 'stake': MinterHelper.to_bip(int.from_bytes(kwargs['data']['stake'], 'big')) }) # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def get_address_from_public_key(cls, public_key): """ @param public_key|string @return: string - Wallet address with prefix """ # Create keccak hash _keccak = MinterHelper.keccak_hash( binascii.unhexlify(public_key.replace(MinterPrefix.PUBLIC_KEY, ''))) return MinterPrefix.ADDRESS + _keccak[-40:]
def _structure_to_kwargs(cls, structure): """ Prepare decoded structure data to instance kwargs. """ kwargs = super()._structure_to_kwargs(structure) # Convert data values to verbose. # Data will be passed as additional kwarg kwargs['data'].update({ 'coin_to_sell': MinterHelper.decode_coin_name(kwargs['data']['coin_to_sell']), 'coin_to_buy': MinterHelper.decode_coin_name(kwargs['data']['coin_to_buy']), 'min_value_to_buy': MinterHelper.to_bip( int.from_bytes(kwargs['data']['min_value_to_buy'], 'big')) }) # Populate data key values as kwargs kwargs.update(kwargs['data']) return kwargs
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'pub_key': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.pub_key, prefix=MinterPrefix.PUBLIC_KEY) ), 'reward_address': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.reward_address, prefix=MinterPrefix.ADDRESS) ), 'owner_address': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.owner_address, prefix=MinterPrefix.ADDRESS) ) } }) return struct
def _structure_from_instance(self): """ Override parent method. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'address': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.address, prefix=MinterPrefix.ADDRESS) ), 'pub_key': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.pub_key, prefix=MinterPrefix.PUBLIC_KEY) ), 'commission': '' if self.commission == 0 else self.commission, 'coin': MinterConvertor.encode_coin_name(self.coin), 'stake': MinterConvertor.convert_value(value=self.stake, to='pip') } }) return struct