Announcing ic-alloy - ICP signers and providers for the Ethereum support library Alloy

I am happy to announce a first alpha version of the ic-alloy EVM RPC support library, a fork of Alloy with ICP support.

Alloy is the next generation of Ethereum support libraries, written in Rust and designed for scalability and performance. Alloy is a rewrite of ethers-rs from the ground up. Alloy includes built in support for transports like HTTP, WebSockets and IPC.

And now … Alloy also works with ICP.

I have added ICP as an Alloy transport layer and signer. This makes it possible to use the full feature set (almost) of Alloy from ICP canisters:

  • Getting blocks, balances and addresses, one by one or in batches
  • Sending ETH and ERC-20 tokens using fillers for nonce, gas estimation etc
  • Interacting with EVM contract functions
  • Watching for blocks and EVM events (logs), that is, subscribing to them on a timed basis
  • Signing messages and transactions
  • etc

I haven’t deployed the library to crates.io yet, I’d like to wait a bit and hopefully receive some feedback first. ic-alloy should make it significantly simpler to interact with the EVM from Rust based canisters.

Try it, let me know what you think and any issues you encounter.

Resources:

Example, get the balance of an address

#[ic_cdk::update]
async fn get_balance(address: String) -> Result<String, String> {
    let address = address.parse::<Address>().map_err(|e| e.to_string())?;
    let rpc_service = RpcService::EthSepolia(EthSepoliaService::Alchemy);
    let config = IcpConfig::new(rpc_service);
    let provider = ProviderBuilder::new().on_icp(config);
    let result = provider.get_balance(address).await;

    match result {
        Ok(balance) => Ok(balance.to_string()),
        Err(e) => Err(e.to_string()),
    }
}

get_balance.rs

Example, sign a message

#[ic_cdk::update]
async fn sign_message(message: String) -> Result<String, String> {
    let ecdsa_key_name = "key_1".to_string();
    let chain_id = 11155111;
    IcpSigner::new(vec![], &ecdsa_key_name, Some(chain_id)).await.unwrap();
    let signature = signer.sign_message(message.as_bytes()).await.unwrap();
    Ok(format!("{:?}", signature))
}

sign_message.rs

5 Likes

Is this a possible drop in replacement for what is in the EVMRPC canister?

Would you run this from the IC or is this more of a client tool?

If it ran from the IC, I guess it would need to use HTTPoutcalls instead of the standard fetch?

No, ic-alloy uses the EVM-RPC canister or an RPC Proxy to make requests to Ethereum.

This is for use in Rust based canisters.

See first answer. This is all Rust, so no fetch like in JS.

1 Like

Very nice…does it do some ‘extra stuff’ besides what the RPC does? Or give more ‘shape’ to it since the current rpc is pretty limited to what calls it can make?

Where I’m going is I’m curious if it could be wrapped in @rvanasa canpack and used easily from Motoko canisters that need to do EVM Stuff beyond the standard EVMRPC functions.

When you say RPC, do you mean the EVM RPC Canister? The Alloy library uses the generic request method of the EVM RPC canister and can therefore access all endpoints of the RPC that serves the requests – Alchemy etc.

See the Alloy book for examples on how to interact with the EVM using Alloy.

@sudoshreyansh Check this out as you were thinking of building a potentially similar utility.

2 Likes