diff --git a/Cargo.lock b/Cargo.lock index 7237ee942..743894dfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6034,6 +6034,7 @@ dependencies = [ "anyhow", "chrono", "frame-support", + "hex", "log", "parity-scale-codec", "polkadex-primitives", diff --git a/primitives/orderbook/Cargo.toml b/primitives/orderbook/Cargo.toml index 5a4b1bda2..d651d34a0 100644 --- a/primitives/orderbook/Cargo.toml +++ b/primitives/orderbook/Cargo.toml @@ -20,11 +20,12 @@ rand = { version = "0.8.5", optional = true } serde = { workspace = true, default-features = false } serde_with = { version = "3.6.1", features = ["json", "macros"], default-features = false } log = { workspace = true, default-features = false } +serde_json = { workspace = true } anyhow = { version = "1.0.69", default-features = false } rust_decimal = { git = "https://github.com/Polkadex-Substrate/rust-decimal.git", branch = "master", features = [ "scale-codec", ], default-features = false } - +hex = { workspace = true } [dev-dependencies] serde_json = "1.0.94" diff --git a/primitives/orderbook/src/constants.rs b/primitives/orderbook/src/constants.rs index d5fe7f159..a6b7029b6 100644 --- a/primitives/orderbook/src/constants.rs +++ b/primitives/orderbook/src/constants.rs @@ -35,6 +35,8 @@ pub const MAX_PRICE: Balance = 10000000 * UNIT_BALANCE; pub const FEE_POT_PALLET_ID: PalletId = PalletId(*b"ocexfees"); +pub const EXT_WRAP_PREFIX: &str = ""; +pub const EXT_WRAP_POSTFIX: &str = ""; #[cfg(test)] mod test { use crate::constants::{MAX_PRICE, MAX_QTY, POLKADEX_MAINNET_SS58}; diff --git a/primitives/orderbook/src/traits.rs b/primitives/orderbook/src/traits.rs index 865411c81..2b3fe2f6e 100644 --- a/primitives/orderbook/src/traits.rs +++ b/primitives/orderbook/src/traits.rs @@ -111,3 +111,7 @@ impl LiquidityMiningCrowdSourcePallet for () { fn stop_accepting_lmp_withdrawals(_epoch: u16) {} } + +pub trait VerifyExtensionSignature { + fn verify_extension_signature(&self, payload: &str, account_id: &AccountId) -> bool; +} diff --git a/primitives/orderbook/src/types.rs b/primitives/orderbook/src/types.rs index c9d0443e4..e36e3a11f 100644 --- a/primitives/orderbook/src/types.rs +++ b/primitives/orderbook/src/types.rs @@ -41,6 +41,7 @@ use std::{ ops::{Mul, Rem}, str::FromStr, }; + pub type OrderId = H256; /// Defined account information required for the "Orderbook" client. @@ -88,6 +89,14 @@ pub struct Trade { pub time: i64, } +impl VerifyExtensionSignature for MultiSignature { + fn verify_extension_signature(&self, payload: &str, account: &AccountId) -> bool { + let wrapped_payload = crate::constants::EXT_WRAP_PREFIX.to_string() + + payload + crate::constants::EXT_WRAP_POSTFIX; + return self.verify(wrapped_payload.as_bytes(), account); + } +} + impl Trade { /// Depends on the trade side - calculates and provides price and asset information required for /// further balances transfers. @@ -303,8 +312,10 @@ impl WithdrawalRequest { Decimal::from_str(&self.payload.amount) } } + use crate::ingress::{EgressMessages, IngressMessages}; use crate::ocex::TradingPairConfig; +use crate::traits::VerifyExtensionSignature; #[cfg(not(feature = "std"))] use core::{ ops::{Mul, Rem}, @@ -313,6 +324,7 @@ use core::{ use frame_support::{Deserialize, Serialize}; use parity_scale_codec::alloc::string::ToString; use scale_info::prelude::string::String; +use sp_runtime::MultiSignature; use sp_std::collections::btree_map::BTreeMap; /// Withdraw payload requested by user. @@ -644,10 +656,20 @@ impl Order { pub fn verify_signature(&self) -> bool { let payload: OrderPayload = self.clone().into(); let result = self.signature.verify(&payload.encode()[..], &self.user); - if !result { - log::error!(target:"orderbook","Order signature check failed"); + if result { + return true; } - result + log::error!(target:"orderbook","Order signature check failed"); + let payload_str = serde_json::to_string(&payload); + if let Ok(payload_str) = payload_str { + let result = + self.signature.verify_extension_signature(&payload_str, &self.main_account); + if result { + return true; + } + } + log::error!(target:"orderbook","orderbook extension signature check failed"); + false } /// Returns the key used for storing in orderbook @@ -905,6 +927,7 @@ impl From for OrderPayload { } } } + #[cfg(feature = "std")] impl TryFrom for Order { type Error = &'static str; @@ -972,6 +995,26 @@ pub struct WithdrawalDetails { pub signature: Signature, } +impl WithdrawalDetails { + /// Verifies the signature. + pub fn verify_signature(&self) -> bool { + let result = self.signature.verify(self.payload.encode().as_ref(), &self.proxy); + if result { + return true; + } + log::error!(target:"orderbook","Withdrawal signature check failed"); + let payload_str = serde_json::to_string(&self.payload); + if let Ok(payload_str) = payload_str { + let result = self.signature.verify_extension_signature(&payload_str, &self.main); + if result { + return true; + } + } + log::error!(target:"orderbook","Withdrawal extension signature check failed"); + false + } +} + /// Overarching type used by validators when submitting /// their signature for a summary to aggregator #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] @@ -987,10 +1030,13 @@ pub struct ApprovedSnapshot { #[cfg(test)] mod tests { use crate::ingress::{EgressMessages, IngressMessages}; + use crate::traits::VerifyExtensionSignature; use crate::types::UserActions; use polkadex_primitives::{AccountId, AssetId}; use rust_decimal::Decimal; + use sp_runtime::MultiSignature; use std::collections::BTreeMap; + use std::str::FromStr; #[test] pub fn test_serialize_deserialize_user_actions() { @@ -1006,4 +1052,20 @@ mod tests { serde_json::to_vec(&action).unwrap(); } + + #[test] + pub fn verify_signature_from_extension() { + // the string signed by polkadot-js api extension using signRaw + let payload = "hello world!"; + let account = + AccountId::from_str("5FYr5g1maSsAAw6w98xdAytZ6MEQ8sNPgp3PNLgy9o79kMug").unwrap(); + // raw signature from polkadot-js api signRaw + let raw_signature = "36751864552cb500ef323ad1b4bd559ade88cff9b922bfdd0b1c18ace7429f57eacc2421dc3ea38a9c434593461fcae0ffa751280e25fedb48e406e42e0f6b82"; + //convert raw signature to sr25519 signature + let sig = hex::decode(raw_signature).unwrap(); + let sig = sp_core::sr25519::Signature::from_slice(&sig[..]).unwrap(); + let sig = MultiSignature::from(sig); + let result = sig.verify_extension_signature(&payload, &account); + assert_eq!(result, true); + } }