-
Notifications
You must be signed in to change notification settings - Fork 470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EIP-1193 support #414
Add EIP-1193 support #414
Changes from 4 commits
5d16f38
022c4e5
3f10dae
15462bc
0f4a832
461bed2
ee62eda
1099ee4
15046bb
ca2aaf7
0656744
8d63e45
98caabc
f546e5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,22 @@ | ||
//! Partial implementation of the `Accounts` namespace. | ||
|
||
use crate::api::{Namespace, Web3}; | ||
use crate::api::Namespace; | ||
#[cfg(feature = "signing")] | ||
use crate::api::Web3; | ||
#[cfg(feature = "signing")] | ||
use crate::error; | ||
use crate::signing::{self, Signature}; | ||
use crate::signing; | ||
#[cfg(feature = "signing")] | ||
use crate::signing::Signature; | ||
use crate::types::H256; | ||
#[cfg(feature = "signing")] | ||
use crate::types::{ | ||
Address, Bytes, Recovery, RecoveryMessage, SignedData, SignedTransaction, TransactionParameters, H256, U256, | ||
Address, Bytes, Recovery, RecoveryMessage, SignedData, SignedTransaction, TransactionParameters, U256, | ||
}; | ||
use crate::Transport; | ||
#[cfg(feature = "signing")] | ||
use rlp::RlpStream; | ||
#[cfg(feature = "signing")] | ||
use std::convert::TryInto; | ||
|
||
/// `Accounts` namespace | ||
|
@@ -31,6 +40,7 @@ impl<T: Transport> Namespace<T> for Accounts<T> { | |
|
||
impl<T: Transport> Accounts<T> { | ||
/// Gets the parent `web3` namespace | ||
#[cfg(feature = "signing")] | ||
enolan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fn web3(&self) -> Web3<T> { | ||
Web3::new(self.transport.clone()) | ||
} | ||
|
@@ -41,6 +51,7 @@ impl<T: Transport> Accounts<T> { | |
/// parameters required for signing `nonce`, `gas_price` and `chain_id`. Note | ||
/// that if all transaction parameters were provided, this future will resolve | ||
/// immediately. | ||
#[cfg(feature = "signing")] | ||
pub async fn sign_transaction<K: signing::Key>( | ||
&self, | ||
tx: TransactionParameters, | ||
|
@@ -100,6 +111,7 @@ impl<T: Transport> Accounts<T> { | |
/// notation, that is the recovery value `v` is either `27` or `28` (as | ||
/// opposed to the standard notation where `v` is either `0` or `1`). This | ||
/// is important to consider when using this signature with other crates. | ||
#[cfg(feature = "signing")] | ||
pub fn sign<S>(&self, message: S, key: impl signing::Key) -> SignedData | ||
where | ||
S: AsRef<[u8]>, | ||
|
@@ -140,6 +152,7 @@ impl<T: Transport> Accounts<T> { | |
/// | ||
/// Recovery signature data uses 'Electrum' notation, this means the `v` | ||
/// value is expected to be either `27` or `28`. | ||
#[cfg(feature = "signing")] | ||
pub fn recover<R>(&self, recovery: R) -> error::Result<Address> | ||
where | ||
R: Into<Recovery>, | ||
|
@@ -158,6 +171,7 @@ impl<T: Transport> Accounts<T> { | |
} | ||
|
||
/// A transaction used for RLP encoding, hashing and signing. | ||
#[cfg(feature = "signing")] | ||
struct Transaction { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
to: Option<Address>, | ||
nonce: U256, | ||
|
@@ -167,6 +181,7 @@ struct Transaction { | |
data: Vec<u8>, | ||
} | ||
|
||
#[cfg(feature = "signing")] | ||
impl Transaction { | ||
/// RLP encode an unsigned transaction for the specified chain ID. | ||
fn rlp_append_unsigned(&self, rlp: &mut RlpStream, chain_id: u64) { | ||
|
@@ -205,6 +220,7 @@ impl Transaction { | |
} | ||
|
||
/// Sign and return a raw signed transaction. | ||
#[cfg(feature = "signing")] | ||
fn sign(self, sign: impl signing::Key, chain_id: u64) -> SignedTransaction { | ||
let mut rlp = RlpStream::new(); | ||
self.rlp_append_unsigned(&mut rlp, chain_id); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,17 @@ | ||
//! Ethereum Contract Interface | ||
|
||
use crate::api::{Accounts, Eth, Namespace}; | ||
#[cfg(feature = "signing")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here an in other places, please group signing-related functionality in a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please group all signing related things into a submodule here as well? Basically I'd like a single |
||
use crate::api::Accounts; | ||
use crate::api::{Eth, Namespace}; | ||
use crate::confirm; | ||
use crate::contract::tokens::{Detokenize, Tokenize}; | ||
#[cfg(feature = "signing")] | ||
use crate::signing; | ||
#[cfg(feature = "signing")] | ||
use crate::types::TransactionParameters; | ||
use crate::types::{ | ||
Address, BlockId, Bytes, CallRequest, FilterBuilder, TransactionCondition, TransactionParameters, | ||
TransactionReceipt, TransactionRequest, H256, U256, | ||
Address, BlockId, Bytes, CallRequest, FilterBuilder, TransactionCondition, TransactionReceipt, TransactionRequest, | ||
H256, U256, | ||
}; | ||
use crate::Transport; | ||
use std::{collections::HashMap, hash::Hash, time}; | ||
|
@@ -142,6 +147,7 @@ impl<T: Transport> Contract<T> { | |
} | ||
|
||
/// Execute a signed contract function and wait for confirmations | ||
#[cfg(feature = "signing")] | ||
pub async fn signed_call_with_confirmations( | ||
&self, | ||
func: &str, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,16 @@ | ||
//! Signing capabilities and utilities. | ||
|
||
use crate::types::{Address, H256}; | ||
#[cfg(feature = "signing")] | ||
use crate::types::Address; | ||
use crate::types::H256; | ||
#[cfg(feature = "signing")] | ||
use secp256k1::recovery::{RecoverableSignature, RecoveryId}; | ||
#[cfg(feature = "signing")] | ||
use secp256k1::{Message, PublicKey, Secp256k1}; | ||
#[cfg(feature = "signing")] | ||
use std::ops::Deref; | ||
|
||
#[cfg(feature = "signing")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here as well. Perhaps it's better to simply disable the entire |
||
pub(crate) use secp256k1::SecretKey; | ||
|
||
/// Error during signing. | ||
|
@@ -41,6 +47,7 @@ impl std::error::Error for RecoveryError {} | |
/// | ||
/// If it's enough to pass a reference to `SecretKey` (lifetimes) than you can use `SecretKeyRef` | ||
/// wrapper. | ||
#[cfg(feature = "signing")] | ||
pub trait Key { | ||
/// Sign given message and include chain-id replay protection. | ||
/// | ||
|
@@ -57,23 +64,27 @@ pub trait Key { | |
/// | ||
/// A wrapper around `secp256k1::SecretKey` reference, which enables it to be used in methods expecting | ||
/// `Key` capabilities. | ||
#[cfg(feature = "signing")] | ||
pub struct SecretKeyRef<'a> { | ||
key: &'a SecretKey, | ||
} | ||
|
||
#[cfg(feature = "signing")] | ||
impl<'a> SecretKeyRef<'a> { | ||
/// A simple wrapper around a reference to `SecretKey` which allows it to be usable for signing. | ||
pub fn new(key: &'a SecretKey) -> Self { | ||
Self { key } | ||
} | ||
} | ||
|
||
#[cfg(feature = "signing")] | ||
impl<'a> From<&'a SecretKey> for SecretKeyRef<'a> { | ||
fn from(key: &'a SecretKey) -> Self { | ||
Self::new(key) | ||
} | ||
} | ||
|
||
#[cfg(feature = "signing")] | ||
impl<'a> Deref for SecretKeyRef<'a> { | ||
type Target = SecretKey; | ||
|
||
|
@@ -82,6 +93,7 @@ impl<'a> Deref for SecretKeyRef<'a> { | |
} | ||
} | ||
|
||
#[cfg(feature = "signing")] | ||
impl<T: Deref<Target = SecretKey>> Key for T { | ||
fn sign(&self, message: &[u8], chain_id: Option<u64>) -> Result<Signature, SigningError> { | ||
let message = Message::from_slice(&message).map_err(|_| SigningError::InvalidMessage)?; | ||
|
@@ -121,6 +133,7 @@ pub struct Signature { | |
/// Recover a sender, given message and the signature. | ||
/// | ||
/// Signature and `recovery_id` can be obtained from `types::Recovery` type. | ||
#[cfg(feature = "signing")] | ||
pub fn recover(message: &[u8], signature: &[u8], recovery_id: i32) -> Result<Address, RecoveryError> { | ||
let message = Message::from_slice(message).map_err(|_| RecoveryError::InvalidMessage)?; | ||
let recovery_id = RecoveryId::from_i32(recovery_id).map_err(|_| RecoveryError::InvalidSignature)?; | ||
|
@@ -140,6 +153,7 @@ pub fn recover(message: &[u8], signature: &[u8], recovery_id: i32) -> Result<Add | |
/// crate is 65 bytes long, that is because it is prefixed by `0x04` to | ||
/// indicate an uncompressed public key; this first byte is ignored when | ||
/// computing the hash. | ||
#[cfg(feature = "signing")] | ||
pub(crate) fn public_key_address(public_key: &PublicKey) -> Address { | ||
let public_key = public_key.serialize_uncompressed(); | ||
|
||
|
@@ -150,6 +164,7 @@ pub(crate) fn public_key_address(public_key: &PublicKey) -> Address { | |
} | ||
|
||
/// Gets the public address of a private key. | ||
#[cfg(feature = "signing")] | ||
pub(crate) fn secret_key_address(key: &SecretKey) -> Address { | ||
let secp = Secp256k1::signing_only(); | ||
let public_key = PublicKey::from_secret_key(&secp, key); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of disabling
signing
capabilities in JS it's actually possible to uselibsecpk256k1
which compiles to WASM. See how it's done inethsign
. That said, it might be pretty involved and would rather review that separately in a follow up PR, so we can just create an issue for now.