diff --git a/binding_tests/interface_test.go b/binding_tests/interface_test.go index 1f2a4d31..cb87e147 100644 --- a/binding_tests/interface_test.go +++ b/binding_tests/interface_test.go @@ -248,7 +248,7 @@ func TestSignWithdraw(t *testing.T) { // test signer signer, err := sdk.NewSigner(s, sdk.L1TypeEth); assert.Nil(t, err) - tx_signature, err := signer.SignWithdraw(tx, l2SourceTokenSymbol) + tx_signature, err := signer.SignWithdraw(tx, l2SourceTokenSymbol,nil,nil) assert.Nil(t, err) // test submitter diff --git a/bindings/sdk/src/ffi.udl b/bindings/sdk/src/ffi.udl index 8e449c46..9b04022f 100644 --- a/bindings/sdk/src/ffi.udl +++ b/bindings/sdk/src/ffi.udl @@ -489,6 +489,35 @@ enum StarkSignerError { "InvalidPrivKey", "SignError", }; + +dictionary TypeDefine { + string name; + string type; +}; + +dictionary TxMessage { + string transaction; + string amount; + string fee; + string token; + string to; + string nonce; +}; + +dictionary Message { + string data; +}; + +[Enum] +interface TypedDataMessage { + CreateL2Key(Message message); + Transaction(TxMessage message); +}; + +interface TypedData { + constructor(TypedDataMessage message,string chain_id); +}; + [Custom] typedef string StarkECDSASignature; @@ -497,7 +526,7 @@ interface StarkSigner { [Throws=StarkSignerError,Name=new_from_hex_str] constructor([ByRef] string hex_str); [Throws=StarkSignerError] - StarkECDSASignature sign_message([ByRef] sequence message); + StarkECDSASignature sign_message([ByRef] TypedData typed_data,[ByRef] string addr); }; @@ -536,7 +565,7 @@ interface ZkLinkSigner { [Throws=ZkSignerError,Name=new_from_hex_eth_signer] constructor([ByRef] string eth_hex_private_key); [Throws=ZkSignerError,Name=new_from_hex_stark_signer] - constructor([ByRef] string hex_private_key); + constructor([ByRef] string hex_private_key,[ByRef] string addr,[ByRef] string chain_id); [Throws=ZkSignerError,Name=new_from_bytes] constructor([ByRef] sequence slice); PackedPublicKey public_key(); @@ -578,9 +607,9 @@ interface Signer { [Throws=SignError] TxSignature sign_change_pubkey_with_eth_ecdsa_auth(ChangePubKey tx); [Throws=SignError] - TxSignature sign_transfer(Transfer tx, [ByRef]string token_sybmol); + TxSignature sign_transfer(Transfer tx, [ByRef]string token_sybmol,string? chain_id,string? addr); [Throws=SignError] - TxSignature sign_withdraw(Withdraw tx, [ByRef]string l2_source_token_symbol); + TxSignature sign_withdraw(Withdraw tx, [ByRef]string l2_source_token_symbol,string? chain_id,string? addr); [Throws=SignError] TxSignature sign_forced_exit(ForcedExit tx); [Throws=SignError] diff --git a/bindings/sdk/src/lib.rs b/bindings/sdk/src/lib.rs index 790066f7..4d6e0907 100644 --- a/bindings/sdk/src/lib.rs +++ b/bindings/sdk/src/lib.rs @@ -37,4 +37,10 @@ use zklink_sdk_interface::sign_change_pubkey::{ use zklink_sdk_interface::signer::{L1Type, Signer}; use zklink_sdk_interface::ChangePubKeyAuthRequest; +use zklink_sdk_signers::starknet_signer::typed_data::message::Message; +use zklink_sdk_signers::starknet_signer::typed_data::message::TxMessage; +use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; +use zklink_sdk_signers::starknet_signer::typed_data::TypeDefine; +use zklink_sdk_signers::starknet_signer::typed_data::TypedData; + include!(concat!(env!("OUT_DIR"), "/ffi.uniffi.rs")); diff --git a/bindings/wasm/src/json_rpc_signer.rs b/bindings/wasm/src/json_rpc_signer.rs index 99e79369..814af046 100755 --- a/bindings/wasm/src/json_rpc_signer.rs +++ b/bindings/wasm/src/json_rpc_signer.rs @@ -6,8 +6,10 @@ use crate::tx_types::transfer::Transfer; use crate::tx_types::withdraw::Withdraw; use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; +use zklink_sdk_interface::json_rpc_signer::JsonRpcProvider; use zklink_sdk_interface::json_rpc_signer::JsonRpcSigner as InterfaceJsonRpcSigner; use zklink_sdk_signers::eth_signer::json_rpc_signer::Provider; +use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::Signer; use zklink_sdk_types::tx_type::change_pubkey::ChangePubKey as TxChangePubKey; use zklink_sdk_types::tx_type::change_pubkey::Create2Data as ChangePubKeyCreate2Data; use zklink_sdk_types::tx_type::forced_exit::ForcedExit as TxForcedExit; @@ -17,8 +19,6 @@ use zklink_sdk_types::tx_type::order_matching::{ use zklink_sdk_types::tx_type::transfer::Transfer as TxTransfer; use zklink_sdk_types::tx_type::withdraw::Withdraw as TxWithdraw; use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; -use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::Signer; -use zklink_sdk_interface::json_rpc_signer::JsonRpcProvider; #[wasm_bindgen] pub struct JsonRpcSigner { @@ -28,14 +28,22 @@ pub struct JsonRpcSigner { //#[wasm_bindgen(constructor)] #[wasm_bindgen(js_name=newRpcSignerWtihProvider)] pub fn new_with_provider(provider: Provider) -> Result { - let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Provider(provider),None,None)?; + let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Provider(provider), None, None)?; Ok(JsonRpcSigner { inner }) } //#[wasm_bindgen(constructor)] #[wasm_bindgen(js_name=newRpcSignerWithSigner)] -pub fn new_with_signer(signer: Signer, pub_key: String,chain_id: String) -> Result { - let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Signer(signer),Some(pub_key),Some(chain_id))?; +pub fn new_with_signer( + signer: Signer, + pub_key: String, + chain_id: String, +) -> Result { + let inner = InterfaceJsonRpcSigner::new( + JsonRpcProvider::Signer(signer), + Some(pub_key), + Some(chain_id), + )?; Ok(JsonRpcSigner { inner }) } diff --git a/bindings/wasm/src/signer.rs b/bindings/wasm/src/signer.rs index f46abb45..f30cf67f 100644 --- a/bindings/wasm/src/signer.rs +++ b/bindings/wasm/src/signer.rs @@ -90,10 +90,18 @@ impl Signer { } #[wasm_bindgen(js_name=signTransfer)] - pub fn sign_transfer(&self, tx: Transfer, token_symbol: &str) -> Result { + pub fn sign_transfer( + &self, + tx: Transfer, + token_symbol: &str, + chain_id: Option, + addr: Option, + ) -> Result { let inner_tx = tx.json_value()?; let transfer: TxTransfer = serde_wasm_bindgen::from_value(inner_tx)?; - let signature = self.inner.sign_transfer(transfer, token_symbol)?; + let signature = self + .inner + .sign_transfer(transfer, token_symbol, chain_id, addr)?; Ok(serde_wasm_bindgen::to_value(&signature)?) } @@ -114,10 +122,18 @@ impl Signer { } #[wasm_bindgen(js_name=signWithdraw)] - pub fn sign_withdraw(&self, tx: Withdraw, token_symbol: &str) -> Result { + pub fn sign_withdraw( + &self, + tx: Withdraw, + token_symbol: &str, + chain_id: Option, + addr: Option, + ) -> Result { let inner_tx = tx.json_value()?; let withdraw: TxWithdraw = serde_wasm_bindgen::from_value(inner_tx)?; - let signature = self.inner.sign_withdraw(withdraw, token_symbol)?; + let signature = self + .inner + .sign_withdraw(withdraw, token_symbol, chain_id, addr)?; Ok(serde_wasm_bindgen::to_value(&signature)?) } diff --git a/interface/src/json_rpc_signer.rs b/interface/src/json_rpc_signer.rs index e7ed42f4..fba05444 100755 --- a/interface/src/json_rpc_signer.rs +++ b/interface/src/json_rpc_signer.rs @@ -9,9 +9,11 @@ use zklink_sdk_signers::eth_signer::json_rpc_signer::{ JsonRpcSigner as EthJsonRpcSigner, Provider, }; use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::{ - StarknetJsonRpcSigner,Signer as StarknetAccountSigner + Signer as StarknetAccountSigner, StarknetJsonRpcSigner, }; +use zklink_sdk_signers::starknet_signer::error::StarkSignerError; +use zklink_sdk_signers::starknet_signer::StarkECDSASignature; use zklink_sdk_signers::zklink_signer::{ZkLinkSignature, ZkLinkSigner}; use zklink_sdk_types::prelude::PackedEthSignature; use zklink_sdk_types::signatures::TxSignature; @@ -22,12 +24,10 @@ use zklink_sdk_types::tx_type::transfer::Transfer; use zklink_sdk_types::tx_type::withdraw::Withdraw; use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; use zklink_sdk_types::tx_type::ZkSignatureTrait; -use zklink_sdk_signers::starknet_signer::StarkECDSASignature; -use zklink_sdk_signers::starknet_signer::error::StarkSignerError; pub enum JsonRpcProvider { Provider(Provider), - Signer(StarknetAccountSigner) + Signer(StarknetAccountSigner), } pub enum Layer1JsonRpcSigner { EthSigner(EthJsonRpcSigner), @@ -40,12 +40,18 @@ pub struct JsonRpcSigner { } impl JsonRpcSigner { - pub fn new(provider: JsonRpcProvider,pub_key: Option,chain_id: Option) -> Result { + pub fn new( + provider: JsonRpcProvider, + pub_key: Option, + chain_id: Option, + ) -> Result { let eth_json_rpc_signer = match provider { - JsonRpcProvider::Provider(provider) => - Layer1JsonRpcSigner::EthSigner(EthJsonRpcSigner::new(provider)), - JsonRpcProvider::Signer(signer) => - Layer1JsonRpcSigner::StarknetSigner(StarknetJsonRpcSigner::new(signer,pub_key.unwrap(),chain_id.unwrap())) + JsonRpcProvider::Provider(provider) => { + Layer1JsonRpcSigner::EthSigner(EthJsonRpcSigner::new(provider)) + } + JsonRpcProvider::Signer(signer) => Layer1JsonRpcSigner::StarknetSigner( + StarknetJsonRpcSigner::new(signer, pub_key.unwrap(), chain_id.unwrap()), + ), }; let default_zklink_signer = ZkLinkSigner::new()?; Ok(Self { @@ -61,19 +67,21 @@ impl JsonRpcSigner { let signature = PackedEthSignature::from_hex(&s)?; let seed = signature.serialize_packed(); ZkLinkSigner::new_from_seed(&seed)? - }, + } Layer1JsonRpcSigner::StarknetSigner(_) => { let signature = StarkECDSASignature::from_hex(&s)?; let seed = signature.signature.to_bytes_be(); ZkLinkSigner::new_from_seed(&seed)? } } - } else { + } else { match &self.eth_signer { - Layer1JsonRpcSigner::EthSigner(signer) => - ZkLinkSigner::new_from_eth_rpc_signer(signer).await?, - Layer1JsonRpcSigner::StarknetSigner(signer) => - ZkLinkSigner::new_from_starknet_rpc_signer(signer).await?, + Layer1JsonRpcSigner::EthSigner(signer) => { + ZkLinkSigner::new_from_eth_rpc_signer(signer).await? + } + Layer1JsonRpcSigner::StarknetSigner(signer) => { + ZkLinkSigner::new_from_starknet_rpc_signer(signer).await? + } } }; self.zklink_signer = zklink_signer; @@ -86,10 +94,12 @@ impl JsonRpcSigner { token_symbol: &str, ) -> Result { match &self.eth_signer { - Layer1JsonRpcSigner::EthSigner(signer) => - sign_eth_transfer(signer, &self.zklink_signer, tx, token_symbol).await, - Layer1JsonRpcSigner::StarknetSigner(signer) => - sign_starknet_transfer(signer, &self.zklink_signer, tx, token_symbol).await, + Layer1JsonRpcSigner::EthSigner(signer) => { + sign_eth_transfer(signer, &self.zklink_signer, tx, token_symbol).await + } + Layer1JsonRpcSigner::StarknetSigner(signer) => { + sign_starknet_transfer(signer, &self.zklink_signer, tx, token_symbol).await + } } } @@ -114,11 +124,14 @@ impl JsonRpcSigner { // create auth data let eth_sign_msg = ChangePubKey::get_eth_sign_msg(&tx.new_pk_hash, tx.nonce, tx.account_id); let eth_signature = match &self.eth_signer { - Layer1JsonRpcSigner::EthSigner(signer) => - signer.sign_message(eth_sign_msg.as_bytes()).await?, + Layer1JsonRpcSigner::EthSigner(signer) => { + signer.sign_message(eth_sign_msg.as_bytes()).await? + } Layer1JsonRpcSigner::StarknetSigner(_) => { //starknet only support change_pubkey_onchain - return Err(StarkSignerError::SignError("Not support for starknet".to_string()).into()); + return Err( + StarkSignerError::SignError("Not support for starknet".to_string()).into(), + ); } }; @@ -136,10 +149,13 @@ impl JsonRpcSigner { l2_source_token_symbol: &str, ) -> Result { match &self.eth_signer { - Layer1JsonRpcSigner::EthSigner(signer) => - sign_eth_withdraw(signer, &self.zklink_signer, tx, l2_source_token_symbol).await, - Layer1JsonRpcSigner::StarknetSigner(signer) => - sign_starknet_withdraw(signer, &self.zklink_signer, tx, l2_source_token_symbol).await, + Layer1JsonRpcSigner::EthSigner(signer) => { + sign_eth_withdraw(signer, &self.zklink_signer, tx, l2_source_token_symbol).await + } + Layer1JsonRpcSigner::StarknetSigner(signer) => { + sign_starknet_withdraw(signer, &self.zklink_signer, tx, l2_source_token_symbol) + .await + } } } diff --git a/interface/src/sign_transfer.rs b/interface/src/sign_transfer.rs index cc6936f2..1041f714 100644 --- a/interface/src/sign_transfer.rs +++ b/interface/src/sign_transfer.rs @@ -1,18 +1,21 @@ use crate::error::SignError; +// #[cfg(feature = "ffi")] +// use std::sync::Arc; #[cfg(feature = "web")] use zklink_sdk_signers::eth_signer::json_rpc_signer::JsonRpcSigner; +#[cfg(not(feature = "web"))] +use zklink_sdk_signers::eth_signer::pk_signer::EthSigner; #[cfg(feature = "web")] use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::StarknetJsonRpcSigner; +use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; #[cfg(not(feature = "web"))] -use zklink_sdk_signers::eth_signer::pk_signer::EthSigner; +use zklink_sdk_signers::starknet_signer::typed_data::TypedData; #[cfg(not(feature = "web"))] use zklink_sdk_signers::starknet_signer::StarkSigner; use zklink_sdk_signers::zklink_signer::pk_signer::ZkLinkSigner; use zklink_sdk_types::basic_types::GetBytes; use zklink_sdk_types::prelude::TxSignature; use zklink_sdk_types::tx_type::transfer::Transfer; -#[cfg(feature = "web")] -use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; #[cfg(not(feature = "web"))] pub fn sign_eth_transfer( @@ -57,7 +60,9 @@ pub async fn sign_starknet_transfer( ) -> Result { tx.signature = zklink_signer.sign_musig(&tx.get_bytes())?; let message = tx.get_starknet_sign_msg(token_symbol); - let starknet_signature = starknet_signer.sign_message(TypedDataMessage::Transaction(message)).await?; + let starknet_signature = starknet_signer + .sign_message(TypedDataMessage::Transaction { message }) + .await?; Ok(TxSignature { tx: tx.into(), @@ -68,14 +73,21 @@ pub async fn sign_starknet_transfer( #[cfg(not(feature = "web"))] pub fn sign_starknet_transfer( signer: &StarkSigner, - zklink_syner: &ZkLinkSigner, + zklink_signer: &ZkLinkSigner, mut tx: Transfer, token_symbol: &str, + chain_id: &str, + addr: &str, ) -> Result { - tx.signature = zklink_syner.sign_musig(&tx.get_bytes())?; - //let message = tx.get_starknet_sign_msg(token_symbol); - let message = tx.get_eth_sign_msg(token_symbol); - let starknet_signature = signer.sign_message(message.as_bytes())?; + tx.signature = zklink_signer.sign_musig(&tx.get_bytes())?; + let message = tx.get_starknet_sign_msg(token_symbol); + // #[cfg(feature = "ffi")] + // let message = Arc::new(message); + let typed_data = TypedData::new( + TypedDataMessage::Transaction { message }, + chain_id.to_string(), + ); + let starknet_signature = signer.sign_message(&typed_data, addr)?; Ok(TxSignature { tx: tx.into(), diff --git a/interface/src/sign_withdraw.rs b/interface/src/sign_withdraw.rs index 2d454614..d8990bdf 100644 --- a/interface/src/sign_withdraw.rs +++ b/interface/src/sign_withdraw.rs @@ -1,30 +1,39 @@ use crate::error::SignError; +// #[cfg(feature = "ffi")] +// use std::sync::Arc; #[cfg(feature = "web")] use zklink_sdk_signers::eth_signer::json_rpc_signer::JsonRpcSigner; #[cfg(not(feature = "web"))] use zklink_sdk_signers::eth_signer::pk_signer::EthSigner; +#[cfg(feature = "web")] +use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::StarknetJsonRpcSigner; +use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; +#[cfg(not(feature = "web"))] +use zklink_sdk_signers::starknet_signer::typed_data::TypedData; #[cfg(not(feature = "web"))] use zklink_sdk_signers::starknet_signer::StarkSigner; use zklink_sdk_signers::zklink_signer::pk_signer::ZkLinkSigner; use zklink_sdk_types::prelude::TxSignature; use zklink_sdk_types::tx_type::withdraw::Withdraw; use zklink_sdk_types::tx_type::ZkSignatureTrait; -#[cfg(feature = "web")] -use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::StarknetJsonRpcSigner; -#[cfg(feature = "web")] -use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; - #[cfg(not(feature = "web"))] pub fn sign_starknet_withdraw( signer: &StarkSigner, zklink_singer: &ZkLinkSigner, mut tx: Withdraw, l2_source_token_symbol: &str, + chain_id: &str, + addr: &str, ) -> Result { tx.sign(zklink_singer)?; - //todo: use eip712 - let message = tx.get_eth_sign_msg(l2_source_token_symbol); - let signature = signer.sign_message(message.as_bytes())?; + let message = tx.get_starknet_sign_msg(l2_source_token_symbol); + // #[cfg(feature = "ffi")] + // let message = Arc::new(message); + let typed_data = TypedData::new( + TypedDataMessage::Transaction { message }, + chain_id.to_string(), + ); + let signature = signer.sign_message(&typed_data, addr)?; Ok(TxSignature { tx: tx.into(), @@ -75,7 +84,9 @@ pub async fn sign_starknet_withdraw( ) -> Result { tx.sign(zklink_singer)?; let message = tx.get_starknet_sign_msg(l2_source_token_symbol); - let stark_signature = stark_signer.sign_message(TypedDataMessage::Transaction(message)).await?; + let stark_signature = stark_signer + .sign_message(TypedDataMessage::Transaction { message }) + .await?; Ok(TxSignature { tx: tx.into(), diff --git a/interface/src/signer.rs b/interface/src/signer.rs index a19a18a6..b093adad 100644 --- a/interface/src/signer.rs +++ b/interface/src/signer.rs @@ -126,6 +126,8 @@ impl Signer { &self, tx: Transfer, token_symbol: &str, + chain_id: Option, + addr: Option, ) -> Result { #[cfg(feature = "ffi")] let tx = (*tx).clone(); @@ -133,9 +135,14 @@ impl Signer { Layer1Sginer::EthSigner(signer) => { sign_eth_transfer(signer, &self.zklink_signer, tx, token_symbol) } - Layer1Sginer::StarknetSigner(signer) => { - sign_starknet_transfer(signer, &self.zklink_signer, tx,token_symbol) - } + Layer1Sginer::StarknetSigner(signer) => sign_starknet_transfer( + signer, + &self.zklink_signer, + tx, + token_symbol, + &chain_id.unwrap(), + &addr.unwrap(), + ), } } @@ -144,6 +151,8 @@ impl Signer { &self, tx: Withdraw, l2_source_token_symbol: &str, + chain_id: Option, + addr: Option, ) -> Result { #[cfg(feature = "ffi")] let tx = (*tx).clone(); @@ -151,9 +160,14 @@ impl Signer { Layer1Sginer::EthSigner(signer) => { sign_eth_withdraw(signer, &self.zklink_signer, tx, l2_source_token_symbol) } - Layer1Sginer::StarknetSigner(signer) => { - sign_starknet_withdraw(signer, &self.zklink_signer, tx,l2_source_token_symbol) - } + Layer1Sginer::StarknetSigner(signer) => sign_starknet_withdraw( + signer, + &self.zklink_signer, + tx, + l2_source_token_symbol, + &chain_id.unwrap(), + &addr.unwrap(), + ), } } diff --git a/signers/Cargo.toml b/signers/Cargo.toml index 6d2864d5..847d7b64 100644 --- a/signers/Cargo.toml +++ b/signers/Cargo.toml @@ -11,6 +11,7 @@ franklin_crypto = { package = "franklin-crypto", version = "0.0.5", git = "https hex = "0.4" js-sys = "0.3.64" k256 = { version = "0.13.1", features = ["ecdsa","sha256"] } +num = { version = "0.4", features = ["serde"] } primitive-types = { version = "0.12", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.5" @@ -19,13 +20,10 @@ serde_json = "1.0" sha2 = "0.10" starknet = { git = "https://github.com/xJonathanLEI/starknet-rs" } starknet-signers = { git = "https://github.com/xJonathanLEI/starknet-rs" } -starknet-crypto = "0.6.1" thiserror = "1.0" wasm-bindgen = { version = "0.2.87", features = ["serde-serialize"] } wasm-bindgen-futures = "0.4" zklink_sdk_utils = { path = "../utils" } -web-sys = "0.3" -num = { version = "0.4", features = ["serde"] } [features] default = [] diff --git a/signers/src/starknet_signer/ecdsa_signature.rs b/signers/src/starknet_signer/ecdsa_signature.rs index fae3c0de..990893d5 100644 --- a/signers/src/starknet_signer/ecdsa_signature.rs +++ b/signers/src/starknet_signer/ecdsa_signature.rs @@ -1,17 +1,16 @@ #![allow(dead_code)] use super::error::StarkSignerError; -use crate::starknet_signer::pk_signer::StarkSigner; +use crate::starknet_signer::typed_data::TypedData; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use starknet::core::crypto::Signature; use starknet::core::types::FieldElement; use starknet_signers::VerifyingKey; use std::fmt; use std::fmt::Formatter; -use zklink_sdk_utils::serde::ZeroPrefixHexSerde; -use num::BigUint; use std::str::FromStr; +use zklink_sdk_utils::serde::ZeroPrefixHexSerde; -#[derive(Clone, PartialEq,Serialize, Deserialize,Eq,Debug)] +#[derive(Clone, PartialEq, Serialize, Deserialize, Eq, Debug)] pub struct StarkSignature { pub s: FieldElement, pub r: FieldElement, @@ -32,22 +31,20 @@ impl StarkSignature { hex::encode(bytes) } - pub fn from_hex(s: &str) -> Result { let s = s.strip_prefix("0x").unwrap_or(s); let bytes = hex::decode(s).map_err(StarkSignerError::invalid_signature)?; Self::from_bytes_be(&bytes) } - pub fn from_str(r:&str,s: &str) -> Result { + pub fn from_str(r: &str, s: &str) -> Result { let r = FieldElement::from_str(r) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; let s = FieldElement::from_str(s) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; - Ok(Self { s,r }) + Ok(Self { s, r }) } - pub fn from_bytes_be(bytes: &[u8]) -> Result { let mut s = [0_u8; 32]; let mut r = [0_u8; 32]; @@ -111,9 +108,11 @@ impl StarkECDSASignature { } impl StarkECDSASignature { - pub fn verify(&self, msg: &[u8]) -> Result { + pub fn verify(&self, msg: &TypedData, addr: &str) -> Result { + let addr = FieldElement::from_hex_be(addr) + .map_err(|e| StarkSignerError::SignError(e.to_string()))?; + let hash = msg.get_message_hash(addr)?; let verifying_key = VerifyingKey::from_scalar(self.pub_key); - let hash = StarkSigner::get_msg_hash(msg); let is_ok = verifying_key .verify( &hash, diff --git a/signers/src/starknet_signer/pk_signer.rs b/signers/src/starknet_signer/pk_signer.rs index 6d974850..993e9fe4 100644 --- a/signers/src/starknet_signer/pk_signer.rs +++ b/signers/src/starknet_signer/pk_signer.rs @@ -1,5 +1,6 @@ use super::error::StarkSignerError as Error; use crate::starknet_signer::ecdsa_signature::StarkSignature; +use crate::starknet_signer::typed_data::TypedData; use crate::starknet_signer::StarkECDSASignature; use starknet::core::crypto::compute_hash_on_elements; use starknet::core::types::FieldElement; @@ -32,8 +33,9 @@ impl StarkSigner { /// 1. get the hash of the message /// 2. sign hash - pub fn sign_message(&self, msg: &[u8]) -> Result { - let hash = Self::get_msg_hash(msg); + pub fn sign_message(&self, msg: &TypedData, addr: &str) -> Result { + let addr = FieldElement::from_hex_be(addr).map_err(|e| Error::SignError(e.to_string()))?; + let hash = msg.get_message_hash(addr)?; let signature = self .0 .sign(&hash) @@ -62,13 +64,14 @@ impl StarkSigner { #[cfg(test)] mod tests { use super::*; - use serde::{Deserialize, Serialize}; + use crate::starknet_signer::typed_data::message::{TxMessage, TypedDataMessage}; use crate::starknet_signer::typed_data::TypedData; - use crate::starknet_signer::typed_data::message::{TypedDataMessage, Message, TxMessage}; + use serde::{Deserialize, Serialize}; + use starknet::core::crypto::Signature; use starknet_signers::VerifyingKey; - use num::BigUint; use std::str::FromStr; - use starknet::core::crypto::Signature; + #[cfg(feature = "ffi")] + use std::sync::Arc; #[derive(Serialize, Deserialize, Debug)] struct TestSignature { @@ -80,24 +83,21 @@ mod tests { let private_key = "0x02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"; let stark_signer = StarkSigner::new_from_hex_str(private_key).unwrap(); let msg_hash = "0x51d5faacb1bdeb6293d52fd4be0a7c62417cb73962cdd6aff385b67239cf081"; - let signature = stark_signer.0.sign(&FieldElement::from_hex_be(msg_hash).unwrap()).unwrap(); + let signature = stark_signer + .0 + .sign(&FieldElement::from_hex_be(msg_hash).unwrap()) + .unwrap(); //let pub_key = stark_signer.public_key(); let pub_key = "0x3b478eae5afdd35358abcc7955bba7acda3d16f4485b62f2497f78ed6bc7126"; let verifying_key = VerifyingKey::from_scalar(FieldElement::from_hex_be(pub_key).unwrap()); let is_ok = verifying_key - .verify( - &FieldElement::from_hex_be(msg_hash).unwrap(), - &signature - ) + .verify(&FieldElement::from_hex_be(msg_hash).unwrap(), &signature) .unwrap(); - println!("{:?}",is_ok); - + println!("{:?}", is_ok); } #[test] fn test_signature_verify() { - let r_str = "1242659239673499744454485192657408749892787349417938392478090301874476933289"; - let s_str = "3203688086163592132535350422117785905751559823323905824858605377390311728388"; let pubkey = "1082125475812817975721104073212648033952831721853656627074253194227094744819"; let msg_hash = "0x51d5faacb1bdeb6293d52fd4be0a7c62417cb73962cdd6aff385b67239cf081"; let sig_str = "0x02647618b4fe405d0dccbdfd25c20bfdeb87631a332491c633943e6f59f16ef306f72dfce21313b636bef4afff3fdc929e5c3d01e3a1f586690ef7db7ebc280a042b54b6bfc5970163d3b9166fd8f24671dfbf850554eeaf12a5e8f4db06c7f3"; @@ -114,9 +114,13 @@ mod tests { }; let message = transfer.clone(); - let typed_data = TypedData::new(TypedDataMessage::Transaction(transfer),"SN_GOERLI".to_string()); - let msg_hash = typed_data.get_message_hash(addr.to_string()).unwrap(); - println!("{:?}",msg_hash); + let typed_data = TypedData::new( + TypedDataMessage::Transaction { message }, + "SN_GOERLI".to_string(), + ); + let addr = FieldElement::from_hex_be(&addr).unwrap(); + let msg_hash = typed_data.get_message_hash(addr).unwrap(); + println!("{:?}", msg_hash); let signature = StarkECDSASignature::from_hex(sig_str).unwrap(); let verifying_key = VerifyingKey::from_scalar(pub_key); let is_ok = verifying_key diff --git a/signers/src/starknet_signer/starknet_json_rpc_signer.rs b/signers/src/starknet_signer/starknet_json_rpc_signer.rs index 54c52796..32ed15f8 100644 --- a/signers/src/starknet_signer/starknet_json_rpc_signer.rs +++ b/signers/src/starknet_signer/starknet_json_rpc_signer.rs @@ -1,11 +1,10 @@ -use wasm_bindgen::prelude::*; -use crate::starknet_signer::{StarkSignature, StarkECDSASignature}; use crate::starknet_signer::error::StarkSignerError; use crate::starknet_signer::typed_data::message::TypedDataMessage; +use crate::starknet_signer::typed_data::TypedData; +use crate::starknet_signer::{StarkECDSASignature, StarkSignature}; use starknet::core::types::FieldElement; use std::str::FromStr; -use serde::Serialize; -use crate::starknet_signer::typed_data::TypedData; +use wasm_bindgen::prelude::*; #[wasm_bindgen] // Rustfmt removes the 'async' keyword from async functions in extern blocks. It's fixed @@ -29,15 +28,19 @@ pub struct StarknetJsonRpcSigner { } impl StarknetJsonRpcSigner { - pub fn new(signer: Signer,pub_key: String,chain_id: String) -> StarknetJsonRpcSigner{ - StarknetJsonRpcSigner { signer,pub_key,chain_id } + pub fn new(signer: Signer, pub_key: String, chain_id: String) -> StarknetJsonRpcSigner { + StarknetJsonRpcSigner { + signer, + pub_key, + chain_id, + } } pub async fn sign_message( &self, message: TypedDataMessage, ) -> Result { - let typed_data = TypedData::new(message,self.chain_id.clone()); + let typed_data = TypedData::new(message, self.chain_id.clone()); let typed_data = serde_wasm_bindgen::to_value(&typed_data) .map_err(|e| StarkSignerError::SignError(e.to_string()))?; let signature = self.signer.signMessage(&typed_data).await.map_err(|e| { @@ -48,25 +51,10 @@ impl StarknetJsonRpcSigner { let signature: Vec = serde_wasm_bindgen::from_value::>(signature) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; - let signature = StarkSignature::from_str(&signature[0],&signature[1]) + let signature = StarkSignature::from_str(&signature[0], &signature[1]) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; let pub_key = FieldElement::from_str(&self.pub_key) .map_err(|e| StarkSignerError::SignError(e.to_string()))?; - Ok(StarkECDSASignature { - pub_key, - signature, - }) + Ok(StarkECDSASignature { pub_key, signature }) } } - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_typed_data() { - let typed_data = TypedData::new("123".to_string()); - let typed_data = serde_json::to_string(&typed_data) - .unwrap(); - println!("{:?}",typed_data); - } -} \ No newline at end of file diff --git a/signers/src/starknet_signer/typed_data/message.rs b/signers/src/starknet_signer/typed_data/message.rs index e354ba80..91f7583a 100644 --- a/signers/src/starknet_signer/typed_data/message.rs +++ b/signers/src/starknet_signer/typed_data/message.rs @@ -1,6 +1,6 @@ -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; -#[derive(Serialize, Deserialize,Debug,Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct TxMessage { pub transaction: String, pub amount: String, @@ -10,14 +10,25 @@ pub struct TxMessage { pub nonce: String, } -#[derive(Serialize, Deserialize,Debug)] +#[derive(Serialize, Deserialize, Debug)] pub struct Message { - pub data: String + pub data: String, } -#[derive(Serialize, Deserialize,Debug)] -#[serde(untagged)] +#[derive(Debug)] pub enum TypedDataMessage { - CreateL2Key(Message), - Transaction(TxMessage), -} \ No newline at end of file + CreateL2Key { message: Message }, + Transaction { message: TxMessage }, +} + +impl Serialize for TypedDataMessage { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + TypedDataMessage::CreateL2Key { message } => message.serialize(serializer), + TypedDataMessage::Transaction { message } => message.serialize(serializer), + } + } +} diff --git a/signers/src/starknet_signer/typed_data/mod.rs b/signers/src/starknet_signer/typed_data/mod.rs index a179fd46..970f929a 100644 --- a/signers/src/starknet_signer/typed_data/mod.rs +++ b/signers/src/starknet_signer/typed_data/mod.rs @@ -1,34 +1,39 @@ pub mod message; -use serde::{Deserialize, Serialize}; -use crate::starknet_signer::typed_data::message::TypedDataMessage; use crate::starknet_signer::error::StarkSignerError; +use crate::starknet_signer::typed_data::message::TypedDataMessage; use num::{BigUint, Num}; -use starknet_crypto::FieldElement; +use serde::{Deserialize, Serialize}; +use starknet::core::crypto::compute_hash_on_elements; +use starknet::core::types::FieldElement; use starknet::core::utils::starknet_keccak; +use std::fmt::Debug; +use std::str::FromStr; +// #[cfg(feature = "ffi")] +// use std::sync::Arc; -#[derive(Serialize, Deserialize,Debug)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct StarknetDomain { pub name: String, pub version: String, - pub chain_id: String + pub chain_id: String, } -#[derive(Serialize, Deserialize,Debug,Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct TypeDefine { pub name: String, pub r#type: String, } -#[derive(Serialize, Deserialize,Debug)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct DataType { pub stark_net_domain: Vec, - pub message: Vec + pub message: Vec, } -#[derive(Serialize, Deserialize,Debug)] +#[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct TypedData { pub types: DataType, @@ -38,16 +43,25 @@ pub struct TypedData { } impl TypedData { - pub fn new(message: TypedDataMessage,chain_id: String) -> Self { + pub fn new(message: TypedDataMessage, chain_id: String) -> Self { let starknet_domain_type = vec![ - TypeDefine { name: "name".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "version".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "chainId".to_string(), r#type: "string".to_string() }, + TypeDefine { + name: "name".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "version".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "chainId".to_string(), + r#type: "string".to_string(), + }, ]; let message_type = Self::get_message_type(&message); let types = DataType { stark_net_domain: starknet_domain_type, - message: message_type + message: message_type, }; let domain = StarknetDomain { name: "zklink".to_string(), @@ -58,39 +72,58 @@ impl TypedData { types, primary_type: "Message".to_string(), domain, - message + message, } } pub fn get_message_type(data_type: &TypedDataMessage) -> Vec { match data_type { - TypedDataMessage::CreateL2Key(_) => { - vec![ - TypeDefine { name: "data".to_string(), r#type: "string".to_string() }, - ] - }, - TypedDataMessage::Transaction(_) => { + TypedDataMessage::CreateL2Key { .. } => { + vec![TypeDefine { + name: "data".to_string(), + r#type: "string".to_string(), + }] + } + TypedDataMessage::Transaction { .. } => { vec![ - TypeDefine { name: "transaction".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "amount".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "fee".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "token".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "to".to_string(), r#type: "string".to_string() }, - TypeDefine { name: "nonce".to_string(), r#type: "string".to_string() }, + TypeDefine { + name: "transaction".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "amount".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "fee".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "token".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "to".to_string(), + r#type: "string".to_string(), + }, + TypeDefine { + name: "nonce".to_string(), + r#type: "string".to_string(), + }, ] - }, + } } } fn string_to_hex(s: &str) -> String { - if let Ok(num) = BigUint::from_str_radix(s.trim_start_matches("0x"),16) { - format!("0x{}",num.to_str_radix(16)) + if let Ok(num) = BigUint::from_str_radix(s.trim_start_matches("0x"), 16) { + format!("0x{}", num.to_str_radix(16)) } else { - format!("0x{}",hex::encode(s)) + format!("0x{}", hex::encode(s)) } } - pub fn get_type_define(&self,struct_type: &str) -> Vec { + pub fn get_type_define(&self, struct_type: &str) -> Vec { if struct_type == "StarkNetDomain" { self.types.stark_net_domain.clone() } else if struct_type == "Message" { @@ -100,12 +133,12 @@ impl TypedData { } } - pub fn encode_type(&self,struct_type: &str) -> String { + pub fn encode_type(&self, struct_type: &str) -> String { let td = self.get_type_define(struct_type); let mut ret = struct_type.to_string() + "("; let mut fields = vec![]; for t in td { - let field = format!("{}:{}",t.name,t.r#type); + let field = format!("{}:{}", t.name, t.r#type); fields.push(field); } ret += &fields.join(","); @@ -113,28 +146,18 @@ impl TypedData { ret } - pub fn compute_hash_on_elements(data: Vec) -> Result { - let mut result = FieldElement::from(0u32); - for e in &data { - let fe = FieldElement::from_hex_be(e) - .map_err(|e| StarkSignerError::SignError(e.to_string()))?; - result = starknet_crypto::pedersen_hash(&result, &fe); - } - - let data_len = FieldElement::from(data.len()); - Ok(starknet_crypto::pedersen_hash(&result, &data_len)) - } - - pub fn get_struct_hash(&self,struct_type: &str,data: &T) -> Result<[u8;32],StarkSignerError> { + pub fn get_struct_hash( + &self, + struct_type: &str, + data: &M, + ) -> Result { let mut types_arry = vec![]; let mut data_arry = vec![]; types_arry.push("felt".to_string()); - let encoded_type = self.encode_type(struct_type); - println!("{}",encoded_type); let type_hash = starknet_keccak(self.encode_type(struct_type).as_bytes()); - data_arry.push(format!("0x{}",hex::encode(type_hash.to_bytes_be()))); - let data_value = serde_json::to_value(data) - .map_err(|e| StarkSignerError::SignError(e.to_string()))?; + data_arry.push(type_hash); + let data_value = + serde_json::to_value(data).map_err(|e| StarkSignerError::SignError(e.to_string()))?; let data_map = data_value.as_object().unwrap(); //type must be exist let td = self.get_type_define(struct_type); @@ -145,51 +168,30 @@ impl TypedData { for t in td { types_arry.push(t.r#type.clone()); let v_str = data_map.get(&t.name).unwrap().as_str().unwrap(); - let v = Self::string_to_hex(&v_str); + let v = Self::string_to_hex(v_str); + let v = FieldElement::from_hex_be(&v) + .map_err(|e| StarkSignerError::SignError(e.to_string()))?; data_arry.push(v); } - println!("{:?}",data_arry); - let result = Self::compute_hash_on_elements(data_arry)?; - Ok(result.to_bytes_be()) + Ok(compute_hash_on_elements(&data_arry)) } - pub fn encode(&self,addr: String) -> Result, StarkSignerError> { - let domain = self.get_struct_hash("StarkNetDomain", &self.domain) + pub fn encode(&self, addr: FieldElement) -> Result, StarkSignerError> { + let domain = self + .get_struct_hash("StarkNetDomain", &self.domain) .map_err(|e| StarkSignerError::SignError(e.to_string()))?; - let message = self.get_struct_hash("Message",&self.message) + let message = self + .get_struct_hash("Message", &self.message) .map_err(|e| StarkSignerError::SignError(e.to_string()))?; //StarkNet Message - let stark_net_message = Self::string_to_hex("StarkNet Message"); - Ok(vec![stark_net_message,format!("0x{}",hex::encode(&domain)),addr,format!("0x{}",hex::encode(&message))]) + let stark_net_message = + FieldElement::from_str(&Self::string_to_hex("StarkNet Message")).unwrap(); + Ok(vec![stark_net_message, domain, addr, message]) } - pub fn get_message_hash(&self,addr: String) -> Result { + pub fn get_message_hash(&self, addr: FieldElement) -> Result { let data = self.encode(addr)?; - println!("{:?}",data); - Ok(Self::compute_hash_on_elements(data)?) + Ok(compute_hash_on_elements(&data)) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::starknet_signer::typed_data::message::Message; - use num::Num; - - #[test] - fn test_typed_data() { - let addr = "04a69b67bcabfa7d3ccb96e1d25c2e6fc93589fe24a6fd04566b8700ff97a71a"; - let message = Message { - data: "Create zkLink L2".to_string() - }; - - let s = "0x5505a8cd4594dbf79d8c59c0df1414ab871ca896"; - BigUint::from_str_radix(s.trim_start_matches("0x"),16).unwrap(); - let typed_data = TypedData::new(TypedDataMessage::CreateL2Key(message),"SN_GOERLI".to_string()); - let data = typed_data.encode( - "0x04a69b67bcabfa7d3ccb96e1d25c2e6fc93589fe24a6fd04566b8700ff97a71a".to_string()).unwrap(); - println!("{:?}",data); - - } -} \ No newline at end of file diff --git a/signers/src/zklink_signer/pk_signer.rs b/signers/src/zklink_signer/pk_signer.rs index e6921eec..e3f56172 100755 --- a/signers/src/zklink_signer/pk_signer.rs +++ b/signers/src/zklink_signer/pk_signer.rs @@ -12,15 +12,17 @@ use franklin_crypto::bellman::{PrimeField, PrimeFieldRepr}; use franklin_crypto::eddsa::{PrivateKey as FLPrivateKey, PrivateKey, PublicKey, Seed}; use sha2::{Digest, Sha256}; use std::fmt; +// #[cfg(feature = "ffi")] +// use std::sync::Arc; #[cfg(feature = "web")] use crate::eth_signer::json_rpc_signer::JsonRpcSigner; +use crate::eth_signer::pk_signer::EthSigner; #[cfg(feature = "web")] use crate::starknet_signer::starknet_json_rpc_signer::StarknetJsonRpcSigner; -use crate::eth_signer::pk_signer::EthSigner; +use crate::starknet_signer::typed_data::message::{Message, TypedDataMessage}; +use crate::starknet_signer::typed_data::TypedData; use crate::starknet_signer::StarkSigner; -#[cfg(feature = "web")] -use crate::starknet_signer::typed_data::message::{TypedDataMessage, Message}; pub struct ZkLinkSigner(EddsaPrivKey); @@ -58,9 +60,7 @@ pub fn sha256_bytes(input: &[u8]) -> Vec { impl ZkLinkSigner { const SIGN_MESSAGE: &'static str = "Sign this message to create a key to interact with zkLink's layer2 services.\nNOTE: This application is powered by zkLink protocol.\n\nOnly sign this message for a trusted client!"; - #[cfg(feature = "web")] - const STARKNET_SIGN_MESSAGE: &'static str = - "Create zkLink's layer2 key.\n"; + const STARKNET_SIGN_MESSAGE: &'static str = "Create zkLink's layer2 key.\n"; pub fn new() -> Result { let eth_pk = H256::random(); let eth_signer = EthSigner::from(eth_pk); @@ -100,9 +100,13 @@ impl ZkLinkSigner { Self::new_from_seed(&seed) } - pub fn new_from_hex_stark_signer(hex_private_key: &str) -> Result { + pub fn new_from_hex_stark_signer( + hex_private_key: &str, + addr: &str, + chain_id: &str, + ) -> Result { let stark_signer = StarkSigner::new_from_hex_str(hex_private_key)?; - Self::new_from_starknet_signer(&stark_signer) + Self::new_from_starknet_signer(&stark_signer, addr, chain_id) } pub fn new_from_eth_signer(eth_signer: &EthSigner) -> Result { @@ -112,8 +116,21 @@ impl ZkLinkSigner { } /// create zkLink signer from starknet signer - pub fn new_from_starknet_signer(starknet_signer: &StarkSigner) -> Result { - let signature = starknet_signer.sign_message(Self::SIGN_MESSAGE.as_bytes())?; + pub fn new_from_starknet_signer( + starknet_signer: &StarkSigner, + addr: &str, + chain_id: &str, + ) -> Result { + let message = Message { + data: Self::STARKNET_SIGN_MESSAGE.to_string(), + }; + // #[cfg(feature = "ffi")] + // let message = Arc::new(message); + let typed_data = TypedData::new( + TypedDataMessage::CreateL2Key { message }, + chain_id.to_string(), + ); + let signature = starknet_signer.sign_message(&typed_data, addr)?; let seed = signature.to_bytes_be(); Self::new_from_seed(&seed) } @@ -128,12 +145,14 @@ impl ZkLinkSigner { } #[cfg(feature = "web")] - pub async fn new_from_starknet_rpc_signer(starknet_signer: &StarknetJsonRpcSigner) -> Result { + pub async fn new_from_starknet_rpc_signer( + starknet_signer: &StarknetJsonRpcSigner, + ) -> Result { let message = Message { - data: Self::STARKNET_SIGN_MESSAGE.to_string() + data: Self::STARKNET_SIGN_MESSAGE.to_string(), }; let signature = starknet_signer - .sign_message(TypedDataMessage::CreateL2Key(message)) + .sign_message(TypedDataMessage::CreateL2Key { message }) .await?; let seed = signature.signature.to_bytes_be(); Self::new_from_seed(&seed) diff --git a/types/src/tx_type/mod.rs b/types/src/tx_type/mod.rs index 6c5429e9..088d5fe6 100644 --- a/types/src/tx_type/mod.rs +++ b/types/src/tx_type/mod.rs @@ -14,11 +14,11 @@ use serde::Serialize; use std::collections::VecDeque; #[cfg(feature = "ffi")] use std::sync::Arc; +use zklink_sdk_signers::starknet_signer::typed_data::message::TxMessage; use zklink_sdk_signers::zklink_signer::error::ZkSignerError; use zklink_sdk_signers::zklink_signer::pk_signer::{sha256_bytes, ZkLinkSigner}; use zklink_sdk_signers::zklink_signer::signature::ZkLinkSignature; use zklink_sdk_signers::zklink_signer::PubKeyHash; -use zklink_sdk_signers::starknet_signer::typed_data::message::TxMessage; pub mod validator; @@ -106,15 +106,14 @@ pub fn starknet_sign_message_part( to: &ZkLinkAddress, nonce: String, ) -> TxMessage { - let message = TxMessage { + TxMessage { transaction: transaction.to_string(), amount: format_units(amount, decimals), token: token_symbol.to_string(), fee: format_units(fee, decimals), to: to.to_string(), nonce, - }; - message + } } /// Formats amount in wei to tokens with precision. diff --git a/types/src/tx_type/transfer.rs b/types/src/tx_type/transfer.rs index 67563682..c286559c 100644 --- a/types/src/tx_type/transfer.rs +++ b/types/src/tx_type/transfer.rs @@ -3,7 +3,9 @@ use crate::basic_types::{ AccountId, GetBytes, Nonce, SubAccountId, TimeStamp, TokenId, ZkLinkAddress, }; use crate::tx_type::validator::*; -use crate::tx_type::{ethereum_sign_message_part, TxTrait, ZkSignatureTrait, starknet_sign_message_part}; +use crate::tx_type::{ + ethereum_sign_message_part, starknet_sign_message_part, TxTrait, ZkSignatureTrait, +}; use crate::params::{SIGNED_TRANSFER_BIT_WIDTH, TOKEN_MAX_PRECISION, TX_TYPE_BIT_WIDTH}; #[cfg(feature = "ffi")] @@ -16,12 +18,13 @@ use std::sync::Arc; use validator::Validate; use zklink_sdk_signers::eth_signer::pk_signer::EthSigner; use zklink_sdk_signers::starknet_signer::error::StarkSignerError; +use zklink_sdk_signers::starknet_signer::typed_data::message::TxMessage; +use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; +use zklink_sdk_signers::starknet_signer::typed_data::TypedData; use zklink_sdk_signers::starknet_signer::StarkSigner; use zklink_sdk_signers::zklink_signer::error::ZkSignerError; use zklink_sdk_signers::zklink_signer::signature::ZkLinkSignature; use zklink_sdk_utils::serde::BigUintSerdeAsRadix10Str; -use zklink_sdk_signers::starknet_signer::typed_data::message::TxMessage; - /// `Transfer` transaction performs a move of funds from one zklink account to another. #[derive(Debug, Clone, Default, Serialize, Deserialize, Validate)] #[serde(rename_all = "camelCase")] @@ -90,7 +93,7 @@ impl Transfer { message } - pub fn get_starknet_sign_msg(&self,token_symbol: &str) -> TxMessage { + pub fn get_starknet_sign_msg(&self, token_symbol: &str) -> TxMessage { starknet_sign_message_part( "Transfer", token_symbol, @@ -131,11 +134,15 @@ impl Transfer { &self, starknet_signer: &StarkSigner, token_symbol: &str, + chain_id: &str, + addr: &str, ) -> Result { - //todo: use eip712 - //let message = self.get_starknet_sign_msg(token_symbol); - let message = self.get_eth_sign_msg(token_symbol); - let signature = starknet_signer.sign_message(message.as_bytes())?; + let message = self.get_starknet_sign_msg(token_symbol); + let typed_data = TypedData::new( + TypedDataMessage::Transaction { message }, + chain_id.to_string(), + ); + let signature = starknet_signer.sign_message(&typed_data, addr)?; let tx_eth_signature = TxLayer1Signature::StarkSignature(signature); Ok(tx_eth_signature) } @@ -145,9 +152,15 @@ impl Transfer { &self, starknet_signer: Arc, token_symbol: &str, + chain_id: &str, + addr: &str, ) -> Result { - let message = self.get_eth_sign_msg(token_symbol); - let signature = starknet_signer.sign_message(message.as_bytes())?; + let message = self.get_starknet_sign_msg(token_symbol); + let typed_data = TypedData::new( + TypedDataMessage::Transaction { message }, + chain_id.to_string(), + ); + let signature = starknet_signer.sign_message(&typed_data, addr)?; let tx_eth_signature = TxLayer1Signature::StarkSignature(signature); Ok(tx_eth_signature) } @@ -263,11 +276,14 @@ mod test { // check starknet signature let private_key_str = "0x02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"; let private_key = StarkSigner::new_from_hex_str(private_key_str).unwrap(); - let message = tx.get_starknet_sign_msg(); - let signature = private_key.sign_message(&message).unwrap(); - let is_ok = signature.verify(&message).unwrap(); + let message = tx.get_starknet_sign_msg("USDC"); + let addr = "0x04A69b67bcaBfA7D3CCb96e1d25C2e6fC93589fE24A6fD04566B8700ff97a71a"; + let typed_data = TypedData::new( + TypedDataMessage::Transaction { message }, + "SN_GOERLI".to_string(), + ); + let signature = private_key.sign_message(&typed_data, addr).unwrap(); + let is_ok = signature.verify(&typed_data, addr).unwrap(); assert!(is_ok); - let starknet_signature = "0x0226424352505249f119fd6913430aad28321afcff18036139b6fa77c4fad6cc064a51bbd082ecb0956589f6089ee24dd9ec32b083f5d56352ca94e5c51d3aa504b98450aa2cc9f9f1f5c0ab47dc28ccff41f7661b6e20181e8204ada6213e1e"; - assert_eq!(signature.as_hex(), starknet_signature); } } diff --git a/types/src/tx_type/withdraw.rs b/types/src/tx_type/withdraw.rs index e12a5aa7..b6ffb543 100644 --- a/types/src/tx_type/withdraw.rs +++ b/types/src/tx_type/withdraw.rs @@ -17,7 +17,9 @@ use crate::params::TOKEN_MAX_PRECISION; #[cfg(feature = "ffi")] use crate::prelude::WithdrawBuilder; use crate::tx_type::validator::*; -use crate::tx_type::{ethereum_sign_message_part, TxTrait, ZkSignatureTrait, starknet_sign_message_part}; +use crate::tx_type::{ + ethereum_sign_message_part, starknet_sign_message_part, TxTrait, ZkSignatureTrait, +}; use zklink_sdk_signers::starknet_signer::typed_data::message::TxMessage; /// `Withdraw` transaction performs a withdrawal of funds from zklink account to L1 account. @@ -97,7 +99,7 @@ impl Withdraw { message } - pub fn get_starknet_sign_msg(&self,token_symbol:&str) -> TxMessage { + pub fn get_starknet_sign_msg(&self, token_symbol: &str) -> TxMessage { starknet_sign_message_part( "Withdraw", token_symbol,