Skip to content

Commit

Permalink
Add extension sig support (#946)
Browse files Browse the repository at this point in the history
## Describe your changes
- add support for verifying sr25519 signatures from pokadot.js extension
called using signRaw. Enabling orders places via wallets (funding
accounts) to be verified directly.
- `RegisterMainAccount` extrinsic can be deprecated once support added
fully to offchain worker and orderbook, as deposit extrinsic can
directly register the funding account for new users, enabling users to
start trading with one click.
  • Loading branch information
Gauthamastro authored Apr 24, 2024
2 parents 140d32d + 45e5d68 commit 9ae5f59
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 4 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion primitives/orderbook/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions primitives/orderbook/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<Bytes>";
pub const EXT_WRAP_POSTFIX: &str = "</Bytes>";
#[cfg(test)]
mod test {
use crate::constants::{MAX_PRICE, MAX_QTY, POLKADEX_MAINNET_SS58};
Expand Down
4 changes: 4 additions & 0 deletions primitives/orderbook/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ impl<AccountId> LiquidityMiningCrowdSourcePallet<AccountId> for () {

fn stop_accepting_lmp_withdrawals(_epoch: u16) {}
}

pub trait VerifyExtensionSignature<AccountId> {
fn verify_extension_signature(&self, payload: &str, account_id: &AccountId) -> bool;
}
68 changes: 65 additions & 3 deletions primitives/orderbook/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use std::{
ops::{Mul, Rem},
str::FromStr,
};

pub type OrderId = H256;

/// Defined account information required for the "Orderbook" client.
Expand Down Expand Up @@ -88,6 +89,14 @@ pub struct Trade {
pub time: i64,
}

impl VerifyExtensionSignature<AccountId> 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.
Expand Down Expand Up @@ -303,8 +312,10 @@ impl<AccountId: Codec + Clone + TypeInfo> WithdrawalRequest<AccountId> {
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},
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -905,6 +927,7 @@ impl From<Order> for OrderPayload {
}
}
}

#[cfg(feature = "std")]
impl TryFrom<OrderDetails> for Order {
type Error = &'static str;
Expand Down Expand Up @@ -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)]
Expand All @@ -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() {
Expand All @@ -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);
}
}

0 comments on commit 9ae5f59

Please sign in to comment.