1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use crate::error::{Error, Result};
use crate::model::{Address, Amount, AssetId, Function, StateChanges};
use crate::util::JsonDeserializer;
use serde_json::Value;
use std::borrow::Borrow;

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct InvokeAction {
    dapp: Address,
    function: Function,
    payment: Vec<Amount>,
    state_changes: StateChanges,
}

impl InvokeAction {
    pub fn new(
        dapp: Address,
        function: Function,
        payment: Vec<Amount>,
        state_changes: StateChanges,
    ) -> InvokeAction {
        InvokeAction {
            dapp,
            function,
            payment,
            state_changes,
        }
    }

    pub fn dapp(&self) -> Address {
        self.dapp.clone()
    }

    pub fn function(&self) -> Function {
        self.function.clone()
    }

    pub fn payment(&self) -> Vec<Amount> {
        self.payment.clone()
    }

    pub fn state_changes(&self) -> StateChanges {
        self.state_changes.clone()
    }
}

impl TryFrom<&Value> for InvokeAction {
    type Error = Error;

    fn try_from(value: &Value) -> Result<Self> {
        let dapp = JsonDeserializer::safe_to_string_from_field(value, "dApp")?;
        let function: Function = value.try_into()?;
        let payment: Vec<Amount> = map_payment(value)?;
        let state_changes: StateChanges = value["stateChanges"].borrow().try_into()?;
        Ok(InvokeAction {
            dapp: Address::from_string(&dapp)?,
            function,
            payment,
            state_changes,
        })
    }
}

//todo rm copy past
fn map_payment(value: &Value) -> Result<Vec<Amount>> {
    JsonDeserializer::safe_to_array_from_field(value, "payment")?
        .iter()
        .map(|payment| {
            let value = JsonDeserializer::safe_to_int_from_field(payment, "amount")?;
            let asset_id = match payment["assetId"].as_str() {
                Some(asset) => Some(AssetId::from_string(asset)?),
                None => None,
            };
            Ok(Amount::new(value as u64, asset_id))
        })
        .collect::<Result<Vec<Amount>>>()
}