def transferERCToken(fromAddr, toAddr, amt, key, symbol): try: w3 = getW3() availableBalance = getWalletTokenBalance(fromAddr, symbol) if amt > availableBalance: return 'Error: Not enough funds.' contract_address = getTokenAddress(symbol) abi_json = getContractAbiJson('ERC20') abi = abi_json erc20_token_contract = getContract(w3, abi, contract_address) nonce = w3.eth.getTransactionCount(fromAddr) amount = convertAmountToWei(symbol, amt) transfer_tx = erc20_token_contract.functions.transfer( toAddr, int(amount)).buildTransaction({ 'chainId': getChainId(), # 1 for mainnet, 3 for ropsten 'gas': 220920, 'gasPrice': w3.toWei(150, 'gwei'), 'nonce': nonce }) signed_txn = w3.eth.account.sign_transaction(transfer_tx, key) try: tx_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction) return w3.toHex(tx_hash) except ValueError as err: return 'Error: ' + str(err) except Exception as ex: return 'Error: ' + str(ex)
def approve(userAddress, tokenSymbol, smartContractAddress, amountToApprove, key, protocol=''): try: if int( amountToApprove ) < 1000000000: #avoid multiple approve charges but up to 1000 USDC amountToApprove = 1000000000 w3 = getW3() contract_address = getTokenAddress(tokenSymbol, protocol) abi_json = getContractAbiJson('ERC20') abi = abi_json erc20_contract = getContract(w3, abi, contract_address) nonce = w3.eth.getTransactionCount(userAddress) appr_tx = erc20_contract.functions.approve( Web3.toChecksumAddress(smartContractAddress), int(amountToApprove)).buildTransaction({ 'chainId': getChainId(), 'gas': 2209200, 'gasPrice': w3.toWei(150, 'gwei'), 'nonce': nonce }) signed_tx = w3.eth.account.signTransaction(appr_tx, key) tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction) return w3.toHex(tx_hash) except Exception as ex: return str(ex)
def getWalletTokenBalance(addr, erc20Token): w3 = getW3() contract_address = getTokenAddress(erc20Token) abi_json = getContractAbiJson('ERC20') abi = abi_json erc20_token_contract = getContract(w3, abi, contract_address) raw_balance = erc20_token_contract.functions.balanceOf(addr).call() return convertAmountFromWei(erc20Token, raw_balance)
def isApproved(userAddress, tokenSymbol, smartContractAddress, amount, protocol=''): w3 = getW3() contract_address = getTokenAddress(tokenSymbol, protocol) abi_json = getContractAbiJson('ERC20') abi = abi_json erc20_contract = getContract(w3, abi, contract_address) approved_amount = erc20_contract.functions.allowance( userAddress, smartContractAddress).call() return approved_amount >= amount
def getAmountsOut(self, token_symbol, token_amount): # function getAmountsOut(uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) userToken = app.config['SYMB'] # token user owns amount = convertAmountToWei(userToken, token_amount) w3 = getW3() abi_json = getContractAbiJson('UNI') abi = abi_json['abi'] uniswap_contract = getContract(w3, abi, self.UNISWAP_CONTRACT_ADDR) addressPaths = [Web3.toChecksumAddress(getTokenAddress(userToken, 'UNI')), Web3.toChecksumAddress(getTokenAddress('WETH', 'UNI')), Web3.toChecksumAddress(getTokenAddress(token_symbol, 'UNI'))] amountsOut = uniswap_contract.functions.getAmountsOut( int(amount), addressPaths).call() return convertAmountFromWei(token_symbol, amountsOut[2])
def tradeToken(self, token_symbol, token_amount): userToken = app.config['SYMB'] # token user owns availableBalance = getWalletTokenBalance(self.userWallet.address, userToken) if (availableBalance < token_amount): return "Insuficent amount in your wallet" uni_contract_address = self.UNISWAP_CONTRACT_ADDR # convert in underlying token balance amount = convertAmountToWei(userToken, token_amount) if not isApproved(self.userWallet.address, userToken, uni_contract_address, amount, 'UNI'): approve(userWall.address, userToken, uni_contract_address, amount, self.userWallet.privateKey, 'UNI') w3 = getW3() abi_json = getContractAbiJson('UNI') abi = abi_json['abi'] uniswap_contract = getContract(w3, abi, uni_contract_address) nonce = w3.eth.getTransactionCount(self.userWallet.address) # function swapExactTokensForTokens # uint amountIn, # uint amountOutMin, # address[] calldata path, # address to, # uint deadline # ) external returns (uint[] memory amounts); amountOutMin = int( amount) * 0.0098 # __convertAmountToWei('DAI', amt/2) addressPaths = [ Web3.toChecksumAddress(getTokenAddress(userToken, 'UNI')), Web3.toChecksumAddress(getTokenAddress(token_symbol, 'UNI')) ] # current_time = datetime.datetime.now(datetime.timezone.utc) # unix_timestamp = current_time.timestamp() # works if Python >= 3.3 # deadline = int(unix_timestamp + (20 * 60)) # 20 minutes deadline = int(time.time()) + 10000 trade_tx = uniswap_contract.functions.swapExactTokensForTokens( int(amount), int(amountOutMin), addressPaths, self.userWallet.address, deadline).buildTransaction({ 'chainId': getChainId(), 'gas': 5000000, 'gasPrice': w3.toWei('20', 'gwei'), 'nonce': nonce }) signed_txn = w3.eth.account.sign_transaction( trade_tx, self.userWallet.privateKey) try: tx = w3.eth.sendRawTransaction(signed_txn.rawTransaction) # return tx.hex() try: txn_receipt = w3.eth.waitForTransactionReceipt(tx, timeout=300) except Exception: return {'status': 'failed', 'error': 'timeout'} else: return {'status': 'success', 'receipt': txn_receipt} except ValueError as err: # return (json.loads(str(err).replace("'", '"')), 402, {'Content-Type': 'application/json'}) return 'Error: ' + str(err)