acta_maker_sdk/orders/
mod.rs1use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
2use sha2::{Digest, Sha256};
3use thiserror::Error;
4use zeroize::{Zeroize, ZeroizeOnDrop};
5
6use crate::signing::sign_verified;
7use crate::types::PositionType;
8use crate::wire::{WireError, decode_base58_32, decode_base58_64, encode_base58, encode_hex};
9use crate::{AsyncSignerLike, SigningError};
10
11pub const ORDER_ID_LEN: usize = 32;
12pub const ORDER_DOMAIN_TAG: [u8; 4] = *b"ACTA";
13
14const TAG_LEN: usize = 4;
15const CHAIN_ID_LEN: usize = 8;
16const PUBKEY_LEN: usize = 32;
17const BOOL_LEN: usize = 1;
18const U64_LEN: usize = 8;
19const HEADER_LEN: usize = TAG_LEN + CHAIN_ID_LEN + PUBKEY_LEN;
20
21const OFF_IS_TAKER_BUY: usize = 0;
23const OFF_POSITION_TYPE: usize = OFF_IS_TAKER_BUY + BOOL_LEN;
24const OFF_MARKET: usize = OFF_POSITION_TYPE + BOOL_LEN;
25const OFF_STRIKE: usize = OFF_MARKET + PUBKEY_LEN;
26const OFF_QUANTITY: usize = OFF_STRIKE + U64_LEN;
27const OFF_GROSS_PRICE: usize = OFF_QUANTITY + U64_LEN;
28const OFF_VALID_UNTIL: usize = OFF_GROSS_PRICE + U64_LEN;
29const OFF_MAKER: usize = OFF_VALID_UNTIL + U64_LEN;
30const OFF_TAKER: usize = OFF_MAKER + PUBKEY_LEN;
31const OFF_NONCE: usize = OFF_TAKER + PUBKEY_LEN;
32const _: () = assert!(HEADER_LEN + OFF_NONCE + U64_LEN == ORDER_PREIMAGE_LEN);
33
34pub const ORDER_PREIMAGE_LEN: usize = TAG_LEN
38 + CHAIN_ID_LEN
39 + PUBKEY_LEN
40 + BOOL_LEN
41 + BOOL_LEN
42 + PUBKEY_LEN
43 + U64_LEN
44 + U64_LEN
45 + U64_LEN
46 + U64_LEN
47 + PUBKEY_LEN
48 + PUBKEY_LEN
49 + U64_LEN;
50
51pub trait SignerLike {
56 fn pubkey_bytes(&self) -> [u8; 32];
57 fn sign_message(&self, msg: &[u8]) -> [u8; 64];
58
59 fn pubkey_base58(&self) -> String {
60 encode_base58(&self.pubkey_bytes())
61 }
62
63 fn sign_message_base58(&self, msg: &[u8]) -> String {
64 encode_base58(&self.sign_message(msg))
65 }
66}
67
68#[derive(Clone)]
74pub struct BytesSigner {
75 signing_key: SigningKey,
76 pubkey: [u8; 32],
77}
78
79impl Zeroize for BytesSigner {
80 fn zeroize(&mut self) {
81 let _ = std::mem::replace(&mut self.signing_key, SigningKey::from_bytes(&[0u8; 32]));
82 }
83}
84
85impl ZeroizeOnDrop for BytesSigner {}
86
87impl BytesSigner {
88 pub fn from_secret(mut secret: [u8; 32]) -> Self {
89 let signing_key = SigningKey::from_bytes(&secret);
90 let pubkey = signing_key.verifying_key().to_bytes();
91 secret.zeroize();
92 Self {
93 signing_key,
94 pubkey,
95 }
96 }
97
98 pub fn from_keypair(keypair: &[u8; 64]) -> Result<Self, OrderError> {
99 let mut secret = [0u8; 32];
100 secret.copy_from_slice(&keypair[0..32]);
101 let signer = Self::from_secret(secret);
102 secret.zeroize();
103
104 if signer.pubkey != keypair[32..64] {
105 return Err(OrderError::KeypairPublicKeyMismatch);
106 }
107
108 Ok(signer)
109 }
110}
111
112impl SignerLike for BytesSigner {
113 fn pubkey_bytes(&self) -> [u8; 32] {
114 self.pubkey
115 }
116
117 fn sign_message(&self, msg: &[u8]) -> [u8; 64] {
118 let signature: Signature = self.signing_key.sign(msg);
119 signature.to_bytes()
120 }
121}
122
123#[derive(Debug, Clone)]
124pub struct OrderPreimageArgs {
125 pub chain_id: u64,
126 pub program_id: [u8; 32],
127 pub is_taker_buy: bool,
128 pub position_type: PositionType,
129 pub market: [u8; 32],
130 pub strike: u64,
131 pub quantity: u64,
132 pub gross_price: u64,
133 pub valid_until: u64,
134 pub maker: [u8; 32],
135 pub taker: [u8; 32],
136 pub nonce: u64,
137}
138
139#[derive(Debug, Error)]
140pub enum OrderError {
141 #[error("keypair public key does not match its secret key")]
142 KeypairPublicKeyMismatch,
143 #[error("invalid signing key: {0}")]
144 InvalidSigningKey(String),
145 #[error("invalid verifying key: {0}")]
146 InvalidVerifyingKey(String),
147 #[error("signature verification failed")]
148 InvalidSignature,
149 #[error(transparent)]
150 Wire(#[from] WireError),
151}
152
153pub fn build_order_preimage(args: &OrderPreimageArgs) -> [u8; ORDER_PREIMAGE_LEN] {
154 let mut buf = [0u8; ORDER_PREIMAGE_LEN];
155 buf[0..TAG_LEN].copy_from_slice(&ORDER_DOMAIN_TAG);
156 buf[TAG_LEN..TAG_LEN + CHAIN_ID_LEN].copy_from_slice(&args.chain_id.to_le_bytes());
157 buf[TAG_LEN + CHAIN_ID_LEN..HEADER_LEN].copy_from_slice(&args.program_id);
158
159 let b = HEADER_LEN;
160 buf[b + OFF_IS_TAKER_BUY] = u8::from(args.is_taker_buy);
161 buf[b + OFF_POSITION_TYPE] = args.position_type.into();
162 buf[b + OFF_MARKET..b + OFF_MARKET + PUBKEY_LEN].copy_from_slice(&args.market);
163 buf[b + OFF_STRIKE..b + OFF_STRIKE + U64_LEN].copy_from_slice(&args.strike.to_le_bytes());
164 buf[b + OFF_QUANTITY..b + OFF_QUANTITY + U64_LEN].copy_from_slice(&args.quantity.to_le_bytes());
165 buf[b + OFF_GROSS_PRICE..b + OFF_GROSS_PRICE + U64_LEN]
166 .copy_from_slice(&args.gross_price.to_le_bytes());
167 buf[b + OFF_VALID_UNTIL..b + OFF_VALID_UNTIL + U64_LEN]
168 .copy_from_slice(&args.valid_until.to_le_bytes());
169 buf[b + OFF_MAKER..b + OFF_MAKER + PUBKEY_LEN].copy_from_slice(&args.maker);
170 buf[b + OFF_TAKER..b + OFF_TAKER + PUBKEY_LEN].copy_from_slice(&args.taker);
171 buf[b + OFF_NONCE..b + OFF_NONCE + U64_LEN].copy_from_slice(&args.nonce.to_le_bytes());
172 buf
173}
174
175pub fn hash_order_preimage(preimage: &[u8; ORDER_PREIMAGE_LEN]) -> [u8; ORDER_ID_LEN] {
176 let digest = Sha256::digest(preimage);
177 digest.into()
178}
179
180pub fn compute_order_id(args: &OrderPreimageArgs) -> [u8; ORDER_ID_LEN] {
181 hash_order_preimage(&build_order_preimage(args))
182}
183
184pub fn order_id_hex(order_id: &[u8; ORDER_ID_LEN]) -> String {
185 encode_hex(order_id)
186}
187
188pub fn order_preimage_hex(preimage: &[u8; ORDER_PREIMAGE_LEN]) -> String {
189 encode_hex(preimage)
190}
191
192pub fn sign_order_id_bytes(
193 order_id: &[u8; ORDER_ID_LEN],
194 signing_key_bytes: &[u8; 32],
195) -> Result<[u8; 64], OrderError> {
196 let signing_key = SigningKey::from_bytes(signing_key_bytes);
197 let signature: Signature = signing_key.sign(order_id);
198 Ok(signature.to_bytes())
199}
200
201pub fn sign_order_id_base58(
202 order_id: &[u8; ORDER_ID_LEN],
203 signing_key_bytes: &[u8; 32],
204) -> Result<String, OrderError> {
205 let sig = sign_order_id_bytes(order_id, signing_key_bytes)?;
206 Ok(encode_base58(&sig))
207}
208
209pub fn sign_order_id_with_signer<S: SignerLike>(
210 order_id: &[u8; ORDER_ID_LEN],
211 signer: &S,
212) -> [u8; 64] {
213 signer.sign_message(order_id)
214}
215
216pub fn sign_order_id_with_signer_base58<S: SignerLike>(
217 order_id: &[u8; ORDER_ID_LEN],
218 signer: &S,
219) -> String {
220 signer.sign_message_base58(order_id)
221}
222
223pub async fn sign_order_id_with_async_signer<S: AsyncSignerLike + ?Sized>(
224 order_id: &[u8; ORDER_ID_LEN],
225 signer: &S,
226) -> Result<[u8; 64], SigningError> {
227 sign_verified(signer, order_id).await
228}
229
230pub fn verify_order_id_signature_bytes(
231 order_id: &[u8; ORDER_ID_LEN],
232 signature: &[u8; 64],
233 verifying_key_bytes: &[u8; 32],
234) -> Result<(), OrderError> {
235 let verifying_key = VerifyingKey::from_bytes(verifying_key_bytes)
236 .map_err(|err| OrderError::InvalidVerifyingKey(err.to_string()))?;
237 let signature = Signature::from_bytes(signature);
238 verifying_key
239 .verify(order_id, &signature)
240 .map_err(|_| OrderError::InvalidSignature)
241}
242
243pub fn verify_order_id_signature_base58(
244 order_id_hex: &str,
245 signature_base58: &str,
246 pubkey_base58: &str,
247) -> Result<(), OrderError> {
248 let order_id = decode_hex32(order_id_hex)?;
249 let signature = decode_base58_64(signature_base58)?;
250 let pubkey = decode_base58_32(pubkey_base58)?;
251 verify_order_id_signature_bytes(&order_id, &signature, &pubkey)
252}
253
254pub fn sign_order_id_from_base58_keypair(
255 order_id_hex: &str,
256 keypair_base58: &str,
257) -> Result<String, OrderError> {
258 let order_id = decode_hex32(order_id_hex)?;
259 let keypair = decode_base58_64(keypair_base58)?;
260 let signer = BytesSigner::from_keypair(&keypair)?;
261 Ok(sign_order_id_with_signer_base58(&order_id, &signer))
262}
263
264fn decode_hex32(hex_str: &str) -> Result<[u8; 32], OrderError> {
265 crate::wire::decode_hex_32(hex_str).map_err(OrderError::Wire)
266}