Не могу провести операцию в одну транзакцию, может не так ее собираю. Если скрипт делить на части, то транзакция проходит успешно. Если делать за одну, то ошибка выполнения
import json
import time
from web3 import Web3
from web3.exceptions import ContractLogicError
# Configuration
INFURA_URL = ''
PRIVATE_KEY = ''
POOL_ID = id # Указать
CHAIN_ID = 10 # Optimism
# Initialize Web3
web3 = Web3(Web3.HTTPProvider(INFURA_URL))
account = web3.eth.account.from_key(PRIVATE_KEY)
# Addresses
USDC_ADDRESS = Web3.to_checksum_address('0x0b2c639c533813f4aa9d7837caf62653d097ff85')
WETH_ADDRESS = Web3.to_checksum_address('0x4200000000000000000000000000000000000006')
POSITION_MANAGER_ADDRESS = Web3.to_checksum_address('0xC36442b4a4522E871399CD717aBDD847Ab11FE88')
ROUTER_ADDRESS = Web3.to_checksum_address('0xE592427A0AEce92De3Edee1F18E0157C05861564')
# Load ABIs
with open('/position_manager_abi.json', 'r') as file:
position_manager_abi = json.load(file)
with open('/router_abi.json', 'r') as file:
router_abi = json.load(file)
# Contracts
position_manager = web3.eth.contract(address=POSITION_MANAGER_ADDRESS, abi=position_manager_abi)
router = web3.eth.contract(address=ROUTER_ADDRESS, abi=router_abi)
def main():
try:
# Get pool information
position_info = position_manager.functions.positions(POOL_ID).call()
liquidity = position_info[7]
print(f'Current position_info: {position_info}')
print(f'Liquidity: {liquidity}')
if liquidity == 0:
raise ValueError("Liquidity is zero. Cannot decrease liquidity.")
# Increase deadline
deadline = int(time.time()) + 3600 # 1 hour from now
# Encode decreaseLiquidity
decrease_data = position_manager.encodeABI(fn_name='decreaseLiquidity', args=[(
POOL_ID,
liquidity,
0,
0,
deadline
)])
# Encode collect
collect_data = position_manager.encodeABI(fn_name='collect', args=[(
POOL_ID,
ROUTER_ADDRESS,
2**128 - 1,
2**128 - 1
)])
# Encode exactInputSingle for WETH to USDC swap
swap_data = router.encodeABI(fn_name='exactInputSingle', args=[{
'tokenIn': WETH_ADDRESS,
'tokenOut': USDC_ADDRESS,
'fee': 3000,
'recipient': account.address,
'deadline': deadline,
'amountIn': 2**256 - 1, # Max uint, will be limited by actual balance
'amountOutMinimum': 0,
'sqrtPriceLimitX96': 0
}])
# Encode sweepToken for any remaining WETH
sweep_weth = router.encodeABI(fn_name='sweepToken', args=[
WETH_ADDRESS,
0,
account.address
])
# Encode sweepToken for USDC
sweep_usdc = router.encodeABI(fn_name='sweepToken', args=[
USDC_ADDRESS,
0,
account.address
])
# Build multicall transaction for all operations
multicall_data = [
decrease_data,
collect_data,
swap_data,
sweep_weth,
sweep_usdc
]
# Estimate gas for the multicall transaction
estimated_gas = position_manager.functions.multicall(multicall_data).estimate_gas({
'from': account.address,
'nonce': web3.eth.get_transaction_count(account.address),
'gasPrice': web3.eth.gas_price,
'chainId': CHAIN_ID,
})
# Build the transaction
transaction = position_manager.functions.multicall(multicall_data).build_transaction({
'from': account.address,
'nonce': web3.eth.get_transaction_count(account.address),
'gas': int(estimated_gas * 1.2), # Add 20% to the estimated gas
'gasPrice': web3.eth.gas_price,
'chainId': CHAIN_ID,
})
# Sign and send transaction
signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY)
tx_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
print(f'Transaction hash: {tx_hash.hex()}')
# Wait for transaction receipt
txn_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
print(f'Transaction confirmed in block: {txn_receipt.blockNumber}')
# Check transaction status
if txn_receipt['status'] == 1:
print('Transaction was successful')
else:
print('Transaction failed')
raise Exception("Transaction failed")
except ContractLogicError as e:
print(f'Contract logic error: {str(e)}')
except Exception as e:
print(f'An error occurred: {str(e)}')
if __name__ == "__main__":
main()