fuel_tx/transaction/types/
output.rs1use fuel_crypto::Hasher;
2use fuel_types::{
3 canonical::{
4 self,
5 Serialize as _,
6 },
7 Address,
8 AssetId,
9 Bytes32,
10 ContractId,
11 Nonce,
12 Word,
13};
14
15mod consts;
16pub mod contract;
17mod repr;
18
19use contract::Contract;
20pub use repr::OutputRepr;
21
22#[derive(
23 Debug,
24 Clone,
25 Copy,
26 PartialEq,
27 Eq,
28 Hash,
29 strum_macros::EnumCount,
30 serde::Serialize,
31 serde::Deserialize,
32)]
33#[cfg_attr(
34 feature = "da-compression",
35 derive(fuel_compression::Compress, fuel_compression::Decompress)
36)]
37#[derive(canonical::Deserialize, canonical::Serialize)]
38pub enum Output {
39 Coin {
40 to: Address,
41 amount: Word,
42 asset_id: AssetId,
43 },
44
45 Contract(Contract),
46
47 Change {
48 to: Address,
49 #[cfg_attr(feature = "da-compression", compress(skip))]
50 amount: Word,
51 asset_id: AssetId,
52 },
53
54 Variable {
55 #[cfg_attr(feature = "da-compression", compress(skip))]
56 to: Address,
57 #[cfg_attr(feature = "da-compression", compress(skip))]
58 amount: Word,
59 #[cfg_attr(feature = "da-compression", compress(skip))]
60 asset_id: AssetId,
61 },
62
63 ContractCreated {
64 contract_id: ContractId,
65 state_root: Bytes32,
66 },
67}
68
69impl Default for Output {
70 fn default() -> Self {
71 Self::ContractCreated {
72 contract_id: Default::default(),
73 state_root: Default::default(),
74 }
75 }
76}
77
78impl Output {
79 pub const fn repr(&self) -> OutputRepr {
80 OutputRepr::from_output(self)
81 }
82
83 pub const fn coin(to: Address, amount: Word, asset_id: AssetId) -> Self {
84 Self::Coin {
85 to,
86 amount,
87 asset_id,
88 }
89 }
90
91 pub const fn contract(
92 input_index: u16,
93 balance_root: Bytes32,
94 state_root: Bytes32,
95 ) -> Self {
96 Self::Contract(Contract {
97 input_index,
98 balance_root,
99 state_root,
100 })
101 }
102
103 pub const fn change(to: Address, amount: Word, asset_id: AssetId) -> Self {
104 Self::Change {
105 to,
106 amount,
107 asset_id,
108 }
109 }
110
111 pub const fn variable(to: Address, amount: Word, asset_id: AssetId) -> Self {
112 Self::Variable {
113 to,
114 amount,
115 asset_id,
116 }
117 }
118
119 pub const fn contract_created(contract_id: ContractId, state_root: Bytes32) -> Self {
120 Self::ContractCreated {
121 contract_id,
122 state_root,
123 }
124 }
125
126 pub const fn asset_id(&self) -> Option<&AssetId> {
127 match self {
128 Output::Coin { asset_id, .. }
129 | Output::Change { asset_id, .. }
130 | Output::Variable { asset_id, .. } => Some(asset_id),
131 _ => None,
132 }
133 }
134
135 pub const fn to(&self) -> Option<&Address> {
136 match self {
137 Output::Coin { to, .. }
138 | Output::Change { to, .. }
139 | Output::Variable { to, .. } => Some(to),
140 _ => None,
141 }
142 }
143
144 pub const fn amount(&self) -> Option<Word> {
145 match self {
146 Output::Coin { amount, .. }
147 | Output::Change { amount, .. }
148 | Output::Variable { amount, .. } => Some(*amount),
149 _ => None,
150 }
151 }
152
153 pub const fn input_index(&self) -> Option<u16> {
154 match self {
155 Output::Contract(Contract { input_index, .. }) => Some(*input_index),
156 _ => None,
157 }
158 }
159
160 pub const fn balance_root(&self) -> Option<&Bytes32> {
161 match self {
162 Output::Contract(Contract { balance_root, .. }) => Some(balance_root),
163 _ => None,
164 }
165 }
166
167 pub const fn state_root(&self) -> Option<&Bytes32> {
168 match self {
169 Output::Contract(Contract { state_root, .. })
170 | Output::ContractCreated { state_root, .. } => Some(state_root),
171 _ => None,
172 }
173 }
174
175 pub const fn contract_id(&self) -> Option<&ContractId> {
176 match self {
177 Output::ContractCreated { contract_id, .. } => Some(contract_id),
178 _ => None,
179 }
180 }
181
182 pub const fn is_coin(&self) -> bool {
183 matches!(self, Self::Coin { .. })
184 }
185
186 pub const fn is_change(&self) -> bool {
187 matches!(self, Self::Change { .. })
188 }
189
190 pub const fn is_variable(&self) -> bool {
191 matches!(self, Self::Variable { .. })
192 }
193
194 pub const fn is_contract(&self) -> bool {
195 matches!(self, Self::Contract(_))
196 }
197
198 pub const fn is_contract_created(&self) -> bool {
199 matches!(self, Self::ContractCreated { .. })
200 }
201
202 pub fn message_nonce(txid: &Bytes32, idx: Word) -> Nonce {
203 (*Hasher::default()
204 .chain(txid)
205 .chain(idx.to_bytes())
206 .finalize())
207 .into()
208 }
209
210 pub fn message_digest(data: &[u8]) -> Bytes32 {
211 Hasher::hash(data)
212 }
213
214 pub fn prepare_sign(&mut self) {
216 match self {
217 Output::Contract(contract) => contract.prepare_sign(),
218
219 Output::Change { amount, .. } => {
220 *amount = 0;
221 }
222
223 Output::Variable {
224 to,
225 amount,
226 asset_id,
227 ..
228 } => {
229 *to = Address::default();
230 *amount = 0;
231 *asset_id = AssetId::default();
232 }
233
234 _ => (),
235 }
236 }
237
238 pub fn prepare_init_execute(&mut self) {
241 self.prepare_sign() }
243}
244
245#[cfg(feature = "typescript")]
246pub mod typescript {
247 use wasm_bindgen::prelude::*;
248
249 use super::*;
250
251 use fuel_types::{
252 Address,
253 AssetId,
254 Bytes32,
255 Word,
256 };
257
258 use alloc::{
259 boxed::Box,
260 format,
261 string::String,
262 vec::Vec,
263 };
264
265 #[derive(Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
266 #[wasm_bindgen]
267 pub struct Output(#[wasm_bindgen(skip)] pub Box<crate::Output>);
268
269 #[wasm_bindgen]
270 impl Output {
271 #[wasm_bindgen(js_name = toJSON)]
272 pub fn to_json(&self) -> String {
273 serde_json::to_string(&self.0).expect("unable to json format")
274 }
275
276 #[wasm_bindgen(js_name = toString)]
277 pub fn typescript_to_string(&self) -> String {
278 format!("{:?}", self.0)
279 }
280
281 #[wasm_bindgen(js_name = to_bytes)]
282 pub fn typescript_to_bytes(&self) -> Vec<u8> {
283 use fuel_types::canonical::Serialize;
284 self.0.to_bytes()
285 }
286
287 #[wasm_bindgen(js_name = from_bytes)]
288 pub fn typescript_from_bytes(value: &[u8]) -> Result<Output, js_sys::Error> {
289 use fuel_types::canonical::Deserialize;
290 crate::Output::from_bytes(value)
291 .map(|v| Output(Box::new(v)))
292 .map_err(|e| js_sys::Error::new(&format!("{:?}", e)))
293 }
294
295 #[wasm_bindgen]
296 pub fn coin(to: Address, amount: Word, asset_id: AssetId) -> Output {
297 Output(Box::new(crate::Output::coin(to, amount, asset_id)))
298 }
299
300 #[wasm_bindgen]
301 pub fn contract(
302 input_index: u16,
303 balance_root: Bytes32,
304 state_root: Bytes32,
305 ) -> Output {
306 Output(Box::new(crate::Output::contract(
307 input_index,
308 balance_root,
309 state_root,
310 )))
311 }
312
313 #[wasm_bindgen]
314 pub fn change(to: Address, amount: Word, asset_id: AssetId) -> Output {
315 Output(Box::new(crate::Output::change(to, amount, asset_id)))
316 }
317
318 #[wasm_bindgen]
319 pub fn variable(to: Address, amount: Word, asset_id: AssetId) -> Output {
320 Output(Box::new(crate::Output::variable(to, amount, asset_id)))
321 }
322
323 #[wasm_bindgen]
324 pub fn contract_created(contract_id: ContractId, state_root: Bytes32) -> Output {
325 Output(Box::new(crate::Output::contract_created(
326 contract_id,
327 state_root,
328 )))
329 }
330 }
331}