def add_contract(configuration, contract_symbol, contract_address): """ Adds new contract ERC20 token into config file with symbol and address :param configuration: configuration file :param contract_symbol: contract symbol :param contract_address: contract address :return: """ contract = Contract(configuration, contract_address) contract.add_new_contract(contract_symbol, contract_address)
def get_balance(configuration, token_symbol=None): """ Get balance from account address. :param configuration: loaded configuration file instance :param token_symbol: None for ETH, ERC20 symbol for other tokens :return: """ wallet_address = Wallet(configuration).get_address() if token_symbol is None: balance = Wallet(configuration).get_balance(wallet_address) else: contract_address = configuration.contracts[token_symbol] contract = Contract(configuration, contract_address) balance = contract.get_balance(wallet_address) return balance, wallet_address
def get_balance(configuration, token_symbol=None): """ Get balance from account address. :param configuration: loaded configuration file instance :param token_symbol: None for ETH, ERC20 symbol for other tokens :return: """ wallet_address = Wallet(configuration).get_address() if token_symbol is None: balance = Wallet(configuration).get_balance(wallet_address) else: try: # check if token is added to the wallet contract_address = configuration.contracts[token_symbol] except KeyError: raise ERC20NotExistsException() contract = Contract(configuration, contract_address) balance = contract.get_balance(wallet_address) return balance, wallet_address
def send_transaction( configuration, keystore_password, to_address, value, token_symbol=None, gas_price_speed=20 # MetaMask default transaction speedup is gasPrice*10 ): """ Sign and send transaction :param configuration: loaded configuration file instance :param keystore_password: password from encrypted keystore with private key for transaction sign :param to_address: address in hex string where originator's funds will be sent :param value: amount of funds to send in ETH or token defined in token_symbol :param token_symbol: None for ETH, ERC20 symbol for other tokens transaction :param gas_price_speed: gas price will be multiplied with this number to speed up transaction :return: tuple of transaction hash and transaction cost """ # my MetaMask address: 0xAAD533eb7Fe7F2657960AC7703F87E10c73ae73b wallet = Wallet(configuration).load_keystore(keystore_password) w3 = Infura().get_web3() transaction = Transaction(account=wallet.get_account(), w3=w3) # check if value to send is possible to convert to the number try: float(value) except ValueError: raise InvalidValueException() if token_symbol is None: # create ETH transaction dictionary tx_dict = transaction.build_transaction( to_address=to_address, value=Web3.toWei(value, "ether"), gas= 21000, # fixed gasLimit to transfer ether from one EOA to another EOA (doesn't include contracts) gas_price=w3.eth.gasPrice * gas_price_speed, # be careful about sending more transactions in row, nonce will be duplicated nonce=w3.eth.getTransactionCount(wallet.get_address()), chain_id=configuration.network) else: # create ERC20 contract transaction dictionary try: # check if token is added to the wallet contract_address = configuration.contracts[token_symbol] except KeyError: raise ERC20NotExistsException() contract = Contract(configuration, contract_address) erc20_decimals = contract.get_decimals() token_amount = int(float(value) * (10**erc20_decimals)) data_for_contract = Transaction.get_tx_erc20_data_field( to_address, token_amount) # check whether there is sufficient ERC20 token balance erc20_balance, _ = WalletAPI.get_balance(configuration, token_symbol) if float(value) > erc20_balance: raise InsufficientERC20FundsException() # calculate how much gas I need, unused gas is returned to the wallet estimated_gas = w3.eth.estimateGas({ 'to': contract_address, 'from': wallet.get_address(), 'data': data_for_contract }) tx_dict = transaction.build_transaction( to_address= contract_address, # receiver address is defined in data field for this contract value= 0, # amount of tokens to send is defined in data field for contract gas=estimated_gas, gas_price=w3.eth.gasPrice * gas_price_speed, # be careful about sending more transactions in row, nonce will be duplicated nonce=w3.eth.getTransactionCount(wallet.get_address()), chain_id=configuration.network, data=data_for_contract) # check whether to address is valid checksum address if not Web3.isChecksumAddress(to_address): raise InvalidAddress() # check whether there is sufficient eth balance for this transaction balance, _ = WalletAPI.get_balance(configuration) transaction_const_wei = tx_dict['gas'] * tx_dict['gasPrice'] transaction_const_eth = w3.fromWei(transaction_const_wei, 'ether') if token_symbol is None: if (transaction_const_eth + Decimal(value)) > balance: raise InsufficientFundsException() else: if transaction_const_eth > balance: raise InsufficientFundsException() # send transaction tx_hash = transaction.send_transaction(tx_dict) print('Pending', end='', flush=True) while True: tx_receipt = w3.eth.getTransactionReceipt(tx_hash) if tx_receipt is None: print('.', end='', flush=True) time.sleep(1) else: print('\nTransaction mined!') break return tx_hash, transaction_const_eth