Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion applications/tari_indexer/src/network_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ where
}

pub async fn submit_transaction(&self, transaction: Transaction) -> Result<TransactionId, NetworkClientError> {
if !transaction.is_shard_applicable() {
if !transaction.has_inputs() {
return Err(NetworkClientError::NoInputsProvided);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ impl ProcessDefinition for WalletDaemonCreateAccount {
"create-account",
"--name",
"Validator Fees",
"--key",
"0",
"--set-active",
"--output",
output_path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ where
return Err(e.into());
}

if !transaction.is_shard_applicable() {
if !transaction.has_inputs() {
warn!(target: LOG_TARGET, "⚠ No involved shards for transaction {tx_id}");
return Err(MempoolError::TransactionValidationError(
TransactionValidationError::NoInvolvedShards { transaction_id: tx_id },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub enum TransactionValidationError {
NoInvolvedShards { transaction_id: TransactionId },
#[error("Invalid transaction signature")]
InvalidSignature,
#[error("Transaction {transaction_id} has no main signer")]
NoMainSigner { transaction_id: TransactionId },
#[error("Transaction {transaction_id} is not signed")]
TransactionNotSigned { transaction_id: TransactionId },
#[error("Network error: {0}")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Validator<Transaction> for IsShardApplicable {
type Error = TransactionValidationError;

fn validate(&self, _context: &(), transaction: &Transaction) -> Result<(), Self::Error> {
if !transaction.is_shard_applicable() {
if !transaction.has_inputs() {
warn!(target: LOG_TARGET, "HasInputs - FAIL: No input shards");
return Err(TransactionValidationError::NoInputs {
transaction_id: transaction.calculate_id(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: BSD-3-Clause

use log::warn;
use tari_engine::executables::Executable;
use tari_transaction::Transaction;

use crate::{transaction_validators::TransactionValidationError, validator::Validator};
Expand All @@ -16,6 +17,13 @@ impl Validator<Transaction> for TransactionSignatureValidator {
type Error = TransactionValidationError;

fn validate(&self, _context: &(), transaction: &Transaction) -> Result<(), TransactionValidationError> {
if transaction.main_signer().is_none() {
warn!(target: LOG_TARGET, "TransactionSignatureValidator - FAIL: No main signer");
return Err(TransactionValidationError::NoMainSigner {
transaction_id: transaction.to_id(),
});
}

if !transaction.verify_all_signatures() {
warn!(target: LOG_TARGET, "TransactionSignatureValidator - FAIL: Invalid signature");
return Err(TransactionValidationError::InvalidSignature);
Expand Down
108 changes: 51 additions & 57 deletions applications/tari_walletd/src/handlers/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use tari_engine_types::{
use tari_ootle_common_types::{optional::Optional, SubstateRequirement};
use tari_ootle_wallet_crypto::{
memo::Memo,
UnblindedOutputStatement,
UnblindedStealthInputStatement,
UnblindedStealthOutputStatement,
UnblindedOutputWitness,
UnblindedStealthInputWitness,
UnblindedStealthOutputWitness,
};
use tari_ootle_wallet_sdk::{
apis::{
Expand Down Expand Up @@ -513,8 +513,8 @@ pub async fn handle_claim_burn(
sdk.stealth_crypto_api()
.derive_stealth_owner_public_key(network, &account_owner_public_key, &nonce);

let output_statement = UnblindedStealthOutputStatement {
statement: UnblindedOutputStatement {
let output_statement = UnblindedStealthOutputWitness {
witness: UnblindedOutputWitness {
amount: final_amount,
mask: mask.key,
sender_public_nonce: output_public_nonce.clone(),
Expand All @@ -527,7 +527,7 @@ pub async fn handle_claim_burn(
};

// Generate the correct secret to spend the claimed output
let input = UnblindedStealthInputStatement {
let input = UnblindedStealthInputWitness {
mask_and_value: decrypted.into_mask_and_value(),
owner_secret: claim_nonce_keypair.secret_key().clone(),
public_nonce: reciprocal_claim_public_key_expanded,
Expand Down Expand Up @@ -946,6 +946,12 @@ pub async fn handle_stealth_transfer(
let network = sdk.sdk_config().network;
let notifier = context.notifier().clone();
let owner_account = get_account(&req.owner_account, &sdk.accounts_api())?;
let Some(owner_key_id) = owner_account.owner_key_id() else {
return Err(invalid_params(
"owner_account",
Some("cannot transfer from an account without an owner key"),
));
};

let params = StealthTransferParams {
input_selection: req.input_selection,
Expand All @@ -968,42 +974,56 @@ pub async fn handle_stealth_transfer(
task::spawn(async move {
let transfer = sdk.stealth_transfer_api().transfer(owner_account, params).await?;

let must_sign_with_account_key =
transfer.fee_inputs.revealed.is_positive() || transfer.transfer_inputs.revealed.is_positive();
let signer_key = if must_sign_with_account_key {
sdk.key_manager_api().get_account_owner_key(owner_key_id)?
} else {
// Since we don't require account auth, use a throwaway nonce to sign the transaction
sdk.key_manager_api().next_key(KeyBranch::Nonce)?.into()
};

let transaction = transfer
.transaction
.authorized_sealed_signer()
.build(vec![])
.seal(&signer_key.secret);

// TODO: if submitting fails we need to unlock the inputs again
if req.dry_run {
let transaction_id = transfer.transaction.calculate_id();
let result = transaction_service
.submit_dry_run_transaction(transfer.transaction)
.await;
// Release the lock immediately as dry run does not submit the transaction
// TODO: maybe transfer() should not lock the outputs if it's a dry run
if let Err(err) = sdk.stealth_outputs_api().release_lock(transfer.lock_id) {
error!(
target: LOG_TARGET,
"Failed to release locked outputs for dry run : {}",
err
);
}
let result = transaction_service.submit_dry_run_transaction(transaction).await;
return match result {
Ok(_) => Ok(StealthTransferResponse { transaction_id }),
Ok(res) => Ok(StealthTransferResponse {
transaction_id: res.finalize.transaction_hash.into(),
}),
Err(e) => {
if let Err(err) = sdk
.stealth_outputs_api()
.release_locked_outputs(transfer.transaction_lock_id)
{
if let Err(err) = sdk.stealth_outputs_api().release_lock(transfer.lock_id) {
error!(
target: LOG_TARGET,
"Failed to release locked outputs after dry run failure: {}",
err
);
}
if let Err(err) = sdk
.stealth_outputs_api()
.release_revealed_funds(transfer.transaction_lock_id)
{
error!(
target: LOG_TARGET,
"Failed to release revealed funds after dry run failure: {}",
err
);
}

Err(anyhow::anyhow!("Dry run transaction failed: {}", e))
},
};
}

let result = transaction_service.submit_transaction(transfer.transaction).await;
// Associate lock with transaction
sdk.stealth_outputs_api()
.locks_set_transaction_id(transfer.lock_id, transaction.calculate_id())?;

let result = transaction_service.submit_transaction(transaction).await;
match result {
Ok(tx_id) => {
notifier.notify(TransactionSubmittedEvent {
Expand All @@ -1014,26 +1034,13 @@ pub async fn handle_stealth_transfer(
Ok(StealthTransferResponse { transaction_id: tx_id })
},
Err(e) => {
if let Err(err) = sdk
.stealth_outputs_api()
.release_locked_outputs(transfer.transaction_lock_id)
{
if let Err(err) = sdk.stealth_outputs_api().release_lock(transfer.lock_id) {
error!(
target: LOG_TARGET,
"Failed to release locked outputs after submission failure: {}",
err
);
}
if let Err(err) = sdk
.stealth_outputs_api()
.release_revealed_funds(transfer.transaction_lock_id)
{
error!(
target: LOG_TARGET,
"Failed to release revealed funds after submission failure: {}",
err
);
}

Err(anyhow::anyhow!("Transaction submission failed: {}", e))
},
Expand All @@ -1060,23 +1067,10 @@ pub async fn handle_associate_stealth_resource(
));
}

// Ensure the resource is in the local cache
if !sdk.resources_api().exists(&req.resource_address)? {
let substate = sdk
.substate_api()
.get_substate_from_network(req.resource_address.into())
.await?;
let resource = substate.into_substate_value().into_resource().ok_or_else(|| {
general_error(format!(
"Indexer returned Substate at address {} is not a resource",
req.resource_address
))
})?;
sdk.resources_api().upsert_resource(&req.resource_address, &resource)?;
}

sdk.accounts_api()
.associate_stealth_resource(account.component_address(), req.resource_address)?;
context
.account_monitor()
.associate_resource(*account.component_address(), req.resource_address)
.await?;

context
.account_monitor()
Expand Down
8 changes: 4 additions & 4 deletions applications/tari_walletd/src/handlers/confidential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rand::rngs::OsRng;
use serde_json::json;
use tari_crypto::{commitment::HomomorphicCommitmentFactory, keys::PublicKey as _, ristretto::RistrettoPublicKey};
use tari_engine_types::{crypto::get_commitment_factory, ToByteType};
use tari_ootle_wallet_crypto::{AlwaysMissLookupTable, IoReaderValueLookup, UnblindedOutputStatement};
use tari_ootle_wallet_crypto::{AlwaysMissLookupTable, IoReaderValueLookup, UnblindedOutputWitness};
use tari_ootle_wallet_sdk::{
apis::key_manager::KeyBranch,
models::{ConfidentialOutputModel, OutputStatus},
Expand Down Expand Up @@ -114,7 +114,7 @@ pub async fn handle_create_transfer_proof(
)
})?;

let output_statement = UnblindedOutputStatement {
let output_statement = UnblindedOutputWitness {
amount: req.amount,
mask: output_mask.key,
sender_public_nonce: public_nonce,
Expand Down Expand Up @@ -171,7 +171,7 @@ pub async fn handle_create_transfer_proof(
lock_id: Some(lock_id),
})?;

Some(UnblindedOutputStatement {
Some(UnblindedOutputWitness {
amount: change_amount,
mask: change_mask.key,
sender_public_nonce: public_nonce,
Expand Down Expand Up @@ -253,7 +253,7 @@ pub async fn handle_create_output_proof(
None,
)?;

let statement = UnblindedOutputStatement {
let statement = UnblindedOutputWitness {
amount: req.amount,
mask: output_mask.key,
sender_public_nonce: public_nonce,
Expand Down
7 changes: 1 addition & 6 deletions applications/tari_walletd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ use log::*;
use tari_common_types::seeds::seed_words::SeedWords;
use tari_ootle_common_types::{optional::Optional, NumPreshards};
use tari_ootle_wallet_sdk::{
apis::{
config::{ConfigApi, ConfigKey},
key_manager::KeyBranch,
},
apis::config::{ConfigApi, ConfigKey},
cipher_seed::CipherSeedRestore,
WalletSdk as Sdk,
WalletSdkConfig,
Expand Down Expand Up @@ -80,8 +77,6 @@ pub async fn run_tari_ootle_walletd(
let needs_seed_recovery =
wallet_sdk.initialize_cipher_seed(seed_words.map(CipherSeedRestore::FromSeedWords).unwrap_or_default())?;

wallet_sdk.key_manager_api().get_or_create_initial(KeyBranch::Account)?;

tokio::spawn({
let wallet_sdk = wallet_sdk.clone();
async move {
Expand Down
4 changes: 3 additions & 1 deletion applications/tari_walletd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ async fn main() -> Result<(), anyhow::Error> {
.map(CipherSeedRestore::FromSeedWords)
.unwrap_or(CipherSeedRestore::CreateNewIfRequired),
)?;
let seed_words = sdk.load_seed_words()?;
let seed_words = sdk
.load_seed_words()?
.expect("Bug: seed words were initialized however load_seed_words returned None");
println!("{}", seed_words.join(" ").reveal())
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,8 @@ export function TransferNftDialog(props: TransferNftDialogProps) {
const result = await calculateFeeEstimate?.();

if (result && "Accept" in result.result.result) {
const fee = result.fee + 100; // Add buffer as per original comment
setTransferFormState({ maxFee: fee.toString() });
return fee;
setTransferFormState({ maxFee: result.fee.toString() });
return result.fee;
} else {
console.error("Fee estimation rejected:", result);
throw new Error("Could not estimate transfer fee");
Expand All @@ -232,9 +231,8 @@ export function TransferNftDialog(props: TransferNftDialogProps) {
const result = await calculateFeeEstimate?.();

if (result && "Accept" in result.result.result) {
const fee = result.fee + 100; // Add buffer
setTransferFormState({ maxFee: fee.toString() });
return fee;
setTransferFormState({ maxFee: result.fee.toString() });
return result.fee;
} else {
console.error("Fee estimation rejected:", result);
throw new Error("Could not estimate transfer fee");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,11 @@ export function SendMoneyDialog(props: SendMoneyDialogProps) {
throw new Error("Fee estimation failed");
}

const fee = resp.final_fee + 100;
let fee = resp.final_fee;
if (props.resource_type === "Confidential") {
// TODO: Add extra amount for confidential transactions, since the bullet proof size is variable
fee += 100;
}
setTransferFormState((prevState) => ({ ...prevState, fee: fee.toString() }));
} catch (error) {
console.error("Fee estimation error:", error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ function ManifestEditor() {
throw new Error("No result returned for dry run");
}
if ("Accept" in finalize!.result) {
setFee(BigInt(finalize!.fee_receipt.total_fees_paid) + 100n);
setFee(BigInt(finalize!.fee_receipt.total_fees_paid));
setFinalizeError(null);
console.log("Dry run successful:", finalize);
} else if ("Reject" in finalize!.result) {
Expand Down
Loading
Loading