I’m trying to set Cloudflare’s workers to track the circulation of some ERC20 tokens as an exercise to learn web3 and wasm. Thought it could be simple enough, but about 90% of the time so far has been trying to solve this elusive error
A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's request context have already finished.
I look for additional information online, but it seems my error is from a different type(?).
Here’s a simple snippet of code to reproduce.
mod erc20_abi; use erc20_abi::ERC20_ABI; use cfg_if::cfg_if; use ethers::{ contract::Contract, core::{abi::Abi, types::Address}, prelude::{AbiError, U256}, providers::{Http, Provider}, }; use num_format::{Locale, ToFormattedString}; use std::convert::TryFrom; use wasm_bindgen::prelude::*; cfg_if! { // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global // allocator. if #[cfg(feature = "wee_alloc")] { extern crate wee_alloc; #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; } } #[wasm_bindgen] pub async fn handle() -> String { let web3_ethereum = Provider::<Http>::try_from(WEB3_URL_ETHEREUM).unwrap(); let abi: Abi = serde_json::from_str(ERC20_ABI).unwrap(); let token_contract_ethereum = Contract::new(parse_address(ADDRESS_ETH), abi, web3_ethereum); let convert_wei_to_decimal = |bignumber: U256| -> String { (bignumber.as_u128() / u128::pow(10, 18)).to_formatted_string(&Locale::en) }; // I believe this is the problem, since just returning a String works fine. let total_supply_ethereum = token_contract_ethereum .method::<_, U256>("totalSupply", ()) .unwrap() .call() .await .unwrap(); convert_wei_to_decimal(total_supply_ethereum) } fn parse_address(address: &str) -> Address { address.parse::<Address>().unwrap() }
This is the worker/workers.js file
addEventListener('fetch', (event) => { event.respondWith(handleRequest(event.request)) }) const { handle } = wasm_bindgen; const instance = wasm_bindgen(wasm); /** * Fetch and log a request * @param {Request} request */ async function handleRequest(request) { await instance; const output = await handle(); let res = new Response(output, { status: 200 }); res.headers.set('Content-type', 'text/html'); return res; }
Cargo.toml
[package] name = "circulating-supply" version = "0.1.0" license = "GPL-3.0-or-later" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] crate-type = ["cdylib", "rlib"] [profile.release] opt-level = 's' # Optimize for size. lto = true panic = "abort" codegen-units = 1 [dependencies] ethers = { git = "https://github.com/gakonst/ethers-rs" } serde_json = "1.0.68" num-format = "0.4.0" cfg-if = "1.0.0" wee_alloc = { version = "0.4.5", optional = true } wasm-bindgen = "0.2.78" wasm-bindgen-futures = "0.4.28" js-sys = "0.3.55"
wrangler dev
will compile it fine, but going to http://127.0.0.1:8787
will result in Error 1101
Advertisement
Answer
In my case a dependency used sth. not available in wasm runtime. I guess ethers cryptography dependencies also depend on sth. like getrandom.
Adding this to Cargo.toml
solved my issue.
[target.wasm32-unknown-unknown.dependencies] getrandom = { version = "0.1", features = ["wasm-bindgen"] }
This will force your dependencies based on getrandom use the wasm features of getrandom.