1use crate::{
2 call_handler_ext::{
3 TransactionConfig,
4 maybe_return_coins,
5 },
6 utxo_manager::SharedUtxoManager,
7 wallet_ext::{
8 BuilderData,
9 WalletExt,
10 },
11};
12use fuel_core_types::{
13 fuel_tx::{
14 Create,
15 Output,
16 TxPointer,
17 UniqueIdentifier,
18 Witness,
19 },
20 fuel_types::canonical::Serialize,
21};
22use fuels::{
23 accounts::ViewOnlyAccount,
24 prelude::{
25 Contract,
26 Error as FuelsError,
27 Result as FuelsResult,
28 Wallet,
29 },
30 programs::contract::{
31 DeployResponse,
32 Regular,
33 },
34};
35use std::future::Future;
36
37pub trait ContractExt {
38 fn almost_sync_deploy(
39 self,
40 account: &Wallet,
41 builder_data: &BuilderData,
42 utxo_manager: &SharedUtxoManager,
43 tx_config: &Option<TransactionConfig>,
44 ) -> impl Future<Output = FuelsResult<DeployResponse>>;
45}
46
47impl ContractExt for Contract<Regular> {
48 async fn almost_sync_deploy(
52 self,
53 account: &Wallet,
54 builder_data: &BuilderData,
55 utxo_manager: &SharedUtxoManager,
56 tx_config: &Option<TransactionConfig>,
57 ) -> FuelsResult<DeployResponse> {
58 let consensus_parameters = &builder_data.consensus_parameters;
59 let max_fee = builder_data.max_fee();
60 let base_asset_id = *consensus_parameters.base_asset_id();
61 let chain_id = consensus_parameters.chain_id();
62 let secret_key = account.signer().secret_key();
63 let owner = account.address();
64
65 let contract_id = self.contract_id();
66 let state_root = self.state_root();
67 let salt = self.salt();
68 let storage_slots = self.storage_slots();
69 let code = self.code();
70 let bytecode = Witness::from(code);
71
72 let witness_limit = bytecode.size() + crate::wallet_ext::SIGNATURE_MARGIN;
73
74 let mut builder = fuel_core_types::fuel_tx::TransactionBuilder::<Create>::create(
75 bytecode,
76 salt,
77 storage_slots.to_vec(),
78 );
79
80 builder
81 .with_chain_id(consensus_parameters.chain_id())
82 .max_fee_limit(max_fee)
83 .witness_limit(witness_limit as u64);
84
85 let input_coins = {
86 utxo_manager
87 .lock()
88 .await
89 .guaranteed_extract_coins(owner, base_asset_id, max_fee as u128)
90 .map_err(|e| FuelsError::Other(e.to_string()))
91 }?;
92
93 for coin in input_coins.iter() {
94 builder.add_unsigned_coin_input(
95 secret_key,
96 coin.utxo_id,
97 coin.amount,
98 coin.asset_id,
99 TxPointer::default(),
100 );
101 }
102
103 builder.add_output(Output::Change {
104 to: owner,
105 amount: 0,
106 asset_id: base_asset_id,
107 });
108
109 builder.add_output(Output::ContractCreated {
110 contract_id,
111 state_root,
112 });
113
114 let tx = builder.finalize_as_transaction();
115 let tx_id = tx.id(&chain_id);
116
117 maybe_return_coins(
118 account,
119 &tx,
120 tx_id,
121 tx_config.and_then(|c| c.expiration_height),
122 utxo_manager,
123 );
124
125 let result = account
126 .send_transaction(chain_id, &tx)
127 .await
128 .map_err(|e| FuelsError::Other(e.to_string()))?;
129 let tx_id = Some(result.tx_id);
130
131 {
132 let mut utxo_manager = utxo_manager.lock().await;
133 utxo_manager.load_from_coins(result.known_coins.into_iter());
134 utxo_manager.load_from_coins(result.dynamic_coins.into_iter());
135 }
136
137 Ok(DeployResponse {
138 tx_status: Some(result.tx_status.take_success_checked(None)?),
139 tx_id,
140 contract_id,
141 })
142 }
143}