m10_sdk/types/
action.rs

1use crate::account::{AccountId, AccountIdError};
2use crate::error::M10Error;
3use crate::types::TxId;
4use crate::TransactionExt;
5use core::convert::{From, TryFrom};
6use core::result::Result;
7use m10_protos::sdk;
8use m10_protos::sdk::transaction_data::Data;
9use serde::Serialize;
10use serde_with::serde_as;
11
12#[cfg_attr(feature = "format", derive(parse_display::Display))]
13#[derive(Clone, Debug, Serialize)]
14pub enum Target {
15    Any,
16    #[cfg_attr(feature = "format", display("Account({0})"))]
17    Account(AccountId),
18}
19
20impl From<Target> for sdk::Target {
21    fn from(target: Target) -> Self {
22        let target = match target {
23            Target::Any => sdk::target::Target::AnyAccount(()),
24            Target::Account(id) => sdk::target::Target::AccountId(id.to_vec()),
25        };
26        Self {
27            target: Some(target),
28        }
29    }
30}
31
32impl TryFrom<sdk::Target> for Target {
33    type Error = M10Error;
34
35    fn try_from(target: sdk::Target) -> Result<Self, Self::Error> {
36        Ok(match target.target {
37            Some(sdk::target::Target::AnyAccount(())) => Target::Any,
38            Some(sdk::target::Target::AccountId(id)) => {
39                Target::Account(AccountId::try_from_be_slice(&id)?)
40            }
41            None => return Err(M10Error::InvalidAccountId(AccountIdError::MissingRoot)),
42        })
43    }
44}
45
46#[serde_as]
47#[derive(Clone, Debug, Serialize)]
48pub struct Action {
49    pub tx_id: TxId,
50    #[serde_as(as = "serde_with::hex::Hex")]
51    pub context_id: Vec<u8>,
52    pub name: String,
53    pub from_account: AccountId,
54    pub target: Target,
55    pub payload: Vec<u8>,
56    // @sadroeck TODO: Add timestamps to protobuf
57    // pub timestamp: SystemTime,
58}
59
60#[cfg(feature = "format")]
61impl std::fmt::Display for Action {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        let Self {
64            tx_id,
65            context_id,
66            name,
67            target,
68            payload,
69            ..
70        } = self;
71        write!(
72            f,
73            "Action{{ tx_id={tx_id} name={name} context={} target={target} payload={}",
74            hex::encode(context_id),
75            hex::encode(payload)
76        )
77    }
78}
79
80impl TryFrom<sdk::Action> for Action {
81    type Error = M10Error;
82
83    fn try_from(action: sdk::Action) -> Result<Self, Self::Error> {
84        Ok(Self {
85            tx_id: action.tx_id,
86            context_id: action.context_id,
87            // timestamp: UNIX_EPOCH + Duration::from_micros(action.timestamp),
88            name: action.name,
89            from_account: AccountId::try_from_be_slice(&action.from_account)?,
90            target: Target::try_from(action.target.unwrap())?,
91            payload: action.payload,
92        })
93    }
94}
95
96impl TryFrom<sdk::FinalizedTransaction> for Action {
97    type Error = M10Error;
98
99    fn try_from(txn: sdk::FinalizedTransaction) -> Result<Self, Self::Error> {
100        let response = txn.response.as_ref().ok_or(M10Error::InvalidTransaction)?;
101        let context_id = txn
102            .request
103            .as_ref()
104            .ok_or(M10Error::InvalidTransaction)?
105            .context_id
106            .clone();
107        let tx_id = response.tx_id;
108        // let timestamp = UNIX_EPOCH + Duration::from_micros(response.timestamp);
109        match txn.into_data().ok_or(M10Error::InvalidTransaction)? {
110            Data::InvokeAction(action) => Ok(Self {
111                tx_id,
112                context_id,
113                // timestamp,
114                name: action.name,
115                from_account: AccountId::try_from_be_slice(&action.from_account)?,
116                target: Target::Any,
117                payload: action.payload,
118            }),
119            _ => Err(M10Error::InvalidTransaction),
120        }
121    }
122}