use near_jsonrpc_client::methods::sandbox_patch_state::RpcSandboxPatchStateRequest;
use near_primitives::types::{BlockId, BlockReference};
use near_primitives::{account::AccessKey, state_record::StateRecord, types::Balance};
use crate::error::SandboxErrorCode;
use crate::network::DEV_ACCOUNT_SEED;
use crate::types::{BlockHeight, KeyType, SecretKey};
use crate::{AccountId, Contract, CryptoHash, InMemorySigner, Network, Worker};
pub struct ImportContractTransaction<'a> {
account_id: &'a AccountId,
from_network: Worker<dyn Network>,
into_network: Worker<dyn Network>,
import_data: bool,
initial_balance: Option<Balance>,
block_ref: Option<BlockReference>,
}
impl<'a, 'b> ImportContractTransaction<'a> {
pub(crate) fn new(
account_id: &'a AccountId,
from_network: Worker<dyn Network>,
into_network: Worker<dyn Network>,
) -> Self {
ImportContractTransaction {
account_id,
from_network,
into_network,
import_data: false,
initial_balance: None,
block_ref: None,
}
}
pub fn block_height(mut self, block_height: BlockHeight) -> Self {
self.block_ref = Some(BlockId::Height(block_height).into());
self
}
pub fn block_hash(mut self, block_hash: CryptoHash) -> Self {
self.block_ref =
Some(BlockId::Hash(near_primitives::hash::CryptoHash(block_hash.0)).into());
self
}
pub fn with_data(mut self) -> Self {
self.import_data = true;
self
}
pub fn initial_balance(mut self, initial_balance: Balance) -> Self {
self.initial_balance = Some(initial_balance);
self
}
pub async fn transact(self) -> crate::result::Result<Contract> {
let account_id = self.account_id.clone();
let sk = SecretKey::from_seed(KeyType::ED25519, DEV_ACCOUNT_SEED);
let pk = sk.public_key();
let signer = InMemorySigner::from_secret_key(account_id.clone(), sk);
let block_ref = self.block_ref.unwrap_or_else(BlockReference::latest);
let mut account_view = self
.from_network
.view_account(&account_id)
.block_reference(block_ref.clone())
.await?
.into_near_account();
if let Some(initial_balance) = self.initial_balance {
account_view.set_amount(initial_balance);
}
let mut records = vec![
StateRecord::Account {
account_id: account_id.clone(),
account: account_view.clone(),
},
StateRecord::AccessKey {
account_id: account_id.clone(),
public_key: pk.clone().into(),
access_key: AccessKey::full_access(),
},
];
if account_view.code_hash() != near_primitives::hash::CryptoHash::default() {
let code = self
.from_network
.view_code(&account_id)
.block_reference(block_ref.clone())
.await?;
records.push(StateRecord::Contract {
account_id: account_id.clone(),
code,
});
}
if self.import_data {
records.extend(
self.from_network
.view_state(&account_id)
.block_reference(block_ref)
.await?
.into_iter()
.map(|(key, value)| StateRecord::Data {
account_id: account_id.clone(),
data_key: key,
value,
}),
);
}
self.into_network
.client()
.query(&RpcSandboxPatchStateRequest {
records: records.clone(),
})
.await
.map_err(|err| SandboxErrorCode::PatchStateFailure.custom(err))?;
self.into_network
.client()
.query(&RpcSandboxPatchStateRequest { records })
.await
.map_err(|err| SandboxErrorCode::PatchStateFailure.custom(err))?;
Ok(Contract::new(signer, self.into_network))
}
}