fuel_tx/transaction/types/
mint.rs1use crate::{
2 input,
3 output,
4 transaction::{
5 field::TxPointer as TxPointerField,
6 validity::{
7 check_size,
8 FormatValidityChecks,
9 },
10 },
11 ConsensusParameters,
12 TransactionRepr,
13 TxPointer,
14 ValidityError,
15};
16use educe::Educe;
17use fuel_asm::Word;
18use fuel_types::{
19 bytes::WORD_SIZE,
20 AssetId,
21 BlockHeight,
22 Bytes32,
23};
24
25use fuel_types::ChainId;
26
27use fuel_types::canonical::Serialize;
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30pub(crate) struct MintMetadata {
31 pub id: Bytes32,
32}
33
34impl MintMetadata {
35 fn compute<Tx>(tx: &Tx, chain_id: &ChainId) -> Self
36 where
37 Tx: crate::UniqueIdentifier,
38 {
39 let id = tx.id(chain_id);
40
41 Self { id }
42 }
43}
44
45#[derive(Default, Debug, Clone, Educe, serde::Serialize, serde::Deserialize)]
51#[cfg_attr(feature = "da-compression", derive(fuel_compression::Compress))]
52#[derive(fuel_types::canonical::Deserialize, fuel_types::canonical::Serialize)]
53#[canonical(prefix = TransactionRepr::Mint)]
54#[educe(Eq, PartialEq, Hash)]
55pub struct Mint {
56 #[cfg_attr(feature = "da-compression", compress(skip))]
58 pub(crate) tx_pointer: TxPointer,
59 pub(crate) input_contract: input::contract::Contract,
61 pub(crate) output_contract: output::contract::Contract,
63 pub(crate) mint_amount: Word,
65 pub(crate) mint_asset_id: AssetId,
67 pub(crate) gas_price: Word,
69 #[serde(skip)]
70 #[educe(PartialEq(ignore))]
71 #[educe(Hash(ignore))]
72 #[canonical(skip)]
73 #[cfg_attr(feature = "da-compression", compress(skip))]
74 pub(crate) metadata: Option<MintMetadata>,
75}
76
77impl crate::UniqueIdentifier for Mint {
78 fn id(&self, chain_id: &ChainId) -> Bytes32 {
79 if let Some(id) = self.cached_id() {
80 return id;
81 }
82
83 let mut clone = self.clone();
84 clone.input_contract.prepare_sign();
85 clone.output_contract.prepare_sign();
86
87 crate::transaction::compute_transaction_id(chain_id, &mut clone)
88 }
89
90 fn cached_id(&self) -> Option<Bytes32> {
91 self.metadata.as_ref().map(|m| m.id)
92 }
93}
94
95impl FormatValidityChecks for Mint {
96 fn check_signatures(&self, _: &ChainId) -> Result<(), ValidityError> {
97 Ok(())
98 }
99
100 fn check_without_signatures(
101 &self,
102 block_height: BlockHeight,
103 consensus_params: &ConsensusParameters,
104 ) -> Result<(), ValidityError> {
105 check_size(self, consensus_params.tx_params())?;
106
107 if self.tx_pointer().block_height() != block_height {
108 return Err(ValidityError::TransactionMintIncorrectBlockHeight);
109 }
110
111 if self.output_contract.input_index != 0 {
112 return Err(ValidityError::TransactionMintIncorrectOutputIndex);
113 }
114
115 if &self.mint_asset_id != consensus_params.base_asset_id() {
117 return Err(ValidityError::TransactionMintNonBaseAsset);
118 }
119
120 Ok(())
121 }
122}
123
124impl crate::Cacheable for Mint {
125 fn is_computed(&self) -> bool {
126 self.metadata.is_some()
127 }
128
129 fn precompute(&mut self, chain_id: &ChainId) -> Result<(), ValidityError> {
130 self.metadata = None;
131 self.metadata = Some(MintMetadata::compute(self, chain_id));
132 Ok(())
133 }
134}
135
136#[cfg(any(test, feature = "test-helpers"))]
137impl Mint {
138 pub fn prepare_sign(&mut self) {
142 self.input_contract.prepare_sign();
143 self.output_contract.prepare_sign();
144 }
145}
146
147mod field {
148 use super::*;
149 use crate::field::{
150 InputContract,
151 MintAmount,
152 MintAssetId,
153 MintGasPrice,
154 OutputContract,
155 };
156
157 impl TxPointerField for Mint {
158 #[inline(always)]
159 fn tx_pointer(&self) -> &TxPointer {
160 &self.tx_pointer
161 }
162
163 #[inline(always)]
164 fn tx_pointer_mut(&mut self) -> &mut TxPointer {
165 &mut self.tx_pointer
166 }
167
168 #[inline(always)]
169 fn tx_pointer_static() -> usize {
170 WORD_SIZE }
172 }
173
174 impl InputContract for Mint {
175 #[inline(always)]
176 fn input_contract(&self) -> &input::contract::Contract {
177 &self.input_contract
178 }
179
180 #[inline(always)]
181 fn input_contract_mut(&mut self) -> &mut input::contract::Contract {
182 &mut self.input_contract
183 }
184
185 #[inline(always)]
186 fn input_contract_offset(&self) -> usize {
187 Self::tx_pointer_static().saturating_add(TxPointer::LEN)
188 }
189 }
190
191 impl OutputContract for Mint {
192 #[inline(always)]
193 fn output_contract(&self) -> &output::contract::Contract {
194 &self.output_contract
195 }
196
197 #[inline(always)]
198 fn output_contract_mut(&mut self) -> &mut output::contract::Contract {
199 &mut self.output_contract
200 }
201
202 #[inline(always)]
203 fn output_contract_offset(&self) -> usize {
204 self.input_contract_offset()
205 .saturating_add(self.input_contract.size())
206 }
207 }
208
209 impl MintAmount for Mint {
210 #[inline(always)]
211 fn mint_amount(&self) -> &fuel_types::Word {
212 &self.mint_amount
213 }
214
215 #[inline(always)]
216 fn mint_amount_mut(&mut self) -> &mut fuel_types::Word {
217 &mut self.mint_amount
218 }
219
220 #[inline(always)]
221 fn mint_amount_offset(&self) -> usize {
222 self.output_contract_offset()
223 .saturating_add(self.output_contract.size())
224 }
225 }
226
227 impl MintAssetId for Mint {
228 #[inline(always)]
229 fn mint_asset_id(&self) -> &AssetId {
230 &self.mint_asset_id
231 }
232
233 #[inline(always)]
234 fn mint_asset_id_mut(&mut self) -> &mut AssetId {
235 &mut self.mint_asset_id
236 }
237
238 #[inline(always)]
239 fn mint_asset_id_offset(&self) -> usize {
240 self.mint_amount_offset().saturating_add(WORD_SIZE)
241 }
242 }
243
244 impl MintGasPrice for Mint {
245 #[inline(always)]
246 fn gas_price(&self) -> &Word {
247 &self.gas_price
248 }
249
250 #[inline(always)]
251 fn gas_price_mut(&mut self) -> &mut Word {
252 &mut self.gas_price
253 }
254
255 #[inline(always)]
256 fn gas_price_offset(&self) -> usize {
257 self.mint_asset_id_offset().saturating_add(AssetId::LEN)
258 }
259 }
260}