| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2025 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- use std::collections::HashMap;
- use lazy_static::lazy_static;
- use rand::rngs::OsRng;
- use darkfi::{
- tx::{ContractCallLeaf, Transaction, TransactionBuilder},
- zk::{proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses},
- zkas::ZkBinary,
- Error, Result,
- };
- use darkfi_deployooor_contract::{
- client::{deploy_v1::DeployCallBuilder, lock_v1::LockCallBuilder},
- model::LockParamsV1,
- DeployFunction,
- };
- use darkfi_money_contract::MONEY_CONTRACT_ZKAS_FEE_NS_V1;
- use darkfi_sdk::{
- crypto::{
- ContractId, Keypair, PublicKey, SecretKey, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID,
- },
- deploy::DeployParamsV1,
- tx::TransactionHash,
- ContractCall,
- };
- use darkfi_serial::{deserialize_async, serialize, serialize_async, AsyncEncodable};
- use rusqlite::types::Value;
- use crate::{convert_named_params, error::WalletDbResult, rpc::ScanCache, Drk};
- // Wallet SQL table constant names. These have to represent the `wallet.sql`
- // SQL schema. Table names are prefixed with the contract ID to avoid collisions.
- lazy_static! {
- pub static ref DEPLOY_AUTH_TABLE: String =
- format!("{}_deploy_auth", DEPLOYOOOR_CONTRACT_ID.to_string());
- pub static ref DEPLOY_HISTORY_TABLE: String =
- format!("{}_deploy_history", DEPLOYOOOR_CONTRACT_ID.to_string());
- }
- // DEPLOY_AUTH_TABLE
- pub const DEPLOY_AUTH_COL_CONTRACT_ID: &str = "contract_id";
- pub const DEPLOY_AUTH_COL_SECRET_KEY: &str = "secret_key";
- pub const DEPLOY_AUTH_COL_IS_LOCKED: &str = "is_locked";
- pub const DEPLOY_AUTH_COL_LOCK_HEIGHT: &str = "lock_height";
- // DEPLOY_HISTORY_TABLE
- pub const DEPLOY_HISTORY_COL_TX_HASH: &str = "tx_hash";
- pub const DEPLOY_HISTORY_COL_CONTRACT: &str = "contract";
- pub const DEPLOY_HISTORY_COL_TYPE: &str = "type";
- pub const DEPLOY_HISTORY_COL_BLOCK_HEIGHT: &str = "block_height";
- pub const DEPLOY_HISTORY_COL_WASM_BINCODE: &str = "wasm_bincode";
- pub const DEPLOY_HISTORY_COL_DEPLOY_IX: &str = "deploy_ix";
- impl Drk {
- /// Initialize wallet with tables for the Deployooor contract.
- pub fn initialize_deployooor(&self) -> WalletDbResult<()> {
- // Initialize Deployooor wallet schema
- let wallet_schema = include_str!("../deploy.sql");
- self.wallet.exec_batch_sql(wallet_schema)?;
- Ok(())
- }
- /// Generate a new deploy authority keypair and place it into the wallet
- pub async fn deploy_auth_keygen(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
- output.push(String::from("Generating a new keypair"));
- let secret_key = SecretKey::random(&mut OsRng);
- let contract_id = ContractId::derive_public(PublicKey::from_secret(secret_key));
- let lock_height: Option<u32> = None;
- let query = format!(
- "INSERT INTO {} ({}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4);",
- *DEPLOY_AUTH_TABLE,
- DEPLOY_AUTH_COL_CONTRACT_ID,
- DEPLOY_AUTH_COL_SECRET_KEY,
- DEPLOY_AUTH_COL_IS_LOCKED,
- DEPLOY_AUTH_COL_LOCK_HEIGHT,
- );
- self.wallet.exec_sql(
- &query,
- rusqlite::params![
- serialize_async(&contract_id).await,
- serialize_async(&secret_key).await,
- 0,
- lock_height
- ],
- )?;
- output.push(String::from("Created new contract deploy authority"));
- output.push(format!("Contract ID: {contract_id}"));
- Ok(())
- }
- /// Insert a deploy authority history record into the wallet.
- pub fn put_deploy_history_record(
- &self,
- tx_hash: &TransactionHash,
- contract: &ContractId,
- tx_type: &str,
- block_height: &u32,
- wasm_bincode: &Option<Vec<u8>>,
- deploy_ix: &Option<Vec<u8>>,
- ) -> WalletDbResult<()> {
- let query = format!(
- "INSERT INTO {} ({}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6);",
- *DEPLOY_HISTORY_TABLE,
- DEPLOY_HISTORY_COL_TX_HASH,
- DEPLOY_HISTORY_COL_CONTRACT,
- DEPLOY_HISTORY_COL_TYPE,
- DEPLOY_HISTORY_COL_BLOCK_HEIGHT,
- DEPLOY_HISTORY_COL_WASM_BINCODE,
- DEPLOY_HISTORY_COL_DEPLOY_IX,
- );
- self.wallet.exec_sql(
- &query,
- rusqlite::params![
- tx_hash.to_string(),
- serialize(contract),
- tx_type,
- block_height,
- serialize(wasm_bincode),
- serialize(deploy_ix),
- ],
- )?;
- Ok(())
- }
- /// Reset all contract deploy authorities locked status in the wallet.
- pub fn reset_deploy_authorities(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
- output.push(String::from("Resetting deploy authorities locked status"));
- let query = format!(
- "UPDATE {} SET {} = 0, {} = NULL;",
- *DEPLOY_AUTH_TABLE, DEPLOY_AUTH_COL_IS_LOCKED, DEPLOY_AUTH_COL_LOCK_HEIGHT
- );
- self.wallet.exec_sql(&query, &[])?;
- output.push(String::from("Successfully reset deploy authorities locked status"));
- Ok(())
- }
- /// Remove deploy authorities locked status in the wallet that
- /// where locked after provided height.
- pub fn unlock_deploy_authorities_after(
- &self,
- height: &u32,
- output: &mut Vec<String>,
- ) -> WalletDbResult<()> {
- output.push(format!("Resetting deploy authorities locked status after: {height}"));
- let query = format!(
- "UPDATE {} SET {} = 0, {} = NULL WHERE {} > ?1;",
- *DEPLOY_AUTH_TABLE,
- DEPLOY_AUTH_COL_IS_LOCKED,
- DEPLOY_AUTH_COL_LOCK_HEIGHT,
- DEPLOY_AUTH_COL_LOCK_HEIGHT
- );
- self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
- output.push(String::from("Successfully reset deploy authorities locked status"));
- Ok(())
- }
- /// Reset all contracts history records in the wallet.
- pub fn reset_deploy_history(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
- output.push(String::from("Resetting deployment history"));
- let query = format!("DELETE FROM {};", *DEPLOY_HISTORY_TABLE);
- self.wallet.exec_sql(&query, &[])?;
- output.push(String::from("Successfully deployment history"));
- Ok(())
- }
- /// Remove the contracts history records in the wallet that were
- /// created after provided height.
- pub fn remove_deploy_history_after(
- &self,
- height: &u32,
- output: &mut Vec<String>,
- ) -> WalletDbResult<()> {
- output.push(format!("Removing deployment history records after: {height}"));
- let query = format!(
- "DELETE FROM {} WHERE {} > ?1;",
- *DEPLOY_HISTORY_TABLE, DEPLOY_HISTORY_COL_BLOCK_HEIGHT
- );
- self.wallet.exec_sql(&query, rusqlite::params![height])?;
- output.push(String::from("Successfully removed deployment history records"));
- Ok(())
- }
- /// List contract deploy authorities from the wallet
- pub async fn list_deploy_auth(
- &self,
- ) -> Result<Vec<(ContractId, SecretKey, bool, Option<u32>)>> {
- let rows = match self.wallet.query_multiple(&DEPLOY_AUTH_TABLE, &[], &[]) {
- Ok(r) => r,
- Err(e) => {
- return Err(Error::DatabaseError(format!(
- "[list_deploy_auth] Deploy auth retrieval failed: {e}",
- )))
- }
- };
- let mut ret = Vec::with_capacity(rows.len());
- for row in rows {
- let Value::Blob(ref contract_id_bytes) = row[0] else {
- return Err(Error::ParseFailed(
- "[list_deploy_auth] Failed to parse contract id bytes",
- ))
- };
- let contract_id: ContractId = deserialize_async(contract_id_bytes).await?;
- let Value::Blob(ref secret_key_bytes) = row[1] else {
- return Err(Error::ParseFailed(
- "[list_deploy_auth] Failed to parse secret key bytes",
- ))
- };
- let secret_key: SecretKey = deserialize_async(secret_key_bytes).await?;
- let Value::Integer(locked) = row[2] else {
- return Err(Error::ParseFailed("[list_deploy_auth] Failed to parse \"is_locked\""))
- };
- let lock_height = match row[3] {
- Value::Integer(lock_height) => {
- let Ok(lock_height) = u32::try_from(lock_height) else {
- return Err(Error::ParseFailed(
- "[list_deploy_auth] Lock height parsing failed",
- ))
- };
- Some(lock_height)
- }
- Value::Null => None,
- _ => {
- return Err(Error::ParseFailed("[list_deploy_auth] Lock height parsing failed"))
- }
- };
- ret.push((contract_id, secret_key, locked != 0, lock_height))
- }
- Ok(ret)
- }
- /// Retrieve a deploy authority keypair and status for provided
- /// contract id.
- async fn get_deploy_auth(&self, contract_id: &ContractId) -> Result<(Keypair, bool)> {
- // Find the deploy authority keypair
- let row = match self.wallet.query_single(
- &DEPLOY_AUTH_TABLE,
- &[DEPLOY_AUTH_COL_SECRET_KEY, DEPLOY_AUTH_COL_IS_LOCKED],
- convert_named_params! {(DEPLOY_AUTH_COL_CONTRACT_ID, serialize_async(contract_id).await)},
- ) {
- Ok(v) => v,
- Err(e) => {
- return Err(Error::DatabaseError(format!(
- "[get_deploy_auth] Failed to retrieve deploy authority keypair: {e}"
- )))
- }
- };
- let Value::Blob(ref secret_key_bytes) = row[0] else {
- return Err(Error::ParseFailed("[get_deploy_auth] Failed to parse secret key bytes"))
- };
- let secret_key: SecretKey = deserialize_async(secret_key_bytes).await?;
- let keypair = Keypair::new(secret_key);
- let Value::Integer(locked) = row[1] else {
- return Err(Error::ParseFailed("[get_deploy_auth] Failed to parse \"is_locked\""))
- };
- Ok((keypair, locked != 0))
- }
- /// Retrieve contract deploy authorities keys map from the wallet.
- pub async fn get_deploy_auths_keys_map(&self) -> Result<HashMap<[u8; 32], SecretKey>> {
- let rows = match self.wallet.query_multiple(
- &DEPLOY_AUTH_TABLE,
- &[DEPLOY_AUTH_COL_SECRET_KEY],
- &[],
- ) {
- Ok(r) => r,
- Err(e) => {
- return Err(Error::DatabaseError(format!(
- "[get_deploy_auths_keys_map] Failed to retrieve deploy authorities secret keys: {e}",
- )))
- }
- };
- let mut ret = HashMap::new();
- for row in rows {
- let Value::Blob(ref secret_key_bytes) = row[0] else {
- return Err(Error::ParseFailed(
- "[get_deploy_auths_keys_map] Failed to parse secret key bytes",
- ))
- };
- let secret_key: SecretKey = deserialize_async(secret_key_bytes).await?;
- ret.insert(PublicKey::from_secret(secret_key).to_bytes(), secret_key);
- }
- Ok(ret)
- }
- /// Retrieve all deploy history records basic information, for
- /// provided contract id.
- pub async fn get_deploy_auth_history(
- &self,
- contract_id: &ContractId,
- ) -> Result<Vec<(String, String, u32)>> {
- let rows = match self.wallet.query_multiple(
- &DEPLOY_HISTORY_TABLE,
- &[DEPLOY_HISTORY_COL_TX_HASH, DEPLOY_HISTORY_COL_TYPE, DEPLOY_HISTORY_COL_BLOCK_HEIGHT],
- convert_named_params! {(DEPLOY_HISTORY_COL_CONTRACT, serialize_async(contract_id).await)},
- ) {
- Ok(r) => r,
- Err(e) => {
- return Err(Error::DatabaseError(format!(
- "[get_deploy_auth_history] Failed to retrieve deploy authority history records: {e}",
- )))
- }
- };
- let mut ret = Vec::with_capacity(rows.len());
- for row in rows {
- let Value::Text(ref tx_hash) = row[0] else {
- return Err(Error::ParseFailed(
- "[get_deploy_auth_history] Transaction hash parsing failed",
- ))
- };
- let Value::Text(ref tx_type) = row[1] else {
- return Err(Error::ParseFailed("[get_deploy_auth_history] Type parsing failed"))
- };
- let Value::Integer(block_height) = row[2] else {
- return Err(Error::ParseFailed(
- "[get_deploy_auth_history] Block height parsing failed",
- ))
- };
- let Ok(block_height) = u32::try_from(block_height) else {
- return Err(Error::ParseFailed(
- "[get_deploy_auth_history] Block height parsing failed",
- ))
- };
- ret.push((tx_hash.clone(), tx_type.clone(), block_height));
- }
- Ok(ret)
- }
- /// Retrieve deploy history record WASM bincode and deployed
- /// instruction, for provided transaction hash.
- pub async fn get_deploy_history_record_data(
- &self,
- tx_hash: &str,
- ) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
- let row = match self.wallet.query_single(
- &DEPLOY_HISTORY_TABLE,
- &[DEPLOY_HISTORY_COL_WASM_BINCODE, DEPLOY_HISTORY_COL_DEPLOY_IX],
- convert_named_params! {(DEPLOY_HISTORY_COL_TX_HASH, tx_hash)},
- ) {
- Ok(v) => v,
- Err(e) => {
- return Err(Error::DatabaseError(format!(
- "[get_deploy_history_record] Failed to retrieve deploy history record: {e}"
- )))
- }
- };
- let Value::Blob(ref wasm_bincode_bytes) = row[0] else {
- return Err(Error::ParseFailed(
- "[get_deploy_history_record] Failed to parse wasm bincode bytes",
- ))
- };
- let wasm_bincode: Option<Vec<u8>> = deserialize_async(wasm_bincode_bytes).await?;
- let Value::Blob(ref deploy_ix_bytes) = row[1] else {
- return Err(Error::ParseFailed(
- "[get_deploy_history_record] Failed to parse deploy ix bytes",
- ))
- };
- let deploy_ix: Option<Vec<u8>> = deserialize_async(deploy_ix_bytes).await?;
- Ok((wasm_bincode, deploy_ix))
- }
- /// Auxiliary function to apply `DeployFunction::DeployV1` call
- /// data to the wallet.
- /// Returns a flag indicating if the provided call refers to our
- /// own wallet.
- fn apply_deploy_deploy_data(
- &self,
- scan_cache: &ScanCache,
- params: &DeployParamsV1,
- tx_hash: &TransactionHash,
- block_height: &u32,
- ) -> Result<bool> {
- // Check if we have the deploy authority key
- let Some(_) = scan_cache.own_deploy_auths.get(¶ms.public_key.to_bytes()) else {
- return Ok(false)
- };
- // Create a new history record containing the deployment data
- if let Err(e) = self.put_deploy_history_record(
- tx_hash,
- &ContractId::derive_public(params.public_key),
- "DEPLOYMENT",
- block_height,
- &Some(params.wasm_bincode.clone()),
- &Some(params.ix.clone()),
- ) {
- return Err(Error::DatabaseError(format!(
- "[apply_deploy_deploy_data] Inserting deploy history recod failed: {e}"
- )))
- }
- Ok(true)
- }
- /// Auxiliary function to apply `DeployFunction::LockV1` call
- /// data to the wallet.
- /// Returns a flag indicating if the provided call refers to our
- /// own wallet.
- async fn apply_deploy_lock_data(
- &self,
- scan_cache: &ScanCache,
- public_key: &PublicKey,
- tx_hash: &TransactionHash,
- lock_height: &u32,
- ) -> Result<bool> {
- // Check if we have the deploy authority key
- let Some(secret_key) = scan_cache.own_deploy_auths.get(&public_key.to_bytes()) else {
- return Ok(false)
- };
- // Lock contract
- let secret_key = serialize_async(secret_key).await;
- let query = format!(
- "UPDATE {} SET {} = 1, {} = ?1 WHERE {} = ?2;",
- *DEPLOY_AUTH_TABLE,
- DEPLOY_AUTH_COL_IS_LOCKED,
- DEPLOY_AUTH_COL_LOCK_HEIGHT,
- DEPLOY_AUTH_COL_SECRET_KEY
- );
- if let Err(e) =
- self.wallet.exec_sql(&query, rusqlite::params![Some(*lock_height), secret_key])
- {
- return Err(Error::DatabaseError(format!(
- "[apply_deploy_lock_data] Lock deploy authority failed: {e}"
- )))
- }
- // Create a new history record for the lock transaction
- if let Err(e) = self.put_deploy_history_record(
- tx_hash,
- &ContractId::derive_public(*public_key),
- "LOCK",
- lock_height,
- &None,
- &None,
- ) {
- return Err(Error::DatabaseError(format!(
- "[apply_deploy_lock_data] Inserting deploy history recod failed: {e}"
- )))
- }
- Ok(true)
- }
- /// Append data related to DeployoOor contract transactions into
- /// the wallet database and update the provided scan cache.
- /// Returns a flag indicating if provided data refer to our own
- /// wallet.
- pub async fn apply_tx_deploy_data(
- &self,
- scan_cache: &mut ScanCache,
- data: &[u8],
- tx_hash: &TransactionHash,
- block_height: &u32,
- ) -> Result<bool> {
- // Run through the transaction call data and see what we got:
- match DeployFunction::try_from(data[0])? {
- DeployFunction::DeployV1 => {
- scan_cache.log(String::from("[apply_tx_deploy_data] Found Deploy::DeployV1 call"));
- let params: DeployParamsV1 = deserialize_async(&data[1..]).await?;
- self.apply_deploy_deploy_data(scan_cache, ¶ms, tx_hash, block_height)
- }
- DeployFunction::LockV1 => {
- scan_cache.log(String::from("[apply_tx_deploy_data] Found Deploy::LockV1 call"));
- let params: LockParamsV1 = deserialize_async(&data[1..]).await?;
- self.apply_deploy_lock_data(scan_cache, ¶ms.public_key, tx_hash, block_height)
- .await
- }
- }
- }
- /// Create a feeless contract deployment transaction.
- pub async fn deploy_contract(
- &self,
- deploy_auth: &ContractId,
- wasm_bincode: Vec<u8>,
- deploy_ix: Vec<u8>,
- ) -> Result<Transaction> {
- // Fetch the keypair and its status
- let (deploy_keypair, is_locked) = self.get_deploy_auth(deploy_auth).await?;
- // Check lock status
- if is_locked {
- return Err(Error::Custom("[deploy_contract] Contract is locked".to_string()))
- }
- // Now we need to do a lookup for the zkas proof bincodes, and create
- // the circuit objects and proving keys so we can build the transaction.
- // We also do this through the RPC.
- let zkas_bins = self.lookup_zkas(&MONEY_CONTRACT_ID).await?;
- let Some(fee_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_FEE_NS_V1)
- else {
- return Err(Error::Custom("[deploy_contract] Fee circuit not found".to_string()))
- };
- let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
- let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
- // Creating Fee circuit proving keys
- let fee_pk = ProvingKey::build(fee_zkbin.k, &fee_circuit);
- // Create the contract call
- let deploy_call = DeployCallBuilder { deploy_keypair, wasm_bincode, deploy_ix };
- let deploy_debris = deploy_call.build()?;
- // Encode the call
- let mut data = vec![DeployFunction::DeployV1 as u8];
- deploy_debris.params.encode_async(&mut data).await?;
- let call = ContractCall { contract_id: *DEPLOYOOOR_CONTRACT_ID, data };
- // Create the TransactionBuilder containing above call
- let mut tx_builder =
- TransactionBuilder::new(ContractCallLeaf { call, proofs: vec![] }, vec![])?;
- // We first have to execute the fee-less tx to gather its used gas, and then we feed
- // it into the fee-creating function.
- let mut tx = tx_builder.build()?;
- let sigs = tx.create_sigs(&[deploy_keypair.secret])?;
- tx.signatures.push(sigs);
- let tree = self.get_money_tree().await?;
- let (fee_call, fee_proofs, fee_secrets) =
- self.append_fee_call(&tx, &tree, &fee_pk, &fee_zkbin, None).await?;
- // Append the fee call to the transaction
- tx_builder.append(ContractCallLeaf { call: fee_call, proofs: fee_proofs }, vec![])?;
- // Now build the actual transaction and sign it with all necessary keys.
- let mut tx = tx_builder.build()?;
- let sigs = tx.create_sigs(&[deploy_keypair.secret])?;
- tx.signatures.push(sigs);
- let sigs = tx.create_sigs(&fee_secrets)?;
- tx.signatures.push(sigs);
- Ok(tx)
- }
- /// Create a feeless contract redeployment lock transaction.
- pub async fn lock_contract(&self, deploy_auth: &ContractId) -> Result<Transaction> {
- // Fetch the keypair and its status
- let (deploy_keypair, is_locked) = self.get_deploy_auth(deploy_auth).await?;
- // Check lock status
- if is_locked {
- return Err(Error::Custom("[lock_contract] Contract is already locked".to_string()))
- }
- // Now we need to do a lookup for the zkas proof bincodes, and create
- // the circuit objects and proving keys so we can build the transaction.
- // We also do this through the RPC.
- let zkas_bins = self.lookup_zkas(&MONEY_CONTRACT_ID).await?;
- let Some(fee_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_FEE_NS_V1)
- else {
- return Err(Error::Custom("[lock_contract] Fee circuit not found".to_string()))
- };
- let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
- let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
- // Creating Fee circuit proving keys
- let fee_pk = ProvingKey::build(fee_zkbin.k, &fee_circuit);
- // Create the contract call
- let lock_call = LockCallBuilder { deploy_keypair };
- let lock_debris = lock_call.build()?;
- // Encode the call
- let mut data = vec![DeployFunction::LockV1 as u8];
- lock_debris.params.encode_async(&mut data).await?;
- let call = ContractCall { contract_id: *DEPLOYOOOR_CONTRACT_ID, data };
- // Create the TransactionBuilder containing above call
- let mut tx_builder =
- TransactionBuilder::new(ContractCallLeaf { call, proofs: vec![] }, vec![])?;
- // We first have to execute the fee-less tx to gather its used gas, and then we feed
- // it into the fee-creating function.
- let mut tx = tx_builder.build()?;
- let sigs = tx.create_sigs(&[deploy_keypair.secret])?;
- tx.signatures.push(sigs);
- let tree = self.get_money_tree().await?;
- let (fee_call, fee_proofs, fee_secrets) =
- self.append_fee_call(&tx, &tree, &fee_pk, &fee_zkbin, None).await?;
- // Append the fee call to the transaction
- tx_builder.append(ContractCallLeaf { call: fee_call, proofs: fee_proofs }, vec![])?;
- // Now build the actual transaction and sign it with all necessary keys.
- let mut tx = tx_builder.build()?;
- let sigs = tx.create_sigs(&[deploy_keypair.secret])?;
- tx.signatures.push(sigs);
- let sigs = tx.create_sigs(&fee_secrets)?;
- tx.signatures.push(sigs);
- Ok(tx)
- }
- }
|