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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use std::{fmt::Debug, fs};
use fuel_tx::Contract;
use fuel_types::{Address, AssetId};
use fuels_types::{
bech32::Bech32Address, constants::BASE_ASSET_ID, errors::Result, input::Input,
transaction_builders::TransactionBuilder, unresolved_bytes::UnresolvedBytes,
};
use crate::{
accounts_utils::{adjust_inputs, adjust_outputs, calculate_base_amount_with_fee},
provider::Provider,
Account, AccountError, AccountResult, ViewOnlyAccount,
};
#[derive(Debug, Clone)]
pub struct Predicate {
address: Bech32Address,
code: Vec<u8>,
data: UnresolvedBytes,
provider: Option<Provider>,
}
impl Predicate {
pub fn address(&self) -> &Bech32Address {
&self.address
}
pub fn data(&self) -> &UnresolvedBytes {
&self.data
}
pub fn provider(&self) -> Option<&Provider> {
self.provider.as_ref()
}
pub fn set_provider(&mut self, provider: Provider) -> &mut Self {
self.provider = Some(provider);
self
}
pub fn from_code(code: Vec<u8>) -> Self {
Self {
address: Self::calculate_address(&code),
code,
data: Default::default(),
provider: None,
}
}
fn calculate_address(code: &[u8]) -> Bech32Address {
let address: Address = (*Contract::root_from_code(code)).into();
address.into()
}
pub fn load_from(file_path: &str) -> Result<Self> {
let code = fs::read(file_path)?;
Ok(Self::from_code(code))
}
pub fn with_data(mut self, data: UnresolvedBytes) -> Self {
self.data = data;
self
}
pub fn with_code(self, code: Vec<u8>) -> Self {
Self {
data: self.data,
provider: self.provider,
..Self::from_code(code)
}
}
pub fn with_provider(mut self, provider: Provider) -> Predicate {
self.set_provider(provider);
self
}
}
impl ViewOnlyAccount for Predicate {
fn address(&self) -> &Bech32Address {
self.address()
}
fn try_provider(&self) -> AccountResult<&Provider> {
self.provider.as_ref().ok_or(AccountError::no_provider())
}
fn set_provider(&mut self, provider: Provider) -> &mut Self {
(self as &mut Predicate).set_provider(provider)
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl Account for Predicate {
async fn get_asset_inputs_for_amount(
&self,
asset_id: AssetId,
amount: u64,
_witness_index: Option<u8>,
) -> Result<Vec<Input>> {
Ok(self
.get_spendable_resources(asset_id, amount)
.await?
.into_iter()
.map(|resource| {
Input::resource_predicate(resource, self.code.clone(), self.data.clone())
})
.collect::<Vec<Input>>())
}
async fn add_fee_resources<Tb: TransactionBuilder>(
&self,
mut tb: Tb,
previous_base_amount: u64,
_witness_index: Option<u8>,
) -> Result<Tb::TxType> {
let consensus_parameters = self
.try_provider()?
.chain_info()
.await?
.consensus_parameters;
tb = tb.set_consensus_parameters(consensus_parameters);
let new_base_amount =
calculate_base_amount_with_fee(&tb, &consensus_parameters, previous_base_amount);
let new_base_inputs = self
.get_asset_inputs_for_amount(BASE_ASSET_ID, new_base_amount, None)
.await?;
adjust_inputs(&mut tb, new_base_inputs);
adjust_outputs(&mut tb, self.address(), new_base_amount);
let tx = tb.build()?;
Ok(tx)
}
}