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
78
79
80
81
82
83
84
85
86
87
88
use crate::serialization::{
    HexNumber,
    HexType,
};
use fuel_core_types::{
    fuel_tx::{
        Contract,
        ContractId,
        StorageSlot,
    },
    fuel_types::{
        AssetId,
        BlockHeight,
        Bytes32,
        Salt,
    },
};
use serde::{
    Deserialize,
    Serialize,
};
use serde_with::{
    serde_as,
    skip_serializing_none,
};

#[skip_serializing_none]
#[serde_as]
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct ContractConfig {
    #[serde_as(as = "HexType")]
    pub code: Vec<u8>,
    #[serde_as(as = "HexType")]
    pub salt: Salt,
    #[serde_as(as = "Option<Vec<(HexType, HexType)>>")]
    #[serde(default)]
    pub state: Option<Vec<(Bytes32, Bytes32)>>,
    #[serde_as(as = "Option<Vec<(HexType, HexNumber)>>")]
    #[serde(default)]
    pub balances: Option<Vec<(AssetId, u64)>>,
    /// UtxoId: auto-generated if None
    #[serde_as(as = "Option<HexType>")]
    #[serde(default)]
    pub tx_id: Option<Bytes32>,
    /// UtxoId: auto-generated if None
    #[serde_as(as = "Option<HexNumber>")]
    #[serde(default)]
    pub output_index: Option<u8>,
    /// TxPointer: auto-generated if None
    /// used if contract is forked from another chain to preserve id & tx_pointer
    /// The block height that the contract was last used in
    #[serde_as(as = "Option<HexNumber>")]
    #[serde(default)]
    pub tx_pointer_block_height: Option<BlockHeight>,
    /// TxPointer: auto-generated if None
    /// used if contract is forked from another chain to preserve id & tx_pointer
    /// The index of the originating tx within `tx_pointer_block_height`
    #[serde_as(as = "Option<HexNumber>")]
    #[serde(default)]
    pub tx_pointer_tx_idx: Option<u16>,
}

impl ContractConfig {
    pub fn unpack(self) -> (ContractId, Vec<u8>, Salt, Bytes32, Vec<StorageSlot>) {
        let bytes = self.code;
        let salt = self.salt;
        let slots = self.state.map(|slots| {
            slots
                .into_iter()
                .map(|(key, value)| StorageSlot::new(key, value))
                .collect::<Vec<_>>()
        });
        let state_root = slots
            .as_ref()
            .map(|slots| Contract::initial_state_root(slots.iter()))
            .unwrap_or(Contract::default_state_root());
        let contract = Contract::from(bytes.clone());
        let root = contract.root();
        let contract_id = contract.id(&salt, &root, &state_root);
        (
            contract_id,
            bytes,
            salt,
            state_root,
            slots.unwrap_or_default(),
        )
    }
}