feat: add wasm http provider support (#403)

* fix: use on wasm only

* feat: enable http provider in wasm

* add http example

* chore: add more verbosity to example

* fix: double webpack issue

* use mnemonic builder
This commit is contained in:
Matthias Seitz 2021-08-24 00:28:05 +02:00 committed by GitHub
parent e6cd74cf1f
commit d35444cc49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 92 deletions

View File

@ -26,7 +26,7 @@ once_cell = "1.8.0"
cargo_metadata = "0.14.0"
cfg-if = "1.0.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
[target.'cfg(target_arch = "wasm32")'.dependencies]
# NOTE: this enables wasm compatibility for getrandom indirectly
getrandom = { version = "0.2", features = ["js"] }

View File

@ -2,12 +2,9 @@ use crate::{
ens,
pubsub::{PubsubClient, SubscriptionStream},
stream::{FilterWatcher, DEFAULT_POLL_INTERVAL},
FeeHistory, FromErr, JsonRpcClient, MockProvider, PendingTransaction,
FeeHistory, FromErr, Http as HttpProvider, JsonRpcClient, MockProvider, PendingTransaction,
};
#[cfg(not(target_arch = "wasm32"))]
use crate::Http as HttpProvider;
use ethers_core::{
abi::{self, Detokenize, ParamType},
types::{
@ -26,7 +23,6 @@ use async_trait::async_trait;
use hex::FromHex;
use serde::{de::DeserializeOwned, Serialize};
use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))]
use url::{ParseError, Url};
use std::{convert::TryFrom, fmt::Debug, time::Duration};
@ -941,7 +937,6 @@ fn decode_bytes<T: Detokenize>(param: ParamType, bytes: Bytes) -> T {
T::from_tokens(tokens).expect("could not parse tokens as address")
}
#[cfg(not(target_arch = "wasm32"))]
impl TryFrom<&str> for Provider<HttpProvider> {
type Error = ParseError;
@ -950,7 +945,6 @@ impl TryFrom<&str> for Provider<HttpProvider> {
}
}
#[cfg(not(target_arch = "wasm32"))]
impl TryFrom<String> for Provider<HttpProvider> {
type Error = ParseError;

View File

@ -15,16 +15,15 @@ macro_rules! if_not_wasm {
}
if_not_wasm! {
mod http;
pub use http::Provider as Http;
#[cfg(feature = "ipc")]
mod ipc;
#[cfg(feature = "ipc")]
pub use ipc::Ipc;
}
mod http;
pub use http::Provider as Http;
#[cfg(feature = "ws")]
mod ws;
#[cfg(feature = "ws")]

View File

@ -2,7 +2,6 @@ const ethers = import('./pkg');
ethers
.then(m => {
m.setup();
m.deploy().catch(console.error);
})
.catch(console.error);

View File

@ -4,7 +4,7 @@
"scripts": {
"build": "webpack",
"serve": "webpack-dev-server",
"ganache": "ganache-cli --blockTime 5 --seed ethers-wasm-seed"
"ganache": "ganache-cli --blockTime 2 -m \"stuff inherit faith park genre spread huge knee ecology private marble supreme\""
},
"devDependencies": {
"@wasm-tool/wasm-pack-plugin": "1.0.1",

View File

@ -1,90 +1,82 @@
pub mod utils;
use crate::utils::SIMPLECONTRACT_BIN;
use ethers::{
contract::abigen,
prelude::{ContractFactory, LocalWallet, Provider, SignerMiddleware},
providers::{Middleware, Ws},
};
use std::sync::Arc;
use wasm_bindgen::prelude::*;
use web_sys::console;
use ethers::{
contract::abigen,
prelude::{ContractFactory, Provider, SignerMiddleware},
providers::Ws,
};
use crate::utils::SIMPLECONTRACT_BIN;
pub mod utils;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
macro_rules! log {
( $( $t:tt )* ) => {
web_sys::console::log_1(&format!( $( $t )* ).into());
}
}
abigen!(
SimpleContract,
"./../contract_abi.json",
event_derives(serde::Deserialize, serde::Serialize)
);
/// key[0] of ganache with custom seed `ethers-wasm-seed`
pub const KEY: &str = "817169e55f14ede54f4fd6a4f2ab4209db14aeeb1b9972b3b28f1560af0a061a";
#[wasm_bindgen]
pub fn setup() {
utils::set_panic_hook();
}
#[wasm_bindgen]
pub async fn deploy() {
utils::set_panic_hook();
console::log_2(
&"ABI: ".into(),
&"SimpleContract ABI: ".into(),
&JsValue::from_serde(&*SIMPLECONTRACT_ABI).unwrap(),
);
let wallet: LocalWallet = KEY.parse().unwrap();
let wallet = utils::key(0);
log!("Wallet: {:?}", wallet);
let endpoint = "ws://127.0.0.1:8545";
let provider = Provider::new(Ws::connect(endpoint).await.unwrap());
let client = Arc::new(SignerMiddleware::new(provider, wallet));
log!("provider connected to `{}`", endpoint);
let version = client.client_version().await;
log!("version {:?}", version);
let account = client.get_accounts().await.unwrap()[0];
log!("account {:?}", account);
log!("Provider connected to `{}`", endpoint);
let bytecode = hex::decode(SIMPLECONTRACT_BIN).unwrap();
let factory = ContractFactory::new(SIMPLECONTRACT_ABI.clone(), bytecode.into(), client.clone());
let init = "hello WASM!";
log!("Deploying contract...");
let contract = factory
.deploy(init.to_string())
.deploy("hello WASM!".to_string())
.unwrap()
.send()
.await
.unwrap();
let addr = contract.address();
log!("deployed contract with address {}", addr);
log!("Deployed contract with address: {:?}", addr);
let contract = SimpleContract::new(addr, client.clone());
let value = contract.get_value().call().await.unwrap();
assert_eq!(init, &value);
let _receipt = contract
.set_value("bye WASM!".to_owned())
let value = "bye from WASM!";
log!("Setting value... `{}`", value);
let receipt = contract
.set_value(value.to_owned())
.send()
.await
.unwrap()
.await
.unwrap();
log!("set value");
// 10. get all events
console::log_2(
&"Set value receipt: ".into(),
&JsValue::from_serde(&receipt).unwrap(),
);
log!("Fetching logs...");
let logs = contract
.value_changed_filter()
.from_block(0u64)
@ -94,9 +86,8 @@ pub async fn deploy() {
let value = contract.get_value().call().await.unwrap();
log!(
"Value: {}. Logs: {:?}",
value,
JsValue::from_serde(&logs).unwrap()
console::log_2(
&format!("Value: `{}`. Logs: ", value).into(),
&JsValue::from_serde(&logs).unwrap(),
);
}

View File

@ -1,3 +1,6 @@
use ethers::prelude::{LocalWallet, MnemonicBuilder};
use ethers::signers::coins_bip39::English;
pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then
@ -9,4 +12,18 @@ pub fn set_panic_hook() {
console_error_panic_hook::set_once();
}
/// The mnemonic phrase used by ganache
pub const PHRASE: &str =
"stuff inherit faith park genre spread huge knee ecology private marble supreme";
pub fn key(index: u32) -> LocalWallet {
MnemonicBuilder::<English>::default()
.phrase(PHRASE)
.index(index)
.unwrap()
.build()
.unwrap()
}
/// Bytecode of the `SimpleContract`
pub const SIMPLECONTRACT_BIN: &str = "608060405234801561001057600080fd5b5060405161073b38038061073b8339818101604052602081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b8382019150602082018581111561006957600080fd5b825186600182028301116401000000008211171561008657600080fd5b8083526020830192505050908051906020019080838360005b838110156100ba57808201518184015260208101905061009f565b50505050905090810190601f1680156100e75780820380516001836020036101000a031916815260200191505b506040525050503373ffffffffffffffffffffffffffffffffffffffff167fe826f71647b8486f2bae59832124c70792fba044036720a54ec8dacdd5df4fcb6000836040518080602001806020018381038352858181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156101b65780601f1061018b576101008083540402835291602001916101b6565b820191906000526020600020905b81548152906001019060200180831161019957829003601f168201915b5050838103825284818151815260200191508051906020019080838360005b838110156101f05780820151818401526020810190506101d5565b50505050905090810190601f16801561021d5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a28060009080519060200190610242929190610249565b50506102e6565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028a57805160ff19168380011785556102b8565b828001600101855582156102b8579182015b828111156102b757825182559160200191906001019061029c565b5b5090506102c591906102c9565b5090565b5b808211156102e25760008160009055506001016102ca565b5090565b610446806102f56000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063209652551461003b57806393a09352146100be575b600080fd5b610043610179565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610083578082015181840152602081019050610068565b50505050905090810190601f1680156100b05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610177600480360360208110156100d457600080fd5b81019080803590602001906401000000008111156100f157600080fd5b82018360208201111561010357600080fd5b8035906020019184600183028401116401000000008311171561012557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061021b565b005b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102115780601f106101e657610100808354040283529160200191610211565b820191906000526020600020905b8154815290600101906020018083116101f457829003601f168201915b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff167fe826f71647b8486f2bae59832124c70792fba044036720a54ec8dacdd5df4fcb6000836040518080602001806020018381038352858181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156102e35780601f106102b8576101008083540402835291602001916102e3565b820191906000526020600020905b8154815290600101906020018083116102c657829003601f168201915b5050838103825284818151815260200191508051906020019080838360005b8381101561031d578082015181840152602081019050610302565b50505050905090810190601f16801561034a5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2806000908051906020019061036f929190610373565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106103b457805160ff19168380011785556103e2565b828001600101855582156103e2579182015b828111156103e15782518255916020019190600101906103c6565b5b5090506103ef91906103f3565b5090565b5b8082111561040c5760008160009055506001016103f4565b509056fea26469706673582212202d397d3d0e6cf9afdeed7d5192e3abff386699395df0409eb5c3ec494832c57a64736f6c63430007000033";

View File

@ -1,16 +1,12 @@
//! Test suite for the Web and headless browsers.
#![cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use ethers::{
contract::abigen,
prelude::{ContractFactory, LocalWallet, Provider, SignerMiddleware},
providers::Ws,
use ethers::prelude::{
abigen, ContractFactory, Http, JsonRpcClient, LocalWallet, Provider, SignerMiddleware, Ws,
};
use std::convert::TryFrom;
use std::sync::Arc;
wasm_bindgen_test_configure!(run_in_browser);
@ -24,19 +20,26 @@ abigen!(
);
#[wasm_bindgen_test]
async fn connect_and_deploy() {
console_log!("starting");
// a private key of a launched ganache `yarn ganache`
let wallet: LocalWallet = ethers_wasm::KEY.parse().unwrap();
async fn http_connect_and_deploy() {
console_log!("connecting http...");
let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
deploy(provider, ethers_wasm::utils::key(0)).await;
}
#[wasm_bindgen_test]
async fn ws_connect_and_deploy() {
console_log!("connecting ws...");
let provider = Provider::new(Ws::connect("ws://localhost:8545").await.unwrap());
deploy(provider, ethers_wasm::utils::key(1)).await;
}
async fn deploy<T: JsonRpcClient>(provider: Provider<T>, wallet: LocalWallet) {
let client = Arc::new(SignerMiddleware::new(provider, wallet));
let bytecode = hex::decode(ethers_wasm::utils::SIMPLECONTRACT_BIN).unwrap();
let factory = ContractFactory::new(SIMPLECONTRACT_ABI.clone(), bytecode.into(), client.clone());
let contract = factory
.deploy("initial value".to_string())
.deploy("Hello from Contract!".to_string())
.unwrap()
.send()
.await
@ -45,27 +48,7 @@ async fn connect_and_deploy() {
console_log!("deployed to {}", addr);
let contract = SimpleContract::new(addr, client.clone());
let _receipt = contract
.set_value("hi".to_owned())
.send()
.await
.unwrap()
.await
.unwrap();
// get all events
let logs = contract
.value_changed_filter()
.from_block(0u64)
.query()
.await
.unwrap();
let value = contract.get_value().call().await.unwrap();
console_log!(
"Value: {}. Logs: {:?}",
value,
JsValue::from_serde(&logs).unwrap()
);
console_log!("value: {:?}", value);
}

View File

@ -11,7 +11,8 @@ module.exports = {
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
template: './index.html',
inject: false
}
),
new WasmPackPlugin({