use crate::{
call_handler_ext::{
TransactionConfig,
maybe_return_coins,
},
utxo_manager::SharedUtxoManager,
wallet_ext::{
BuilderData,
WalletExt,
},
};
use fuel_core_types::{
fuel_tx::{
Create,
Output,
TxPointer,
UniqueIdentifier,
Witness,
},
fuel_types::canonical::Serialize,
};
use fuels::{
accounts::ViewOnlyAccount,
prelude::{
Contract,
Error as FuelsError,
Result as FuelsResult,
Wallet,
},
programs::contract::{
DeployResponse,
Regular,
},
};
use std::future::Future;
pub trait ContractExt {
fn almost_sync_deploy(
self,
account: &Wallet,
builder_data: &BuilderData,
utxo_manager: &SharedUtxoManager,
tx_config: &Option<TransactionConfig>,
) -> impl Future<Output = FuelsResult<DeployResponse>>;
}
impl ContractExt for Contract<Regular> {
async fn almost_sync_deploy(
self,
account: &Wallet,
builder_data: &BuilderData,
utxo_manager: &SharedUtxoManager,
tx_config: &Option<TransactionConfig>,
) -> FuelsResult<DeployResponse> {
let consensus_parameters = &builder_data.consensus_parameters;
let max_fee = builder_data.max_fee();
let base_asset_id = *consensus_parameters.base_asset_id();
let chain_id = consensus_parameters.chain_id();
let secret_key = account.signer().secret_key();
let owner = account.address();
let contract_id = self.contract_id();
let state_root = self.state_root();
let salt = self.salt();
let storage_slots = self.storage_slots();
let code = self.code();
let bytecode = Witness::from(code);
let witness_limit = bytecode.size() + crate::wallet_ext::SIGNATURE_MARGIN;
let mut builder = fuel_core_types::fuel_tx::TransactionBuilder::<Create>::create(
bytecode,
salt,
storage_slots.to_vec(),
);
builder
.with_chain_id(consensus_parameters.chain_id())
.max_fee_limit(max_fee)
.witness_limit(witness_limit as u64);
let input_coins = {
utxo_manager
.lock()
.await
.guaranteed_extract_coins(owner, base_asset_id, max_fee as u128)
.map_err(|e| FuelsError::Other(e.to_string()))
}?;
for coin in input_coins.iter() {
builder.add_unsigned_coin_input(
secret_key,
coin.utxo_id,
coin.amount,
coin.asset_id,
TxPointer::default(),
);
}
builder.add_output(Output::Change {
to: owner,
amount: 0,
asset_id: base_asset_id,
});
builder.add_output(Output::ContractCreated {
contract_id,
state_root,
});
let tx = builder.finalize_as_transaction();
let tx_id = tx.id(&chain_id);
maybe_return_coins(
account,
&tx,
tx_id,
tx_config.and_then(|c| c.expiration_height),
utxo_manager,
);
let result = account
.send_transaction(chain_id, &tx)
.await
.map_err(|e| FuelsError::Other(e.to_string()))?;
let tx_id = Some(result.tx_id);
{
let mut utxo_manager = utxo_manager.lock().await;
utxo_manager.load_from_coins(result.known_coins.into_iter());
utxo_manager.load_from_coins(result.dynamic_coins.into_iter());
}
Ok(DeployResponse {
tx_status: Some(result.tx_status.take_success_checked(None)?),
tx_id,
contract_id,
})
}
}