use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub const MAX_COMMISSION_FEE_BPS: u8 = 15;
pub const MAX_BUILDER_CODE_FEE_BPS: u8 = MAX_COMMISSION_FEE_BPS;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SignatureDomain {
Mainnet = 1,
Testnet = 2,
Devnet = 3,
}
impl SignatureDomain {
pub const fn as_str(self) -> &'static str {
match self {
Self::Mainnet => "mainnet",
Self::Testnet => "testnet",
Self::Devnet => "devnet",
}
}
}
impl std::fmt::Display for SignatureDomain {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.as_str())
}
}
impl std::str::FromStr for SignatureDomain {
type Err = crate::Error;
fn from_str(value: &str) -> crate::Result<Self> {
match value {
"mainnet" => Ok(Self::Mainnet),
"testnet" => Ok(Self::Testnet),
"devnet" => Ok(Self::Devnet),
_ => Err(crate::Error::InvalidSignatureDomain(value.to_string())),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pubkey(pub [u8; 32]);
impl Pubkey {
pub fn from_bytes(bytes: [u8; 32]) -> Self {
Self(bytes)
}
pub fn from_base58(s: &str) -> crate::Result<Self> {
let bytes = bs58::decode(s)
.into_vec()
.map_err(|e| crate::Error::InvalidBase58(e.to_string()))?;
if bytes.len() != 32 {
return Err(crate::Error::InvalidKeyLength {
expected: 32,
got: bytes.len(),
});
}
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Ok(Self(arr))
}
pub fn to_base58(&self) -> String {
bs58::encode(&self.0).into_string()
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
impl std::fmt::Display for Pubkey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_base58())
}
}
impl Serialize for Pubkey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_base58())
}
}
impl<'de> Deserialize<'de> for Pubkey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Pubkey::from_base58(&s).map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Hash(pub [u8; 32]);
impl Hash {
pub fn from_bytes(bytes: [u8; 32]) -> Self {
Self(bytes)
}
pub fn from_base58(s: &str) -> crate::Result<Self> {
let bytes = bs58::decode(s)
.into_vec()
.map_err(|e| crate::Error::InvalidBase58(e.to_string()))?;
if bytes.len() != 32 {
return Err(crate::Error::InvalidHashLength(bytes.len()));
}
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Ok(Self(arr))
}
pub fn to_base58(&self) -> String {
bs58::encode(&self.0).into_string()
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn random() -> Self {
use rand::Rng;
let mut bytes = [0u8; 32];
rand::thread_rng().fill(&mut bytes);
Self(bytes)
}
#[inline]
pub fn from_wincode_bytes(wincode_bytes: &[u8]) -> Self {
use sha2::{Digest, Sha256};
let hash: [u8; 32] = Sha256::digest(wincode_bytes).into();
Self(hash)
}
}
impl std::fmt::Display for Hash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_base58())
}
}
impl Serialize for Hash {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_base58())
}
}
impl<'de> Deserialize<'de> for Hash {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Hash::from_base58(&s).map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum TimeInForce {
Gtc,
Ioc,
Alo,
}
impl TimeInForce {
pub const fn discriminant(&self) -> u32 {
match self {
Self::Gtc => 0,
Self::Ioc => 1,
Self::Alo => 2,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum OrderType {
Limit { tif: TimeInForce },
Trigger {
#[serde(rename = "isMarket")]
is_market: bool,
#[serde(rename = "triggerPx")]
trigger_px: f64,
},
}
impl OrderType {
pub const fn limit(tif: TimeInForce) -> Self {
Self::Limit { tif }
}
pub const fn market() -> Self {
Self::Trigger {
is_market: true,
trigger_px: 0.0,
}
}
pub const fn discriminant(&self) -> u32 {
match self {
Self::Limit { .. } => 0,
Self::Trigger { .. } => 1,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Order {
#[serde(rename = "c")]
pub symbol: String,
#[serde(rename = "b")]
pub is_buy: bool,
#[serde(rename = "px")]
pub price: f64,
#[serde(rename = "sz")]
pub size: f64,
#[serde(rename = "r")]
pub reduce_only: bool,
#[serde(rename = "i", default)]
pub iso: bool,
#[serde(rename = "t")]
pub order_type: OrderType,
#[serde(rename = "cloid", skip_serializing_if = "Option::is_none")]
pub client_id: Option<Hash>,
#[serde(
rename = "builderCode",
default,
skip_serializing_if = "Option::is_none"
)]
pub commission: Option<Commission>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slippage: Option<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Commission {
pub to: Pubkey,
pub fee: u8,
}
pub type BuilderCode = Commission;
impl Commission {
pub fn new(to: Pubkey, fee: u8) -> crate::Result<Self> {
if fee == 0 || fee > MAX_COMMISSION_FEE_BPS {
return Err(crate::Error::InvalidOrder(
"builder-code fee must be 1..=15 bps".to_string(),
));
}
Ok(Self { to, fee })
}
}
impl Order {
pub fn limit(
symbol: impl Into<String>,
is_buy: bool,
price: f64,
size: f64,
tif: TimeInForce,
) -> Self {
Self {
symbol: symbol.into(),
is_buy,
price,
size,
reduce_only: false,
iso: false,
order_type: OrderType::limit(tif),
client_id: None,
commission: None,
slippage: None,
}
}
pub fn market(symbol: impl Into<String>, is_buy: bool, size: f64) -> Self {
Self {
symbol: symbol.into(),
is_buy,
price: 0.0,
size,
reduce_only: false,
iso: false,
order_type: OrderType::market(),
client_id: None,
commission: None,
slippage: None,
}
}
pub fn reduce_only(mut self) -> Self {
self.reduce_only = true;
self
}
pub fn with_slippage(mut self, slippage: f64) -> Self {
self.slippage = Some(slippage);
self
}
pub fn isolated(mut self) -> Self {
self.iso = true;
self
}
pub fn with_client_id(mut self, client_id: Hash) -> Self {
self.client_id = Some(client_id);
self
}
pub fn iso(mut self) -> Self {
self.iso = true;
self
}
pub fn with_commission(mut self, to: Pubkey, fee: u8) -> crate::Result<Self> {
self.commission = Some(Commission::new(to, fee)?);
Ok(self)
}
pub fn with_builder_code(self, to: Pubkey, fee: u8) -> crate::Result<Self> {
self.with_commission(to, fee)
}
pub fn with_random_client_id(mut self) -> Self {
self.client_id = Some(Hash::random());
self
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Cancel {
#[serde(rename = "c")]
pub symbol: String,
#[serde(rename = "oid")]
pub order_id: Hash,
}
impl Cancel {
pub fn new(symbol: impl Into<String>, order_id: Hash) -> Self {
Self {
symbol: symbol.into(),
order_id,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Modify {
#[serde(rename = "oid")]
pub order_id: Hash,
pub symbol: String,
pub amount: f64,
}
impl Modify {
pub fn new(order_id: Hash, symbol: impl Into<String>, amount: f64) -> Self {
Self {
order_id,
symbol: symbol.into(),
amount,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CancelAll {
#[serde(rename = "c")]
pub symbols: Vec<String>,
}
impl CancelAll {
pub fn all() -> Self {
Self { symbols: vec![] }
}
pub fn for_symbols(symbols: Vec<String>) -> Self {
Self { symbols }
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Stop {
pub symbol: String,
pub is_buy: bool,
pub size: f64,
pub trigger_price: f64,
pub limit_price: f64,
#[serde(default)]
pub iso: bool,
#[serde(
rename = "builderCode",
default,
skip_serializing_if = "Option::is_none"
)]
pub commission: Option<Commission>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slippage: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TakeProfit {
pub symbol: String,
pub is_buy: bool,
pub size: f64,
pub trigger_price: f64,
pub limit_price: f64,
#[serde(default)]
pub iso: bool,
#[serde(
rename = "builderCode",
default,
skip_serializing_if = "Option::is_none"
)]
pub commission: Option<Commission>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slippage: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RangeOco {
pub symbol: String,
pub is_buy: bool,
pub size: f64,
pub collar_min: f64,
pub collar_max: f64,
pub limit_min: f64,
pub limit_max: f64,
#[serde(default)]
pub iso: bool,
#[serde(
rename = "builderCode",
default,
skip_serializing_if = "Option::is_none"
)]
pub commission: Option<Commission>,
#[serde(
rename = "slSlippage",
default,
skip_serializing_if = "Option::is_none"
)]
pub sl_slippage: Option<f64>,
#[serde(
rename = "tpSlippage",
default,
skip_serializing_if = "Option::is_none"
)]
pub tp_slippage: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TriggerBasket {
pub symbol: String,
pub is_buy: bool,
pub trigger_price: f64,
pub actions: Vec<OrderItem>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TrailingStop {
pub symbol: String,
pub is_buy: bool,
pub size: f64,
pub trail_bps: u32,
pub step_bps: u32,
pub limit_price: Option<f64>,
#[serde(default)]
pub iso: bool,
#[serde(
rename = "builderCode",
default,
skip_serializing_if = "Option::is_none"
)]
pub commission: Option<Commission>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slippage: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OnFill {
pub trigger: Box<OrderItem>,
pub actions: Vec<OrderItem>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum OrderItem {
Order(Order),
Modify(Modify),
Cancel(Cancel),
CancelAll(CancelAll),
Stop(Stop),
TakeProfit(TakeProfit),
RangeOco(RangeOco),
TriggerBasket(TriggerBasket),
OnFill(OnFill),
TrailingStop(TrailingStop),
}
impl OrderItem {
pub const fn discriminant(&self) -> u32 {
match self {
Self::Order(order) => match order.order_type {
OrderType::Limit { .. } => 1, OrderType::Trigger { .. } => 0, },
Self::Modify(_) => 2, Self::Cancel(_) => 3, Self::CancelAll(_) => 4, Self::Stop(_) => 5, Self::TakeProfit(_) => 6, Self::RangeOco(_) => 7, Self::TriggerBasket(_) => 8, Self::TrailingStop(_) => 9, Self::OnFill(_) => 10, }
}
}
impl From<Order> for OrderItem {
fn from(order: Order) -> Self {
Self::Order(order)
}
}
impl From<Cancel> for OrderItem {
fn from(cancel: Cancel) -> Self {
Self::Cancel(cancel)
}
}
impl From<Modify> for OrderItem {
fn from(modify: Modify) -> Self {
Self::Modify(modify)
}
}
impl From<CancelAll> for OrderItem {
fn from(cancel_all: CancelAll) -> Self {
Self::CancelAll(cancel_all)
}
}
impl From<Stop> for OrderItem {
fn from(stop: Stop) -> Self {
Self::Stop(stop)
}
}
impl From<TakeProfit> for OrderItem {
fn from(tp: TakeProfit) -> Self {
Self::TakeProfit(tp)
}
}
impl From<RangeOco> for OrderItem {
fn from(rng: RangeOco) -> Self {
Self::RangeOco(rng)
}
}
impl From<TriggerBasket> for OrderItem {
fn from(trig: TriggerBasket) -> Self {
Self::TriggerBasket(trig)
}
}
impl From<OnFill> for OrderItem {
fn from(of: OnFill) -> Self {
Self::OnFill(of)
}
}
impl From<TrailingStop> for OrderItem {
fn from(trl: TrailingStop) -> Self {
Self::TrailingStop(trl)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Faucet {
pub user: Pubkey,
pub amount: Option<f64>,
}
impl Faucet {
pub fn new(user: Pubkey) -> Self {
Self { user, amount: None }
}
pub fn with_amount(user: Pubkey, amount: f64) -> Self {
Self {
user,
amount: Some(amount),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct AgentWallet {
pub agent: Pubkey,
pub delete: bool,
}
impl AgentWallet {
pub fn add(agent: Pubkey) -> Self {
Self {
agent,
delete: false,
}
}
pub fn remove(agent: Pubkey) -> Self {
Self {
agent,
delete: true,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ApproveCommissionFee {
pub to: Pubkey,
pub max_fee: u8,
}
pub type ApproveBuilderCode = ApproveCommissionFee;
#[derive(Debug, Clone, PartialEq)]
pub struct RevokeCommissionFee {
pub to: Pubkey,
}
pub type RevokeBuilderCode = RevokeCommissionFee;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct LiquidatorInstrumentConfig {
pub symbol: String,
pub max_exposure: f64,
pub reserve: f64,
pub rfactor: f64,
pub volume_percent: f64,
pub volume_min: f64,
pub volume_rampup: u64,
pub max_sweep_bps: f64,
pub max_adl_notional: f64,
pub max_adl_percent: f64,
}
impl LiquidatorInstrumentConfig {
pub fn new(symbol: impl Into<String>) -> Self {
Self {
symbol: symbol.into(),
..Self::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct LiquidatorConfig {
pub cross_exposure: f64,
pub scoring_skew: f64,
pub toxicity: f64,
pub urgency_size_fraction: f64,
pub sweep_sds: f64,
pub instruments: Vec<LiquidatorInstrumentConfig>,
}
impl LiquidatorConfig {
pub fn new(
cross_exposure: f64,
scoring_skew: f64,
toxicity: f64,
urgency_size_fraction: f64,
sweep_sds: f64,
) -> Self {
Self {
cross_exposure,
scoring_skew,
toxicity,
urgency_size_fraction,
sweep_sds,
instruments: Vec::new(),
}
}
pub fn with_instrument(mut self, instrument: LiquidatorInstrumentConfig) -> Self {
self.instruments.retain(|i| i.symbol != instrument.symbol);
self.instruments.push(instrument);
self
}
pub fn sorted_instruments(&self) -> Vec<&LiquidatorInstrumentConfig> {
let mut sorted: Vec<_> = self.instruments.iter().collect();
sorted.sort_by(|a, b| a.symbol.cmp(&b.symbol));
sorted
}
}
pub(crate) fn liquidator_config_to_json(config: &LiquidatorConfig) -> serde_json::Value {
let instruments: Vec<_> = config
.sorted_instruments()
.into_iter()
.map(|i| {
serde_json::json!({
"symbol": i.symbol,
"max_exposure": i.max_exposure,
"reserve": i.reserve,
"rfactor": i.rfactor,
"volume_percent": i.volume_percent,
"volume_min": i.volume_min,
"volume_rampup": i.volume_rampup,
"max_sweep_bps": i.max_sweep_bps,
"max_adl_notional": i.max_adl_notional,
"max_adl_percent": i.max_adl_percent,
})
})
.collect();
serde_json::json!({
"cross_exposure": config.cross_exposure,
"scoring_skew": config.scoring_skew,
"toxicity": config.toxicity,
"urgency_size_fraction": config.urgency_size_fraction,
"sweep_sds": config.sweep_sds,
"instruments": instruments,
})
}
#[derive(Debug, Clone, PartialEq)]
pub struct UserSettings {
pub max_leverage: Vec<(String, f64)>,
}
impl UserSettings {
pub fn new(max_leverage: Vec<(String, f64)>) -> Self {
Self { max_leverage }
}
pub fn set_leverage(symbol: impl Into<String>, leverage: f64) -> Self {
Self {
max_leverage: vec![(symbol.into(), leverage)],
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct OraclePrice {
pub timestamp: u64,
pub asset: String,
pub price: f64,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PythOraclePrice {
pub timestamp: u64,
pub feed_index: u64,
pub price: u64,
pub exponent: i16,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WhitelistFaucet {
pub target: Pubkey,
pub whitelist: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CreateSubAccount {
pub name: String,
pub margin_amount: Option<f64>,
}
impl CreateSubAccount {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
margin_amount: None,
}
}
pub fn with_margin(name: impl Into<String>, margin_amount: f64) -> Self {
Self {
name: name.into(),
margin_amount: Some(margin_amount),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RemoveSubAccount {
pub to_remove: Pubkey,
}
impl RemoveSubAccount {
pub fn new(to_remove: Pubkey) -> Self {
Self { to_remove }
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RenameSubAccount {
pub account: Pubkey,
pub name: String,
}
impl RenameSubAccount {
pub fn new(account: Pubkey, name: impl Into<String>) -> Self {
Self {
account,
name: name.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TransferKind {
#[default]
Internal,
External,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Transfer {
pub kind: TransferKind,
pub from: Pubkey,
pub to: Pubkey,
pub margin_amount: f64,
}
impl Transfer {
pub fn internal(from: Pubkey, to: Pubkey, margin_amount: f64) -> Self {
Self {
kind: TransferKind::Internal,
from,
to,
margin_amount,
}
}
pub fn external(from: Pubkey, to: Pubkey, margin_amount: f64) -> Self {
Self {
kind: TransferKind::External,
from,
to,
margin_amount,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Withdraw {
pub user: Pubkey,
pub vault: Pubkey,
pub recipient_token_account: Pubkey,
pub amount: u64,
pub blockhash: Hash,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WithdrawLockRecover {
pub user: Pubkey,
pub hash: Hash,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CreateMultisig {
pub signers: Vec<Pubkey>,
pub threshold: u32,
pub time_lock_secs: u32,
pub proposal_lifetime_secs: u32,
}
impl CreateMultisig {
pub fn new(signers: Vec<Pubkey>, threshold: u32) -> Self {
Self {
signers,
threshold,
time_lock_secs: 0,
proposal_lifetime_secs: 7 * 24 * 3600,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MultisigPropose {
pub multisig: Pubkey,
pub actions: Vec<Action>,
pub proposal_lifetime_secs: Option<u32>,
}
impl MultisigPropose {
pub fn new(multisig: Pubkey, actions: Vec<Action>) -> Self {
Self {
multisig,
actions,
proposal_lifetime_secs: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MultisigApprove {
pub multisig: Pubkey,
pub proposal_id: u64,
}
impl MultisigApprove {
pub fn new(multisig: Pubkey, proposal_id: u64) -> Self {
Self {
multisig,
proposal_id,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MultisigReject {
pub multisig: Pubkey,
pub proposal_id: u64,
}
impl MultisigReject {
pub fn new(multisig: Pubkey, proposal_id: u64) -> Self {
Self {
multisig,
proposal_id,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MultisigCancel {
pub multisig: Pubkey,
pub proposal_id: u64,
}
impl MultisigCancel {
pub fn new(multisig: Pubkey, proposal_id: u64) -> Self {
Self {
multisig,
proposal_id,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MultisigExecute {
pub multisig: Pubkey,
pub proposal_id: u64,
}
impl MultisigExecute {
pub fn new(multisig: Pubkey, proposal_id: u64) -> Self {
Self {
multisig,
proposal_id,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct UpdateMultisigPolicy {
pub multisig: Pubkey,
pub signers: Vec<Pubkey>,
pub threshold: u32,
pub time_lock_secs: u32,
pub proposal_lifetime_secs: u32,
}
impl UpdateMultisigPolicy {
pub fn new(multisig: Pubkey, signers: Vec<Pubkey>, threshold: u32) -> Self {
Self {
multisig,
signers,
threshold,
time_lock_secs: 0,
proposal_lifetime_secs: 7 * 24 * 3600,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Action {
Order { orders: Vec<OrderItem> },
Oracle { oracles: Vec<OraclePrice> },
PythOracle { oracles: Vec<PythOraclePrice> },
Faucet(Faucet),
UpdateUserSettings(UserSettings),
AgentWalletCreation(AgentWallet),
WhitelistFaucet(WhitelistFaucet),
CreateSubAccount(CreateSubAccount),
RemoveSubAccount(RemoveSubAccount),
RenameSubAccount(RenameSubAccount),
Transfer(Transfer),
Withdraw(Withdraw),
WithdrawLockRecover(WithdrawLockRecover),
CreateMultisig(CreateMultisig),
MultisigPropose(MultisigPropose),
MultisigApprove(MultisigApprove),
MultisigReject(MultisigReject),
MultisigCancel(MultisigCancel),
MultisigExecute(MultisigExecute),
UpdateMultisigPolicy(UpdateMultisigPolicy),
ApproveCommissionFee(ApproveCommissionFee),
RevokeCommissionFee(RevokeCommissionFee),
UpdateLiquidatorConfig(LiquidatorConfig),
}
impl Action {
pub const fn discriminant(&self) -> u32 {
match self {
Self::Order { .. } => 0, Self::Oracle { .. } => 5, Self::PythOracle { .. } => 6,
Self::Faucet(_) => 7,
Self::UpdateUserSettings(_) => 9,
Self::AgentWalletCreation(_) => 8,
Self::WhitelistFaucet(_) => 10,
Self::ApproveCommissionFee(_) => 40,
Self::RevokeCommissionFee(_) => 41,
Self::CreateSubAccount(_) => 27,
Self::RemoveSubAccount(_) => 28,
Self::Transfer(_) => 29,
Self::CreateMultisig(_) => 30,
Self::MultisigPropose(_) => 31,
Self::MultisigApprove(_) => 32,
Self::MultisigReject(_) => 33,
Self::MultisigCancel(_) => 34,
Self::MultisigExecute(_) => 35,
Self::UpdateMultisigPolicy(_) => 36,
Self::RenameSubAccount(_) => 37,
Self::Withdraw(_) => 45,
Self::WithdrawLockRecover(_) => 54,
Self::UpdateLiquidatorConfig(_) => 43,
}
}
pub const fn type_str(&self) -> &'static str {
match self {
Self::Order { .. } => "order",
Self::Oracle { .. } => "px",
Self::PythOracle { .. } => "o",
Self::Faucet(_) => "faucet",
Self::UpdateUserSettings(_) => "updateUserSettings",
Self::AgentWalletCreation(_) => "agentWalletCreation",
Self::WhitelistFaucet(_) => "whitelistFaucet",
Self::ApproveCommissionFee(_) => "abc",
Self::RevokeCommissionFee(_) => "rbc",
Self::CreateSubAccount(_) => "createSubAccount",
Self::RemoveSubAccount(_) => "removeSubAccount",
Self::Transfer(_) => "transfer",
Self::CreateMultisig(_) => "createMultisig",
Self::MultisigPropose(_) => "msp",
Self::MultisigApprove(_) => "msa",
Self::MultisigReject(_) => "msr",
Self::MultisigCancel(_) => "msc",
Self::MultisigExecute(_) => "mse",
Self::UpdateMultisigPolicy(_) => "msu",
Self::RenameSubAccount(_) => "renameSubAccount",
Self::Withdraw(_) => "withdraw",
Self::WithdrawLockRecover(_) => "withdrawLockRecover",
Self::UpdateLiquidatorConfig(_) => "liq",
}
}
}
impl From<LiquidatorConfig> for Action {
fn from(config: LiquidatorConfig) -> Self {
Self::UpdateLiquidatorConfig(config)
}
}
impl From<RenameSubAccount> for Action {
fn from(action: RenameSubAccount) -> Self {
Self::RenameSubAccount(action)
}
}
impl From<CreateMultisig> for Action {
fn from(action: CreateMultisig) -> Self {
Self::CreateMultisig(action)
}
}
impl From<MultisigPropose> for Action {
fn from(action: MultisigPropose) -> Self {
Self::MultisigPropose(action)
}
}
impl From<MultisigApprove> for Action {
fn from(action: MultisigApprove) -> Self {
Self::MultisigApprove(action)
}
}
impl From<MultisigReject> for Action {
fn from(action: MultisigReject) -> Self {
Self::MultisigReject(action)
}
}
impl From<MultisigCancel> for Action {
fn from(action: MultisigCancel) -> Self {
Self::MultisigCancel(action)
}
}
impl From<MultisigExecute> for Action {
fn from(action: MultisigExecute) -> Self {
Self::MultisigExecute(action)
}
}
impl From<UpdateMultisigPolicy> for Action {
fn from(action: UpdateMultisigPolicy) -> Self {
Self::UpdateMultisigPolicy(action)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedTransaction {
pub actions: Vec<serde_json::Value>,
#[serde(with = "crate::nonce::serde_decimal")]
pub nonce: u64,
pub account: String,
pub signer: String,
pub signature: String,
#[serde(skip_serializing, skip_deserializing, default)]
pub order_id: Option<String>,
#[serde(skip_serializing, skip_deserializing, default)]
pub order_ids: Option<Vec<String>>,
}
impl SignedTransaction {
pub fn to_json(&self) -> crate::Result<String> {
serde_json::to_string(self).map_err(crate::Error::from)
}
pub fn to_json_bytes(&self) -> crate::Result<Vec<u8>> {
serde_json::to_vec(self).map_err(crate::Error::from)
}
}