1use lazy_static::lazy_static;
20use rand::rngs::OsRng;
21
22use darkfi::{
23 tx::{ContractCallLeaf, Transaction, TransactionBuilder},
24 Error, Result,
25};
26use darkfi_deployooor_contract::{
27 client::{deploy_v1::DeployCallBuilder, lock_v1::LockCallBuilder},
28 DeployFunction,
29};
30use darkfi_sdk::{
31 crypto::{ContractId, Keypair, DEPLOYOOOR_CONTRACT_ID},
32 ContractCall,
33};
34use darkfi_serial::{deserialize_async, serialize_async, AsyncEncodable};
35use rusqlite::types::Value;
36
37use crate::{convert_named_params, error::WalletDbResult, Drk};
38
39lazy_static! {
42 pub static ref DEPLOY_AUTH_TABLE: String =
43 format!("{}_deploy_auth", DEPLOYOOOR_CONTRACT_ID.to_string());
44}
45
46pub const DEPLOY_AUTH_COL_ID: &str = "id";
48pub const DEPLOY_AUTH_COL_DEPLOY_AUTHORITY: &str = "deploy_authority";
49pub const DEPLOY_AUTH_COL_IS_FROZEN: &str = "is_frozen";
50
51impl Drk {
52 pub fn initialize_deployooor(&self) -> WalletDbResult<()> {
54 let wallet_schema = include_str!("../deploy.sql");
56 self.wallet.exec_batch_sql(wallet_schema)?;
57
58 Ok(())
59 }
60
61 pub async fn deploy_auth_keygen(&self) -> WalletDbResult<()> {
63 eprintln!("Generating a new keypair");
64
65 let keypair = Keypair::random(&mut OsRng);
66
67 let query = format!(
68 "INSERT INTO {} ({}, {}) VALUES (?1, ?2);",
69 *DEPLOY_AUTH_TABLE, DEPLOY_AUTH_COL_DEPLOY_AUTHORITY, DEPLOY_AUTH_COL_IS_FROZEN,
70 );
71 self.wallet.exec_sql(&query, rusqlite::params![serialize_async(&keypair).await, 0])?;
72
73 eprintln!("Created new contract deploy authority");
74 println!("Contract ID: {}", ContractId::derive_public(keypair.public));
75
76 Ok(())
77 }
78
79 pub async fn list_deploy_auth(&self) -> Result<Vec<(i64, ContractId, bool)>> {
81 let rows = match self.wallet.query_multiple(&DEPLOY_AUTH_TABLE, &[], &[]) {
82 Ok(r) => r,
83 Err(e) => {
84 return Err(Error::DatabaseError(format!(
85 "[list_deploy_auth] Deploy auth retrieval failed: {e:?}",
86 )))
87 }
88 };
89
90 let mut ret = Vec::with_capacity(rows.len());
91 for row in rows {
92 let Value::Integer(idx) = row[0] else {
93 return Err(Error::ParseFailed("[list_deploy_auth] Failed to parse index"))
94 };
95
96 let Value::Blob(ref auth_bytes) = row[1] else {
97 return Err(Error::ParseFailed("[list_deploy_auth] Failed to parse keypair bytes"))
98 };
99 let deploy_auth: Keypair = deserialize_async(auth_bytes).await?;
100
101 let Value::Integer(frozen) = row[2] else {
102 return Err(Error::ParseFailed("[list_deploy_auth] Failed to parse \"is_frozen\""))
103 };
104
105 ret.push((idx, ContractId::derive_public(deploy_auth.public), frozen != 0))
106 }
107
108 Ok(ret)
109 }
110
111 async fn get_deploy_auth(&self, idx: u64) -> Result<Keypair> {
113 let row = match self.wallet.query_single(
115 &DEPLOY_AUTH_TABLE,
116 &[DEPLOY_AUTH_COL_DEPLOY_AUTHORITY],
117 convert_named_params! {(DEPLOY_AUTH_COL_ID, idx)},
118 ) {
119 Ok(v) => v,
120 Err(e) => {
121 return Err(Error::DatabaseError(format!(
122 "[deploy_contract] Failed to retrieve deploy authority keypair: {e:?}"
123 )))
124 }
125 };
126
127 let Value::Blob(ref keypair_bytes) = row[0] else {
128 return Err(Error::ParseFailed("[deploy_contract] Failed to parse keypair bytes"))
129 };
130 let keypair: Keypair = deserialize_async(keypair_bytes).await?;
131
132 Ok(keypair)
133 }
134
135 pub async fn deploy_contract(
137 &self,
138 deploy_auth: u64,
139 wasm_bincode: Vec<u8>,
140 deploy_ix: Vec<u8>,
141 ) -> Result<Transaction> {
142 let deploy_keypair = self.get_deploy_auth(deploy_auth).await?;
144
145 let deploy_call = DeployCallBuilder { deploy_keypair, wasm_bincode, deploy_ix };
147 let deploy_debris = deploy_call.build()?;
148
149 let mut data = vec![DeployFunction::DeployV1 as u8];
151 deploy_debris.params.encode_async(&mut data).await?;
152 let call = ContractCall { contract_id: *DEPLOYOOOR_CONTRACT_ID, data };
153 let mut tx_builder =
154 TransactionBuilder::new(ContractCallLeaf { call, proofs: vec![] }, vec![])?;
155
156 let mut tx = tx_builder.build()?;
157 let sigs = tx.create_sigs(&[deploy_keypair.secret])?;
158 tx.signatures = vec![sigs];
159
160 Ok(tx)
161 }
162
163 pub async fn lock_contract(&self, deploy_auth: u64) -> Result<Transaction> {
165 let deploy_keypair = self.get_deploy_auth(deploy_auth).await?;
167
168 let lock_call = LockCallBuilder { deploy_keypair };
170 let lock_debris = lock_call.build()?;
171
172 let mut data = vec![DeployFunction::LockV1 as u8];
174 lock_debris.params.encode_async(&mut data).await?;
175 let call = ContractCall { contract_id: *DEPLOYOOOR_CONTRACT_ID, data };
176 let mut tx_builder =
177 TransactionBuilder::new(ContractCallLeaf { call, proofs: vec![] }, vec![])?;
178
179 let mut tx = tx_builder.build()?;
180 let sigs = tx.create_sigs(&[deploy_keypair.secret])?;
181 tx.signatures = vec![sigs];
182
183 Ok(tx)
184 }
185}