Encountering an issue with ‘transaction_count’ in the basic_ethereum example while using Uniswap on the Sepolia testnet

So I made some changes to basic_ethereum example and got following error message while calling ‘swap_eth_to_usdc’

Error message I am getting:

Error: Failed update call.
Caused by: The replica returned a rejection error: reject code CanisterError, reject message Error from Canister zkrig-uqaaa-aaaap-qkmiq-cai: Canister called `ic0.trap` with message: Panicked at 'failed to get transaction count for GetTransactionCountArgs { address: "0x7C92eB543Fd4Ec33678bC5f0492159F11B0B5DE3", block: Latest }, error: (CanisterError, "failed to decode canister response as (evm_rpc_canister_types::MultiGetTransactionCountResult,): Fail to decode argument 0")', src/lib.rs:461:13
Canister Backtrace:
ic_cdk::api::trap
ic_cdk::printer::set_panic_hook::{{closure}}
std::panicking::rust_panic_with_hook
std::panicking::begin_panic_handler::{{closure}}
std::sys::backtrace::__rust_end_short_backtrace
rust_begin_unwind
core::panicking::panic_fmt
basic_ethereum::transaction_count::{{closure}}
basic_ethereum::__canister_method_swap_eth_to_usdc::{{closure}}
ic_cdk::futures::waker::wake
ic_cdk::api::call::callback


call_on_cleanup also failed:

Canister called `ic0.trap` with message: Panicked at 'failed to get transaction count for GetTransactionCountArgs { address: "0x7C92eB543Fd4Ec33678bC5f0492159F11B0B5DE3", block: Latest }, error: (NoError, "cleanup")', src/lib.rs:461:13
Canister Backtrace:
ic_cdk::api::trap
ic_cdk::printer::set_panic_hook::{{closure}}
std::panicking::rust_panic_with_hook
std::panicking::begin_panic_handler::{{closure}}
std::sys::backtrace::__rust_end_short_backtrace
rust_begin_unwind
core::panicking::panic_fmt
basic_ethereum::transaction_count::{{closure}}
basic_ethereum::__canister_method_swap_eth_to_usdc::{{closure}}
ic_cdk::futures::waker::wake
ic_cdk::api::call::cleanup
, error code None

The code I added for Uniswap:

#[update]
pub async fn swap_eth_to_usdc() → String {
let caller = validate_caller_not_anonymous();
let wallet = EthereumWallet::new(caller).await;
let chain_id = read_state(|s| s.ethereum_network().chain_id());
let nonce = nat_to_u64(transaction_count(Some(caller), Some(BlockTag::Latest)).await);
let (gas_limit, max_fee_per_gas, max_priority_fee_per_gas) = estimate_transaction_fees();

let uniswap_router_address = "0xC532a74256D3Db42D0Bf7a0400fEFDbad7694008".parse().unwrap();

let usdc_address = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238".parse().unwrap();

let weth_address = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14".parse().unwrap();

let amount_in_eth = U256::from(10_000_000_000_000_000_u128); // 0.01 ETH

let path = vec![weth_address, usdc_address];

let mut data = vec![0x7f, 0xff, 0xff, 0xff];
data.extend_from_slice(&[0u8; 32]);
data.extend_from_slice(&encode_path(&path));
data.extend_from_slice(wallet.ethereum_address().as_ref());
data.extend_from_slice(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); // deadline

let transaction = TxEip1559 {
    chain_id,
    nonce,
    gas_limit,
    max_fee_per_gas,
    max_priority_fee_per_gas,
    to: TxKind::Call(uniswap_router_address),
    value: amount_in_eth,
    access_list: Default::default(),
    input: data.into(),
};

let tx_hash = transaction.signature_hash().0;
let (raw_signature, recovery_id) = wallet.sign_with_ecdsa(tx_hash).await;
let signature = Signature::from_bytes_and_parity(&raw_signature, recovery_id.is_y_odd())
    .expect("BUG: failed to create a signature");
let signed_tx = transaction.into_signed(signature);

let raw_transaction_hash = *signed_tx.hash();
let mut tx_bytes: Vec<u8> = vec![];
TxEnvelope::from(signed_tx).encode_2718(&mut tx_bytes);
let raw_transaction_hex = format!("0x{}", hex::encode(&tx_bytes));
ic_cdk::println!(
    "Sending raw transaction hex {} with transaction hash {}",
    raw_transaction_hex,
    raw_transaction_hash
);

let single_rpc_service = read_state(|s| s.single_evm_rpc_service());
let (result,) = EVM_RPC
    .eth_send_raw_transaction(
        single_rpc_service,
        None,
        raw_transaction_hex.clone(),
        2_000_000_000_u128,
    )
    .await
    .unwrap_or_else(|e| {
        panic!(
            "failed to send raw transaction {}, error: {:?}",
            raw_transaction_hex, e
        )
    });
ic_cdk::println!(
    "Result of sending raw transaction {}: {:?}.",
    raw_transaction_hex,
    result
);

raw_transaction_hash.to_string()

fn encode_path(path: &[AlloyAddress]) → Vec {
let mut encoded = Vec::new();
for address in path {
encoded.extend_from_slice(&address.0[…]); // Use the underlying byte array
}
encoded
}

My lib.rs code if reuired: src/lib.rs:447 - src/lib.rs:477

#[update]
pub async fn transaction_count(owner: Option<Principal>, block: Option<BlockTag>) -> Nat {
    let caller = validate_caller_not_anonymous();
    let owner = owner.unwrap_or(caller);
    let wallet = EthereumWallet::new(owner).await;
    let rpc_services = read_state(|s| s.evm_rpc_services());
    let args = GetTransactionCountArgs {
        address: wallet.ethereum_address().to_string(),
        block: block.unwrap_or(BlockTag::Finalized),
    };
    let (result,) = EVM_RPC
        .eth_get_transaction_count(rpc_services, None, args.clone(), 2_000_000_000_u128)
        .await
        .unwrap_or_else(|e| {
            panic!(
                "failed to get transaction count for {:?}, error: {:?}",
                args, e
            )
        });
    match result {
        MultiGetTransactionCountResult::Consistent(consistent_result) => match consistent_result {
            GetTransactionCountResult::Ok(count) => count,
            GetTransactionCountResult::Err(error) => {
                ic_cdk::trap(&format!("failed to get transaction count for {:?}, error: {:?}",args, error))
            }
        },
        MultiGetTransactionCountResult::Inconsistent(inconsistent_results) => {
            ic_cdk::trap(&format!("inconsistent results when retrieving transaction count for {:?}. Received results: {:?}", args, inconsistent_results))
        }
    }
}

Are you using evm-rpc-types that is part of the evm-rpc-canister repository?

Or are you using evm-rpc-canister-types? This one is out dated and not officially supported by our team.

I was using ‘evm-rpc-canister-types’ as it was mentioned in the basic_ethereum example on github basic_ethereum