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);
+ }
}