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))
}
}
}