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 }
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 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 match txn.into_data().ok_or(M10Error::InvalidTransaction)? {
110 Data::InvokeAction(action) => Ok(Self {
111 tx_id,
112 context_id,
113 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}