Selling tokens and get BNB instead of wBNB? - python

I made a function that sells a token in the BSC smartchain. However, I want to receive it in BNB directly instead of wBNB. How can I unwrap the wBNB I receive?
def sell_drdc(wallet_address, token_address, wallet_no):
if not is_approved(token_address):
approve(wallet_address, private_key)
erc20 = web3.eth.contract(token_address, abi=erc20Abi)
token_value = erc20.functions.balanceOf(wallet_address).call()
if token_value != 0:
pancakeswap2_txn = router.functions.swapExactTokensForTokensSupportingFeeOnTransferTokens (token_value, 0, [DRDC_Address, wbnb_contract], wallet_address, (int(time()) + 900)).buildTransaction({
'from': wallet_address,
'nonce': web3.eth.get_transaction_count(wallet_address),
})
signed_txn = web3.eth.account.sign_transaction(pancakeswap2_txn, private_key=private_key)
try:
tx_token = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
web3.eth.waitForTransactionReceipt(tx_token, timeout=900)
display_success() # Just function that sends success message
update_text()
except ValueError:
display_error() # Just a function that sends the error
except UnboundLocalError:
sell_drdc(wallet_address, token_address, wallet_no) # Attempts to repeat if something goes wrong

I managed to see what's wrong, It should be
swapExactTokensForETHSupportingFeeOnTransferTokens

Related

web3py with 0x API

I have been trying to perform a swap on Ropsten using the 0x API to get the best quote but every time I try to perform a swap the transaction fails without any feedback(at least from Etherscan) while the approve tx goes through fine.
I am probably missing something here, but I'm getting blind to keep staring at my code.
import requests
import json
import time
from web3 import Web3
walletAddress = 'mywalletaddress'
wpk = 'myprivatekey'
# Setup Ropsten provider
w3 = Web3(Web3.HTTPProvider('https://ropsten.infura.io/v3/'))
# Get the nonce to prevent from sending the transaction twice
nonce = w3.eth.getTransactionCount(walletAddress)
print('Nonce:', nonce)
# Store the generic ERC20 abi for later use
ABI = json.load(open('abi.json'))
# ROPSTEN ADDRESSES
WETH = Web3.toChecksumAddress('0xc778417e063141139fce010982780140aa0cd5ab')
DAI = Web3.toChecksumAddress('0xad6d458402f60fd3bd25163575031acdce07538d')
USDC = Web3.toChecksumAddress('0x07865c6e87b9f70255377e024ace6630c1eaa37f')
def calcAmount(initialAmount, contractAddress):
contract = w3.eth.contract(address=contractAddress, abi=ABI)
decimals = contract.functions.decimals().call()
amount = int(initialAmount * 10**decimals)
return amount
print(decimals, amount)
def getTokenSymbol(contractAddress):
contract = w3.eth.contract(address=contractAddress, abi=ABI)
tokenSymbol = contract.functions.symbol().call()
return tokenSymbol
print('Symbol:', tokenSymbol)
# Define query parameters
initialAmount = 100
slippage = '0.01' # 0.01 = 1% slippage
sellAmount = calcAmount(initialAmount, USDC)
print('Sell:', sellAmount)
def approve(token, spenderAddress, walletAddress, wpk):
token = Web3.toChecksumAddress(token)
contract = w3.eth.contract(address=token, abi=ABI)
spender = Web3.toChecksumAddress(spenderAddress)
max_amount = Web3.toWei(2**64 - 1, 'ether')
nonce = w3.eth.getTransactionCount(walletAddress)
tx = contract.functions.approve(spender, max_amount).buildTransaction({
'from': walletAddress,
'nonce': nonce
})
signed_tx = w3.eth.account.signTransaction(tx, wpk)
tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
print("Approve", w3.toHex(tx_hash))
w3.eth.wait_for_transaction_receipt(tx_hash)
def getQuote(buyToken, slippage, sellToken, sellAmount):
# Make the query https://ropsten.api.0x.org/
query = 'https://ropsten.api.0x.org/swap/v1/quote?buyToken={}&slippage={}&sellToken={}&sellAmount={}'.format(buyToken, slippage, sellToken, sellAmount)
# Get the query and store the response in data
response = requests.get(query)
data = response.json()
# Print a prettiefied version of the response (optional)
print(json.dumps(data, indent=2))
# Convert the buyAmmount to integer
buyAmount = int(data['buyAmount'])
# Convert the buyAmount to a readable number
finalPrice = calcAmount(buyAmount, buyToken)
# Get the symbol of the 2 tokens
buyTokenSymbol = getTokenSymbol(buyToken)
sellTokenSymbol = getTokenSymbol(sellToken)
print(sellTokenSymbol, '->', buyTokenSymbol)
approve(data['sellTokenAddress'], data['allowanceTarget'], walletAddress, wpk)
tx = {
"from": walletAddress,
"to": Web3.toChecksumAddress(data['to']),
"data": data['data'],
"value": 0,
"gas": int(data['gas']),
"gasPrice": int(data['gasPrice']),
"nonce": nonce + 1,
"chainId": data['chainId']
}
# sign the transaction
signed_tx = w3.eth.account.sign_transaction(tx, wpk)
#
# send transaction
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
#
# get transaction hash
print(w3.toHex(tx_hash))
# Use only for testing the query
getQuote(DAI, slippage, USDC, sellAmount)
As you can see I am trying to swap USDC for DAI using the 0x API.
The first tx generated is approved
Etherscan approval tx
But the actual swap fails without any feedback
Etherscan swap tx
I honestly don't know what to try anymore...I've been digging both documentation and reading anything I could find on Stackoverflow without any luck.
Any help is greatly appreciate.
Gas Limit & Usage by Txn: 134,523 | 132,823 (98.74%)
Im 99,9% sure it is because ur running out of gas, try to increase it

web3 python getAmountsOut execution reverted

I managed to set up this function that returns the token value in USD of a contract, everything works fine in some contracts, but in other contracts I get the error "execution reverted" when calling the function "getAmountsOut" does anyone have any idea what it can be? I get the contracts from the same place in bscscan and for some it works and for some it doesn't.
bsc = 'https://bsc-dataseed.binance.org/'
web3 = Web3(Web3.HTTPProvider(bsc))
panRouterContractAddress = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
panabi = '[{...}]'
contractbuy = web3.eth.contract(address=panRouterContractAddress, abi=panabi) # PANCAKESWAP
def get_price(self):
try:
# Base currency token instantiate and ABI
baseCurrency = web3.toChecksumAddress("0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56") # BUSD
# get symbol token
sellTokenContract = web3.eth.contract(self.token_to_buy, abi=sellAbi)
symbol = sellTokenContract.functions.symbol().call()
# Selling token instance and contract
tokenToSell = web3.toChecksumAddress(self.token_to_buy) # TOKEN PRICE
sellAmount = web3.toWei(1, 'ether')
# Calculate minimum amount of tokens to receive
amountOut = contractbuy.functions.getAmountsOut(sellAmount, [tokenToSell, baseCurrency]).call() # Error here
amountOutMin = web3.fromWei(int(amountOut[1]), 'ether')
print("Valor do token: ", str(amountOutMin))
str_format = "{:." + self.decs_usd + "f}"
return float(str_format.format(amountOutMin)), symbol
except Exception as ex:
print("ERRO:ver_preco:", ex)
return "", ""
contracts ok:
https://bscscan.com/address/0x5649e392a1bac3e21672203589adf8f6c99f8db3
https://bscscan.com/address/0x00e1656e45f18ec6747f5a8496fd39b50b38396d
contracts error:
https://bscscan.com/address/0x9376e6b29b5422f38391a2a315623cb853c3c68e
https://bscscan.com/address/0xe786d5a4b985bfe5e371f8e94413cfb440f6618a
if anyone can explain to me why this error occurs in some tokens and not others, and how I can get error message details besides "execution reverted"
The latter specified token addresses fail with the error because there is no existing Pancakeswap pair contract for the specified address combination.
Another way of checking the existence of a pair contract is by calling the factory's getPair() function.
// returns the existing pair contract address 0x5f7A2a0A32C0616898cA7957C1D58BC92a7E2f6f
getPair(
// ZDC token specified in your question as OK
"0x5649e392A1BAC3e21672203589aDF8f6C99f8dB3",
// BUSD
"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56"
)
// returns the zero address 0x0000000000000000000000000000000000000000
// because there's no pair contract for these specified tokens
getPair(
// DGZV token specified in your question as NOTOK
"0x9376E6B29b5422f38391A2a315623cB853c3c68e",
// BUSD
"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56"
)

How to continuously keep track of balance of a particular token in my wallet

I'm trying to create a bot which keeps a track of a particular token in my wallet. As soon as it detects the token, it should send the token to another address. I've written the code but i don't know why my while loop doesn't work. The code kind of skips the while loop and creates the transaction at the end anyway which results in an error since there is no token to transfer. The script should be stuck in a loop until there is some token balance but it isn't happening.I'm running this on a VS Code terminal.
from web3 import Web3
import json
bsc = "https://bsc-dataseed.binance.org/"
web3 = Web3(Web3.HTTPProvider(bsc))
print(web3.isConnected())
main_address = "wallet to be tracked"
contract_address = "token contract address"
abi = json.loads('the abi')
contract = web3.eth.contract(address=contract_address, abi = abi)
balanceOfToken = contract.functions.balanceOf(main_address).call()
print(web3.fromWei(balanceOfToken, 'ether'))
while(True):
balanceOfToken = contract.functions.balanceOf(main_address).call()
print(balanceOfToken)
if(balanceOfToken > web3.fromWei(0.5, 'ether')):
break
continue
second_address = "the other wallet address"
main_key = "private key of first wallet"
nonce = web3.eth.getTransactionCount(main_address)
token_tx = contract.functions.transfer(my_address, balanceOfToken).buildTransaction({
'chainId':56, 'gas': 90000, 'gasPrice': web3.toWei('5', 'gwei'), 'nonce':nonce
})
signed_tx = web3.eth.account.signTransaction(token_tx, main_key)
web3.eth.sendRawTransaction(signed_tx.rawTransaction)
print(contract.functions.balanceOf(my_address).call() + " " + contract.functions.name().call())
The value of web3.fromWei(0.5, 'ether') is Decimal('5E-19') (from trying out the API myself).
The value of balanceOfToken is 10^-18 (from discussion in comments).
Since 10^-18 is bigger then 5 * 10^-19, the condition if(balanceOfToken > web3.fromWei(0.5, 'ether')) evaluates to True and the loop exits.

How to reconnect after a ServerDisconnectedError or ServerTimeoutError in "await asyncio.gather(*tasks)" when using aiohttp.ClientSession()?

So, I'm trying to repeat a failed loop, because of errors such as ServerDisconnectedError and ServerTimeoutError, but I not getting it. Basically, what I'm doing is sending product codes to an endpoint that will return me some information about each one. I'm using asyncio.ensure_future to create the tasks and await asyncio.gather(*tasks) do the tasks (I'm not really familiar with asyncio and aiohttp functions, so I might be wrong in this explanation).
The ETL is running perfectly, the problem is the bigger is the chunk_size (amount of product code to be sent to the endpoint) the higher is the probability to get a ServerDisconnectedError or ServerTimeoutError during the loop. I can catch both of these two exceptions, the problem is, once I repeat the loop with "continue" it looks like the repeated loop doesnt work the properly (taking just a few time to send the same chunk of codes that took a good time running the first time), continually showing me the same excepetions I got the first time of the round. I don't know what to do, if I must reconnect the server once disconnected or anything else. I need to repeat the loop that failed and send again the chunk of product codes to the endpoint, as it did for the first time, in an attempt to acquire the information from this endpoint. Could anybody help with that? I hope I have been clear in the explanation of the problem.
So, this is the code:
async def get_all_balance(session, url, headers, product_code, company_code, balance_code):
async with session.post(url,
data=json.dumps(
{'products': [product_code], 'companies': company_code, 'cdBalance': balance_code, 'inStock': 1, 'inSalesOrder': 1}),
headers=headers) as resp:
if resp.status == 200:
data = await resp.read()
product_balance = json.loads(data.decode("utf-8"))
for data in product_balance['saldos']:
lst_balance.append({
"cd_SKU": data.get('cdSKU'),
"cd_product": data.get('cdProduct'),
"cd_reference": data.get('cdReference'),
"cd_color": data.get('cdColor'),
"ds_size": data.get('dsSize'),
"cd_company": data.get('cdCompany'),
"nr_CNPJ_company": data.get('nrCNPJCompany'),
"qt_stock": data.get('qtStock'),
"qt_sales_order": data.get('qtSalesOrder'),
"cd_balance": codigo_balance
})
else:
print("Resp.Status: {}".format(resp.status))
async def main():
token = get_token() # Get a token to access the endpoint
headers = {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
}
async with aiohttp.ClientSession() as session:
lst_dict_cd_product = get_product_balance() # Get a list of dicts containing the product codes such as [{"cdProduto": "13889"}, {"cdProduto": "059788"}, ...]
print("Qt products: " + str(len(lst_dict_cd_product)))
tasks_balance = []
lst_companies = [{"cdCompany": 1}, {"cdCompany": 2}, ...]
lst_codigo_balance = [1, 11, 14] # A balance code to be sent to the endpoint as a part of the payload
chunk_size = 30000
count = 0
num_chunks = len(lst_dict_cd_product) / chunk_size
mod_chunks = len(lst_dict_cd_product) % chunk_size
# print(num_chunks)
# print(mod_chunks)
if mod_chunks != 0:
print(int(num_chunks) + 1)
else:
print(int(num_chunks))
for balance_code in lst_balance_code:
if balance_code == 1:
company_code= lst_companies[0:]
print(company_code)
else:
company_code= lst_companies[0:1]
print(company_code)
for start in range(0, len(lst_dict_cd_product), chunk_size):
end = start + chunk_size
# print(lst_dict_cd_product[start:end]) # item chunks
lst_product_code = lst_dict_cd_product[start:end]
print("Chunks : {} of {} round {} s:e{}".format(
start, end, count, str(lst_codigo_product[0]) + ":" + str(lst_codigo_product[-1])))
if count != 0:
time.sleep(60)
k=0
while k < 1:
for product_code in lst_codigo_product:
url = 'https://www30.bhan.com.br:9443/api/v1/produto/saldoproduto'
balance_tasks.append(asyncio.ensure_future(
get_all_balance(session, url, headers, product_code, company_code, balance_code))) # emp_all[0:]
try:
await asyncio.gather(*balance_tasks)
count += 1
k += 1
except Exception as e:
continue
# Save a json file
asyncio.run(main())
```python
Make an infinite loop:
import time
connection = None
while(True):
connection = try_connect()
if connection:
break # Get out of the loop.
time.sleep(2) # Seconds.
do_someting(connection)
EDIT:
def try_connect():
try:
connection = ... # get connection.
except [failed_connection_exception_type]:
return False
else:
return connection
EDIT 2:
Short version
import time
connection = None
while(True):
try:
connection = ... # get connection.
except [exception_type_to_catch]:
time.sleep(2) # Seconds.
continue
else:
break
do_someting(connection)

iot edge direct method handler in python

I have created a module for a Bacnet scan and it will respond with a list of devices and its address as a result. But I'm having trouble implementing a direct method handler in python. When i first tried implementing it myself i got this error. Which could mean I didn't successfully register the direct method callback. I have some references but it was from C# and azure docs is not helping me figure out the right method to register the callback. for IoTHubModuleClient there's a on_method_request_received and a receive_method_request. appreciate any help!
def iothub_client_scan_run():
try:
iot_client = iothub_client_init()
bacnet_scan_listener_thread = threading.Thread(target=device_method_listener, args=(iot_client,))
bacnet_scan_listener_thread.daemon = True
bacnet_scan_listener_thread.start()
while True:
time.sleep(1000)
def device_method_listener(iot_client):
while True:
# Receive the direct method request
method_request = iot_client.receive_method_request()
print (
"\nMethod callback called with:\nmethodName = {method_name}\npayload = {payload}".format(
method_name=method_request.name,
payload=method_request.payload
)
)
if method_request.name == "runBacnetScan":
response = bacnet_scan_device(method_request)
else:
response_payload = {"Response": "Direct method {} not defined".format(method_request.name)}
response_status = 404
# Send a method response indicating the method request was resolved
print('Sending method response')
iot_client.send_method_response(response)
print('Message sent!')
Edit:
Here is my route config
I was able to resolve my issue or at least find the root cause and it was my network configuration under the createOptions. It seems like there's an issue when I'm trying to do NetworkMode: host and connects to the IotModuleClient.connect_from_edge_environment via connect with connection string. I'm still trying to tweak the connection configuration but at least i know its not on the code.
async def method_request_handler(module_client):
while True:
method_request = await module_client.receive_method_request()
print (
"\nMethod callback called with:\nmethodName = {method_name}\npayload = {payload}".format(
method_name=method_request.name,
payload=method_request.payload
)
)
if method_request.name == "method1":
payload = {"result": True, "data": "some data"} # set response payload
status = 200 # set return status code
print("executed method1")
elif method_request.name == "method2":
payload = {"result": True, "data": 1234} # set response payload
status = 200 # set return status code
print("executed method2")
else:
payload = {"result": False, "data": "unknown method"} # set response payload
status = 400 # set return status code
print("executed unknown method: " + method_request.name)
# Send the response
method_response = MethodResponse.create_from_method_request(method_request, status, payload)
await module_client.send_method_response(method_response)
print('Message sent!')
def stdin_listener():
while True:
try:
selection = input("Press Q to quit\n")
if selection == "Q" or selection == "q":
print("Quitting...")
break
except:
time.sleep(10)
# Schedule task for C2D Listener
listeners = asyncio.gather(input1_listener(module_client), twin_patch_listener(module_client), method_request_handler(module_client))

Categories