Giter Club home page Giter Club logo

uniswap-universal-router-decoder's Introduction

  • ๐Ÿ‘‹ Hi, Iโ€™m Elnaril. Nice to see you here! :)
  • ๐Ÿ‘€ Iโ€™m interested in Python and Blockchains
  • ๐Ÿ–ฅ Freelance developer (ex-developer for top European banks), you can find more about my services on Fiverr:

Elnaril profile on Fiverr

uniswap-universal-router-decoder's People

Contributors

elnaril avatar speedssr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

uniswap-universal-router-decoder's Issues

I don't know what is wrong

from uniswap_universal_router_decoder import FunctionRecipient, RouterCodec
from web3 import Account, Web3

private_key = "x"

chain_id = 56
rpc_endpoint = "https://binance.llamarpc.com"
w3 = Web3(Web3.HTTPProvider(rpc_endpoint))
account = Account.from_key(private_key)

amount_in = 1 * 10**27
min_amount_out = 1 * 10**18

token1 = Web3.to_checksum_address('0x55d398326f99059ff775485246999027b3197955')
token2 = Web3.to_checksum_address('0x643D89FBe699068353D24acf55Eb33366d57F533')

path = [token1, token2]

ur_address = Web3.to_checksum_address("0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad")
ur_abi = open("universalRouter.ABI").read()

codec = RouterCodec()

data, signable_message = codec.create_permit2_signable_message(
    token1,
    2**100,  # max = 2**160 - 1
    codec.get_default_deadline(),
    w3.eth.get_transaction_count("0x000000000022D473030F116dDEE9F6B43aC78BA3"),  # Permit2 nonce
    ur_address,  # The UR checksum address
    codec.get_default_deadline(),
    chain_id  # chain id
)

signed_message = Account.sign_message(signable_message, private_key=private_key)

encoded_input = (
        codec.encode.chain().permit2_permit(data, signed_message).v3_swap_exact_in(
        FunctionRecipient.SENDER,
        amount_in,  # in Wei
        w3.to_wei(0, 'gwei'),  # in Wei
        [
            token1,
            1,
            token2,
        ],
    )
        .build(codec.get_default_deadline())
)

trx_params = {
        "from": account.address,
        "to": ur_address,
        "gas": 300000,
        "maxPriorityFeePerGas": w3.eth.max_priority_fee,
        'maxFeePerGas': w3.to_wei(3, 'gwei'),
        # "maxFeePerGas": 100 * 10**9,
        "type": '0x2',
        "chainId": chain_id,
        "value": 0,
        "nonce": w3.eth.get_transaction_count(account.address),
        "data": encoded_input
}


decoded_trx_input = codec.decode.function_input(encoded_input)

print(decoded_trx_input)


raw_transaction = w3.eth.account.sign_transaction(trx_params, account.key).rawTransaction
trx_hash = w3.eth.send_raw_transaction(raw_transaction)
print(trx_hash.hex())

I bought the token manually and I got the data from tx and decode it. It looks like this:
# (<Function execute(bytes,bytes[],uint256)>, {'commands': b'\n\x00', 'inputs': [(<Function PERMIT2_PERMIT(((address,uint256,uint256,uint256),address,uint256),bytes)>, {'struct': {'details': {'token': '0x55d398326f99059fF775485246999027B3197955', 'amount': 1461501637330902918203684832716283019655932542975, 'expiration': 1697657024, 'nonce': 0}, 'spender': '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD', 'sigDeadline': 1695066824}, 'data': b"\x920\xd6\xf4J\xf8a90\xda\xc1u\\\xcc'y\xcf\xa4\x13\x08\xdaR}\x9c\xf2\x00b\xbd\x19\xfb\x1c\xdbY(\x874\xb5\x8c\xf7\xc4\x0cC\xb1g\x03L\x1c\x08\xe0\r\x80\xa9\x8b\xc3i$E\xde\xa0-q\xc2}\x93\x1c"}), (<Function V3_SWAP_EXACT_IN(address,uint256,uint256,bytes,bool)>, {'recipient': '0x0000000000000000000000000000000000000001', 'amountIn': 1000000000000000000, 'amountOutMin': 1359931813892587514595, 'path': b"U\xd3\x982o\x99\x05\x9f\xf7uHRF\x99\x90'\xb3\x19yU\x00\x01\xf4d=\x89\xfb\xe6\x99\x06\x83S\xd2J\xcfU\xeb36mW\xf53", 'payerIsSender': True})], 'deadline': 1695066812})

I tried to encode the things on my side too and got the almost same input for my code:
(<Function execute(bytes,bytes[],uint256)>, {'commands': b'\n\x00', 'inputs': [(<Function PERMIT2_PERMIT(((address,uint256,uint256,uint256),address,uint256),bytes)>, {'struct': {'details': {'token': '0x55d398326f99059fF775485246999027B3197955', 'amount': 1267650600228229401496703205376, 'expiration': 1695372715, 'nonce': 1}, 'spender': '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD', 'sigDeadline': 1695372715}, 'data': b'\x07\xb0\xd5F\x8f\x031a\x9d\xc5\x17\x05D\xfc\xfd\xeaO?\x15p\x95}*H3\xe1=\xc89\xb9E\x0eX\x7f\xefnG\xdc\xc7\x83\xd5\xc6)\xfe\x0f\x03\xe8r\xdd\xd6\xe3i\x94\xd8\x0cL-\x0c\x96?\xe3\xfa\xd8<\x1c'}), (<Function V3_SWAP_EXACT_IN(address,uint256,uint256,bytes,bool)>, {'recipient': '0x0000000000000000000000000000000000000001', 'amountIn': 1000000000000000000000000000, 'amountOutMin': 0, 'path': b"U\xd3\x982o\x99\x05\x9f\xf7uHRF\x99\x90'\xb3\x19yU\x00\x00\x01d=\x89\xfb\xe6\x99\x06\x83S\xd2J\xcfU\xeb36mW\xf53", 'payerIsSender': True})], 'deadline': 1695372715})

but it fails again and again..
I hope you guys know what should I do..

Here my successful tx(manual on uniswap): https://bscscan.com/tx/0x8fa2f34489edce758386692092efb9d9d00a317ac9c72631708540b487051749
Here my failed tx: https://bscscan.com/tx/0xfb62cbcc9f5fad8c5be485129e3105f485018941e2ad78f1dcbf889eba9a70c9

Quick Uniswap version detection

Hi. I'm learning web3.py and came across your library, it's really cool work, thank you! I have a question a bit off-topic, but please answer if you can: if at the moment I buy a token, I only know its address. How can I quickly determine the version of its liquidity pool (uniswap v2 or uniswap v3) to generate a correct transaction? Thanks.

js version

plz cant you make a java script version thnx in advance

The SDK fails to decode input data when there is too many commands.

How to do a swap ?

I would love to see a sample of transaction for a swap, for example :

"""

from uniswap_universal_router_decoder import FunctionRecipient, RouterCodec

codec = RouterCodec()

Permit signature

data, signable_message = codec.create_permit2_signable_message(
"0x...",
amount, # max = 2**160 - 1 (I don't get how to do this part for example)
expiration, (same thing)
nonce, # Permit2 nonce (same thing)
spender, # UR
deadline, (same thing)
1, # chain id
)

Then you need to sign the message:

signed_message = acc.sign_message(signable_message) # where acc is your LocalAccount

Permit + v2 swap encoding

path = [token_in_address, token_out_address]
encoded_data = (
codec
.encode
.chain()
.permit2_permit(data, signed_message)
----Same goes for code below----
.v2_swap_exact_in(FunctionRecipient.SENDER, Wei(10**18), Wei(0), path)

    .build(deadline)

)

Then in your transaction dict:

transaction["data"] = encoded_data

you can now sign and send the transaction to the UR

"""

I would really appreciate, already love your code btw, but I would love to understand it better and use it better :) good job bro

Decoding uniswap v3 Router with 2 swaps

Seems that the lib does not correctly decode for cases where there are 2 swaps in one, here is an example TX:
https://etherscan.io/tx/0x88d143d3b2cb85c2b12610f7d07f237728946ae68eb6c299e0ab31bd338744e0

The output seems pretty strange, and is definitely incorrect for the second leg, where USDT value is very large.

(<Function execute(bytes,bytes[],uint256)>, {'commands': b'\x08\x00', 'inputs': [(<Function V2_SWAP_EXACT_IN(address,uint256,uint256,address[],bool)>, {'recipient': '0x0000000000000000000000000000000000000002', 'amountIn': 20991550410, 'amountOutMin': 0, 'path': ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', '0xdAC17F958D2ee523a2206206994597C13D831ec7'], 'payerIsSender': True}), (<Function V3_SWAP_EXACT_IN(address,uint256,uint256,bytes,bool)>, {'recipient': '0x0000000000000000000000000000000000000001', 'amountIn': 57896044618658097711785492504343953926634992332820282019728792003956564819968, 'amountOutMin': 8116820978936411681401, 'path': b'\xda\xc1\x7f\x95\x8d.\xe5#\xa2 b\x06\x99E\x97\xc1=\x83\x1e\xc7\x00\x0b\xb8aM\xa3\xb3{of\xf7\xcei\xb4\xbb\xbc\xf9\xa5\\\xe6\x16\x87\x07', 'payerIsSender': False})], 'deadline': 1699592747})

Decoding transactions that contain both a V2 and V3 swap

I noticed that for transactions that contain both a V2 and V3 swap, the amount in of the V3 swap seems to be incorrect.

For example - when decoding this:
0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064b6e69300000000000000000000000000000000000000000000000000000000000000030a080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000706abff8bb86ba0b38e66a9043e06a424b9e6bb5000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000064de6c9400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad0000000000000000000000000000000000000000000000000000000064b6e69c00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041865b9acc924bdd22ae665462d588000e268729143cf3ab8b4ea3521092cf14c8065967ac54a7bff61760e63ac2e17e2e9021f07ed8fd1ad818ee9eab82bfeba11b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000083c234736e8c7ddf51900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000706abff8bb86ba0b38e66a9043e06a424b9e6bb5000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000213615bb54a241fe300000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20027106e2a43be0b1d33b726f0ca3b8de60b3482b8b050000000000000000000000000000000000000000000

This decodes to:
(<Function execute(bytes,bytes[],uint256)>, {'commands': b'\n\x08\x00', 'inputs': [(<Function PERMIT2_PERMIT(((address,uint256,uint256,uint256),address,uint256),bytes)>, {'struct': {'details': {'token': '0x706abfF8Bb86bA0b38E66A9043e06a424B9e6BB5', 'amount': 1461501637330902918203684832716283019655932542975, 'expiration': 1692298388, 'nonce': 0}, 'spender': '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD', 'sigDeadline': 1689708188}, 'data': b'\x86[\x9a\xcc\x92K\xdd"\xaefTb\xd5\x88\x00\x0e&\x87)\x14<\xf3\xab\x8bN\xa3R\x10\x92\xcf\x14\xc8\x06Yg\xacT\xa7\xbf\xf6\x17`\xe6:\xc2\xe1~.\x90!\xf0~\xd8\xfd\x1a\xd8\x18\xee\x9e\xab\x82\xbf\xeb\xa1\x1b'}), (<Function V2_SWAP_EXACT_IN(address,uint256,uint256,address[],bool)>, {'recipient': '0x0000000000000000000000000000000000000002', 'amountIn': 40777315588000000000000000000, 'amountOutMin': 0, 'path': ['0x706abfF8Bb86bA0b38E66A9043e06a424B9e6BB5', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'], 'payerIsSender': True}), (<Function V3_SWAP_EXACT_IN(address,uint256,uint256,bytes,bool)>, {'recipient': '0x0000000000000000000000000000000000000001', 'amountIn': 57896044618658097711785492504343953926634992332820282019728792003956564819968, 'amountOutMin': 38289986341071757283, 'path': b"\xc0*\xaa9\xb2#\xfe\x8d\n\x0e\O'\xea\xd9\x08<ul\xc2\x00'\x10n*C\xbe\x0b\x1d3\xb7&\xf0\xca;\x8d\xe6\x0b4\x82\xb8\xb0P", 'payerIsSender': False})], 'deadline': 1689708179})

The amount in and amount outs of the V3 swap are incorrect

This tx is from hash: 0x08689c2b4979df68cd1bb8f6ae675db18a5264a4f14811f5d8fd670192fbc9d7
etherscan: https://etherscan.io/tx/0x08689c2b4979df68cd1bb8f6ae675db18a5264a4f14811f5d8fd670192fbc9d7

Replace deprecated eth_account function

The function eth_account.encode_structured_data() is deprecated in favour of eth_account.messages.encode_typed_data().

The UR SDK is still using encode_structured_data() in RouterCodec.create_permit2_signable_message and thus must be updated with encode_typed_data().

As a source of inspiration, one can look how it was used in the UniswapX SDK.

Is it possible to have the F flag set to 1 so transaction continues on partial reverts ?

I tried changing i.e. 0x08 => 0x88 which executes the comands in the chain fine, but the desired effect of partial revert does not work.

Comands.sol

bytes1 internal constant FLAG_ALLOW_REVERT = 0x80;

Uniswap Technical Reference

F

A single bit flag, that signals whether or not the command should be allowed to revert without the whole transaction failing.

If f is 0 aka false and the command reverts, then the entire transaction will revert and none of the commands will be executed.
If f is 1 aka true and the command reverts, then the transaction will continue, allowing us to achieve partial fills. If using this flag, be careful to include further commands that will remove any funds that could be left unused in the UniversalRouter contract.

Can swap V3 only on Base. V2 Fails

Hello,

For some reason V2 swaps does not work on base chain.

Trying to buy a token 0x850Eaa67cA676B42C0693461848C33dd77249657, smart path returns:
{'path': ('0x850Eaa67cA676B42C0693461848C33dd77249657', '0x4200000000000000000000000000000000000006'), 'function': 'V2_SWAP_EXACT_IN', 'weight': 100, 'estimate': 153192176802} which means a V2 path is available.

I send this:

(<Function execute(bytes,bytes[],uint256)>, {'commands': b'\x0b\x08', 'inputs': [(<Function WRAP_ETH(address,uint256)>, {'recipient': '0x0000000000000000000000000000000000000002', 'amountMin': 1000000000000}, {'revert_on_fail': True}), (<Function V2_SWAP_EXACT_IN(address,uint256,uint256,address[],bool)>, {'recipient': '0x0000000000000000000000000000000000000001', 'amountIn': 1000000000000, 'amountOutMin': 0, 'path': ['0x4200000000000000000000000000000000000006', '0x850Eaa67cA676B42C0693461848C33dd77249657'], 'payerIsSender': False}, {'revert_on_fail': True})], 'deadline': 1714753768})

and it fails TX. Can you spot why is this happening? I have no problems buying tokens with V3 pools.

V2 Deployments on Base Sepolia:

Factory: 0x7Ae58f10f7849cA6F5fB71b7f45CB416c9204b1e

Router :0x1689E7B1F10000AE47eBfE339a4f69dECd19F602

Universal Router: 0x050E797f3625EC8785265e1d9BDd4799b97528A1

Broken Amounts on a tx with multiple swaps

I use version 1.1.0

To reproduce try TX

https://etherscan.io/tx/0x4293ec6511d3d9fba510f3638135f5bdf64205b9328c8165190dbd37d191d0a2

The decoded input will be ->

{
  'commands': b
  '\x08\x00',
  'inputs': [
    (<Function
    V2_SWAP_EXACT_IN(address,
    uint256,
    uint256,
    address
    [],
    bool)>,
    {
      'recipient': '0x0000000000000000000000000000000000000002',
      'amountIn': 25000000000206173218298377997,
      'amountOutMin': 0,
      'path': [
        '0xaaeE1A9723aaDB7afA2810263653A34bA2C21C7a',
        '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
      ],
      'payerIsSender': True
    },
    {
      'revert_on_fail': True
    }
    ),
    (<Function
    V3_SWAP_EXACT_IN(address,
    uint256,
    uint256,
    bytes,
    bool)>,
    {
      'recipient': '0x0000000000000000000000000000000000000001',
      'amountIn': 57896044618658097711785492504343953926634992332820282019728792003956564819968,
      'amountOutMin': 15557248383,
      'path': b
      "\xc0*\xaa9\xb2#\xfe\x8d\n\x0e\\O'\xea\xd9\x08<ul\xc2\x00\x01\xf4\xa0\xb8i\x91\xc6!\x8b6\xc1\xd1\x9dJ.\x9e\xb0\xce6\x06\xebH",
      'payerIsSender': False
    },
    {
      'revert_on_fail': True
    }
    )
  ],
  'deadline': 1710842387
}

Add the support for `PAY_PORTION` and `SWEEP` command

It would be greatly appreciated if you could include support for the PAY_PORTION and SWEEP commands in your library. This would enable us to implement a swap fee feature for the hosted DEXs effectively, as it involves performing three commands simultaneously: one for the swap, another for paying a portion, and the third for sweeping. Unfortunately, Uniswap's documentation does not provide clear instructions on how to achieve this using the 'execute' method. Therefore, it would be highly beneficial if you could incorporate this functionality into your library.

Fetch Permit2 allowance, expiration and nonce

Add a method RouterCodec.fetch_permit2_allowance() that would request the Permit2 contract and return a tuple (allowance, expiration, nonce) for a given (owner, token, spender).

Must be callable for a specific BlockIdentifier but call the latest block by default.

Constants must be defined in _constants.py.

As a parameter of this new method, the default Permit2 address would be 0x000000000022D473030F116dDEE9F6B43aC78BA3 as a ChecksumAddress, but users could call the method with a custom Permit2 address.

As part of the API exposed by this lib, this new method must have a docstring explaining its purpose, parameters and outputs.

Unit tests must be added to keep coverage at 100%

All integration tests where permit2 allowance is requested must be updated with this new method.

The doc (README.md) must be updated to explain the purpose of this new method and illustrate its usage and results.

Decoding issues

NonEmptyPaddingBytes:
Error while decoding trx 0x2b6af8ef8fe18829a0fcf2b0f391c55daf76f53bb68369ecaefdb1f38045f919: Padding bytes were not empty: b'\xc7v\x95\x0f%\x02\xe1\xb7+\xe9\xb2B'
Error while decoding trx 0x806b881b751047a0b84c83d0d4024720f7f736c1c468603bde85a10765567752: Padding bytes were not empty: b'-.\x1b(\x1c\x88\xd9q\x7fS\x88\xaf'
Error while decoding trx 0xabe719c531418ad0c738009ed9e8c545ac0e318ee7482f53439fedfa3d291913: Padding bytes were not empty: b"/\x87.\xca\x08'[pz\x84\xc8w"
Error while decoding trx 0xcab39d096db15a84a0e589e9092fd582ae5c7743c5c296cee3a11d5aa6f070d5: Padding bytes were not empty: b'\x9cw\xfdG\xb6L\xcf|\x14\x19\xce\xc5'

OverflowError:
Error while decoding trx 0x89b6a2a724654f6659dff686a06620a7ebf31cb3a0b708584a5ee36f68a89ddf: cannot fit 'int' into an index-sized integer
Error while decoding trx 0x62198643b5b561689ecde5c47bbed0485de95d8a06205ca8652ddbd9e084389c: cannot fit 'int' into an index-sized integer
Error while decoding trx 0xaa09578416502a1b8ae25cb44d4a4b91853ad6a58e635a92eefd348f83adc41d: cannot fit 'int' into an index-sized integer
Error while decoding trx 0xc94556b28c28b65d34aa54fb5d2bbfdd502253c7aaf01bc3d087ba7ac045f94d: cannot fit 'int' into an index-sized integer

InsufficientDataBytes:
Error while decoding trx 0xd3e1a0ca9c4bc9378e27205aaa0cec7753bb8b315e0ec6bbcf5a7e765a492f13: Tried to read 32 bytes. Only got 0 bytes
Error while decoding trx 0x5d2ce09546ae92f725a1d3913cca696690f846b78c3e47adca584b84dd49b171: Tried to read 32 bytes. Only got 0 bytes
Error while decoding trx 0xa5f1f2fd11f4761bfd1a06966a82fa09e060960aacd445bc30b5042559a7b49c: Tried to read 32 bytes. Only got 0 bytes
Error while decoding trx 0x6b437b6468eb0f48b49f5bc2779539a25122503bfaff4906558d9df245987be1: Tried to read 32 bytes. Only got 0 bytes

permit2_sign not work on bsc

permit_data, signable_message = codec.create_permit2_signable_message(
        approve_token,
        allowance_amount,
        codec.get_default_expiration(365*24*3600),  # 30 days
        p2_nonce,
        UR_ADDRESS,
        codec.get_default_deadline(),  # 180 seconds
        56,
    )

signed_message = client.w3.eth.account.sign_message(signable_message, private_key=wallet_key)

    encoded_input = (
            codec
            .encode
            .chain()
            .permit2_permit(permit_data, signed_message)
            .v2_swap_exact_in(FunctionRecipient.SENDER, amount_in, min_amount_out, path, payer_is_sender=True)
            .build(codec.get_default_deadline())
    )

i used the code to generate permit_data and signed_message, then add permit2_permit(permit_data, signed_message) to the call chain, the transaction fails. but if i signed in the pancake and swap once, then remove the permit2_permit from the sign, the code works like a charm.

Not working

Hi There!
It seams they have changed something in contract logic.
The transaction that passes has data like this:
0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000f2e0200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b3c499c542cef5e3811e1192ce70d8cc03d5c33590000642791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000000000000000000000

Transactions with generated data fail. Generated date is this:
0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000f1b3000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174

v3 path decoding fails for some paths

Example input data:

[(<Function PERMIT2_PERMIT(tuple,bytes)>, {'struct': (('0x0f51bb10119727a7e5eA3538074fb341F56B09Ad', 1461501637330902918203684832716283019655932542975, 1681036949, 0), '0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B', 1678446749), 'data': b'\xb3\xb0b[\xd5\x06\xe7\xb5\xc2\x83\xe4\r\x9dw\xc9\xbb\xee\x9b1G)\xe6$\xb2!\xb5B\xc7w*"\x91_P5\xac\xe9\xac :1\x890}\xd7Rf\x17\xf5\xb5@\x12_$3\xe8\xf4%1\xfa!P\xea\xcd\x1c'}), (<Function V2_SWAP_EXACT_IN(address,uint256,uint256,address[],bool)>, {'recipient': '0x0000000000000000000000000000000000000002', 'amountIn': 3500000000000000000000, 'amountOutMin': 4389999701576844961, 'path': ['0x0f51bb10119727a7e5eA3538074fb341F56B09Ad', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'], 'payerIsUser': True}), (<Function V3_SWAP_EXACT_IN(address,uint256,uint256,bytes,bool)>, {'recipient': '0x0000000000000000000000000000000000000002', 'amountIn': 6500000000000000000000, 'amountOutMin': 8221515176544471463, 'path': b"\x0fQ\xbb\x10\x11\x97'\xa7\xe5\xea58\x07O\xb3A\xf5k\t\xad\x00'\x10\xa0\xb8i\x91\xc6!\x8b6\xc1\xd1\x9dJ.\x9e\xb0\xce6\x06\xebH\x00\x01\xf4\xc0*\xaa9\xb2#\xfe\x8d\n\x0e\O'\xea\xd9\x08<ul\xc2", 'payerIsSender': True}), (<Function UNWRAP_WETH(address,uint256)>, {'recipient': '0x0000000000000000000000000000000000000001', 'amountMin': 12611514878121316424})]

Running decode_v3_path("V3_SWAP_EXACT_IN", b"\x0fQ\xbb\x10\x11\x97'\xa7\xe5\xea58\x07O\xb3A\xf5k\t\xad\x00'\x10\xa0\xb8i\x91\xc6!\x8b6\xc1\xd1\x9dJ.\x9e\xb0\xce6\x06\xebH\x00\x01\xf4\xc0*\xaa9\xb2#\xfe\x8d\n\x0e\\O'\xea\xd9\x08<ul\xc2")

This produces an error:
Exception has occurred: ValueError

Unknown format 02aaa39b223fe8d0a0e5c4f27ead9083c756cc2, attempted to normalize to 0x02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

NOTE:
I'm using w3.toChecksumAddress() due to compatibility issues with my existing code, and not Web3.to_checksum_address()
if that makes any difference.

Universal Router Encoder Doesn't Seem to Work

Versions:

uniswap-universal-router-decoder 0.8.0
web3                             6.0.0b11

I've tried using this encoder a thousand ways. Using a tester blockchain with eth-tester. On Goerli. On Ethereum. Only doing a V2 swap. Only doing a V3 swap. Swapping through WETH with wrap_eth, and swapping between two ERC-20 tokens without it. Not even once have I gotten this encoder to actually work. Sometimes the revert message is stack underflow (0 <=> 1). Other times it's TRANSFER_FAILED. Other times, there's no feedback at all. Please help.

Reproducible Example:

from web3 import Web3
from web3.providers.rpc import HTTPProvider
from uniswap_universal_router_decoder import FunctionRecipient, RouterCodec

rpc_url = ...

w3 = Web3(HTTPProvider(rpc_url))

account_address = Web3.to_checksum_address("0x01DCDb24406CB31C7eC7FcaD7766F6a584D25DE2")

weth_abi = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]'  # noqa

weth_address = Web3.to_checksum_address("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
usdc_address = Web3.to_checksum_address("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
weth_contract = w3.eth.contract(address=weth_address, abi=weth_abi)

ur_address = Web3.to_checksum_address("0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B")


# Verify account has allowances of weth and usdc
weth_allowance = weth_contract.functions.allowance(account_address, ur_address).call()
assert weth_allowance >= 1000

v2_path = [weth_address, usdc_address]
v2_in_amount = 500
v2_out_amount = 0
v3_path = [weth_address, 500, usdc_address]
v3_in_amount = 500
v3_out_amount = 0
total_in_amount = v2_in_amount + v3_in_amount

codec = RouterCodec()

encoded_data = (
    codec
    .encode
    .chain()
    .wrap_eth(FunctionRecipient.ROUTER, total_in_amount)
    .v2_swap_exact_in(FunctionRecipient.SENDER, v2_in_amount, v2_out_amount, v2_path, payer_is_sender=False)
    .v3_swap_exact_in(FunctionRecipient.SENDER, v3_in_amount, v3_out_amount, v3_path, payer_is_sender=False)
    .build(codec.get_default_deadline())
)


tx_params = {
    "from": account_address,
    "to": ur_address,
    "gas": 800_000,
    "maxPriorityFeePerGas": w3.eth.max_priority_fee,
    "maxFeePerGas": int(w3.eth.gas_price * 1.1),
    "type": '0x2',
    "chainId": w3.eth.chain_id,
    "value": total_in_amount,
    "nonce": w3.eth.get_transaction_count(account_address),
    "data": encoded_data,
}

# ContractLogicError
w3.eth.estimate_gas(tx_params)

This example uses a throwaway account without much gas money, but you can always use a different account, as I have, and I assume you'd get the same result. I've never been able to get this encoder to actually work. If I'm missing something obvious, I'd be happy for it to be shown to me.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.