{"id":13525752,"url":"https://github.com/horizonx-tech/ic-web3-rs","last_synced_at":"2026-03-11T13:18:37.473Z","repository":{"id":167093189,"uuid":"640825794","full_name":"horizonx-tech/ic-web3-rs","owner":"horizonx-tech","description":null,"archived":false,"fork":false,"pushed_at":"2025-01-04T16:30:45.000Z","size":297,"stargazers_count":11,"open_issues_count":0,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T20:57:44.246Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/horizonx-tech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-05-15T07:55:37.000Z","updated_at":"2025-08-25T17:12:40.000Z","dependencies_parsed_at":"2024-01-17T09:37:46.400Z","dependency_job_id":"6d5511df-93a3-4204-a99c-0460f5baae1e","html_url":"https://github.com/horizonx-tech/ic-web3-rs","commit_stats":null,"previous_names":["horizonx-tech/ic-web3","horizonx-tech/ic-web3-rs"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/horizonx-tech/ic-web3-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizonx-tech%2Fic-web3-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizonx-tech%2Fic-web3-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizonx-tech%2Fic-web3-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizonx-tech%2Fic-web3-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/horizonx-tech","download_url":"https://codeload.github.com/horizonx-tech/ic-web3-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizonx-tech%2Fic-web3-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30382669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T12:49:11.341Z","status":"ssl_error","status_checked_at":"2026-03-11T12:46:41.342Z","response_time":84,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:01:21.763Z","updated_at":"2026-03-11T13:18:37.456Z","avatar_url":"https://github.com/horizonx-tech.png","language":"Rust","funding_links":[],"categories":["Chain Fusion"],"sub_categories":["Ethereum"],"readme":"# ic-web3-rs\nRPC client for canisters on the Internet Computer to access Ethereum networks, powered by the Internet Computer's threshold ECDSA signature and outbound http call features.\n\nThis is a fork of [rocklabs-io/ic-web3](https://github.com/rocklabs-io/ic-web3).\n\n### Features\n\n* Perform RPC calls to Ethereum networks within canisters\n* Sign messages with IC's threshold ECDSA\n* Send transactions to Ethereum networks within canisters\n* Query/call Ethereum contracts within canisters\n\n### Usage\n\nAdd the following to your `Cargo.toml`:\n\n```\n[dependencies]\nic-web3-rs = { git = \"https://github.com/horizonx-tech/ic-web3-rs\" }\n```\n\n\n### Custom HTTP Transformation\n\nThis supports custom HTTP transformation, which is useful to avoid `no consensus was reached` errors.\nThis helps when to use the same canister to send multiple kinds of requests to Ethereum networks, such as `eth_getTransactionCount` and `eth_getBalance`, so that the canister must transform different types of responses.\nTo use this feature, you need to implement the `TransformContext` trait and pass it as `CallOptions`.\n\n\n```rust\nuse ic_web3::{\n    contract::Options, ethabi::Address, transforms::processors,\n    transforms::transform::TransformProcessor, transports::ic_http_client::CallOptionsBuilder,\n};\n...\n\n#[query]\n#[candid_method(query)]\nfn transform_request(args: TransformArgs) -\u003e HttpResponse {\n    processors::get_filter_changes_processor().transform(args)\n}\n\nfn call_options() -\u003e Options {\n    let call_options = CallOptionsBuilder::default()\n        .transform(Some(TransformContext {\n            function: TransformFunc(candid::Func {\n                principal: ic_cdk::api::id(),\n                method: \"transform_request\".to_string(),\n            }),\n            context: vec![],\n        }))\n        .max_resp(None)\n        .cycles(None)\n        .build()\n        .unwrap();\n    let mut opts = Options::default();\n    opts.call_options = Some(call_options);\n    opts\n}\n#[update]\n#[candid_method(update)]\nasync fn set_value(symbol: String, value: WrappedU256) {\n    struct Dist {\n        nw: SupportedNetwork,\n        addr: Address,\n    }\n\n    for d in ORACLE_ADDRESSES.with(|addresses| {\n        addresses\n            .borrow()\n            .iter()\n            .map(|(\u0026k, \u0026v)| Dist { nw: k, addr: v })\n            .collect::\u003cVec\u003cDist\u003e\u003e()\n    }) {\n        let context = ctx(d.nw).unwrap();\n        let oracle = IPriceOracle::new(d.addr.clone(), \u0026context);\n        let res = match oracle\n            .set_price(\n                symbol.to_string().clone(),\n                value.value(),\n                Some(call_options()),\n            )\n            .await\n        {\n            Ok(v) =\u003e ic_cdk::println!(\"set_value: {:?}\", v),\n            Err(e) =\u003e {\n                ic_cdk::println!(\"set_value error: {:?}. retry\", e);\n                oracle\n                    .set_price(\n                        symbol.to_string().clone(),\n                        value.value(),\n                        Some(call_options()), // This is the custom HTTP transformation\n                    )\n                    .await;\n            }\n        };\n        ic_cdk::println!(\"set_value: {:?}\", res);\n    }\n}\n```\n\n\n### Examples\n\nNote: you should have dfx 0.11.2 or above.\n\nPlease refer to [example](./examples/main.rs) for the complete example.\n\n```rust\nuse candid::candid_method;\nuse ic_cdk_macros::{self, update};\nuse std::str::FromStr;\n\nuse ic_web3::transports::ICHttp;\nuse ic_web3::Web3;\nuse ic_web3::ic::{get_eth_addr, KeyInfo};\nuse ic_web3::{\n    contract::{Contract, Options},\n    ethabi::ethereum_types::{U64, U256},\n    types::{Address, TransactionParameters, BlockId, BlockNumber, Block},\n};\n\nconst URL: \u0026str = \"\u003cGOERLI-RPC-URL\u003e\";\nconst CHAIN_ID: u64 = 5;\nconst KEY_NAME: \u0026str = \"dfx_test_key\";\nconst TOKEN_ABI: \u0026[u8] = include_bytes!(\"../src/contract/res/token.json\");\n\ntype Result\u003cT, E\u003e = std::result::Result\u003cT, E\u003e;\n\n#[update(name = \"get_eth_gas_price\")]\n#[candid_method(update, rename = \"get_eth_gas_price\")]\nasync fn get_eth_gas_price() -\u003e Result\u003cString, String\u003e {\n    let w3 = match ICHttp::new(URL, None) {\n        Ok(v) =\u003e { Web3::new(v) },\n        Err(e) =\u003e { return Err(e.to_string()) },\n    };\n    let gas_price = w3.eth().gas_price().await.map_err(|e| format!(\"get gas price failed: {}\", e))?;\n    ic_cdk::println!(\"gas price: {}\", gas_price);\n    Ok(format!(\"{}\", gas_price))\n}\n\n// get canister's ethereum address\n#[update(name = \"get_canister_addr\")]\n#[candid_method(update, rename = \"get_canister_addr\")]\nasync fn get_canister_addr() -\u003e Result\u003cString, String\u003e {\n    match get_eth_addr(None, None, KEY_NAME.to_string()).await {\n        Ok(addr) =\u003e { Ok(hex::encode(addr)) },\n        Err(e) =\u003e { Err(e) },\n    }\n}\n\n// send tx to eth\n#[update(name = \"send_eth\")]\n#[candid_method(update, rename = \"send_eth\")]\nasync fn send_eth(to: String, value: u64) -\u003e Result\u003cString, String\u003e {\n    // ecdsa key info\n    let derivation_path = vec![ic_cdk::id().as_slice().to_vec()];\n    let key_info = KeyInfo{ derivation_path: derivation_path, key_name: KEY_NAME.to_string() };\n\n    // get canister eth address\n    let from_addr = get_eth_addr(None, None, KEY_NAME.to_string())\n        .await\n        .map_err(|e| format!(\"get canister eth addr failed: {}\", e))?;\n    // get canister the address tx count\n    let w3 = match ICHttp::new(URL, None) {\n        Ok(v) =\u003e { Web3::new(v) },\n        Err(e) =\u003e { return Err(e.to_string()) },\n    };\n    let tx_count = w3.eth()\n        .transaction_count(from_addr, None)\n        .await\n        .map_err(|e| format!(\"get tx count error: {}\", e))?;\n        \n    ic_cdk::println!(\"canister eth address {} tx count: {}\", hex::encode(from_addr), tx_count);\n    // construct a transaction\n    let to = Address::from_str(\u0026to).unwrap();\n    let tx = TransactionParameters {\n        to: Some(to),\n        nonce: Some(tx_count), // remember to fetch nonce first\n        value: U256::from(value),\n        gas_price: Some(U256::exp10(10)), // 10 gwei\n        gas: U256::from(21000),\n        ..Default::default()\n    };\n    // sign the transaction and get serialized transaction + signature\n    let signed_tx = w3.accounts()\n        .sign_transaction(tx, key_info, CHAIN_ID)\n        .await\n        .map_err(|e| format!(\"sign tx error: {}\", e))?;\n    match w3.eth().send_raw_transaction(signed_tx.raw_transaction).await {\n        Ok(txhash) =\u003e { \n            ic_cdk::println!(\"txhash: {}\", hex::encode(txhash.0));\n            Ok(format!(\"{}\", hex::encode(txhash.0)))\n        },\n        Err(e) =\u003e { Err(e.to_string()) },\n    }\n}\n```\n\nStart a local replica:\n\n```\ndfx start --background --clean --enable-canister-http\n```\n\nDeploy the example canister:\n\n```\ndfx deploy\n```\n\n### Endpoint Canister\n\nThe public endpoint canister is deployed at: `3ondx-siaaa-aaaam-abf3q-cai`, [code](./examples/endpoint.rs). You can access Ethereum Mainnet data by passing RPC calls to the endpoint canister.\n\n### Acknowledgment\n\nThis repo is modified from the [ic-web3](https://github.com/rocklabs-io/ic-web3) project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhorizonx-tech%2Fic-web3-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhorizonx-tech%2Fic-web3-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhorizonx-tech%2Fic-web3-rs/lists"}