Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions applications/tari_app_utilities/src/genesis_resources.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2025 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use tari_engine_types::resource::Resource;
use tari_ootle_common_types::Network;
use tari_template_lib::{
auth::{OwnerRule, ResourceAccessRules},
constants::PUBLIC_IDENTITY_RESOURCE_ADDRESS,
models::{Metadata, ResourceAddress},
prelude::{ResourceType, STEALTH_TARI_RESOURCE_ADDRESS},
resource::TOKEN_SYMBOL,
rule,
};

pub fn get_public_identity_resource() -> (ResourceAddress, Resource) {
let value = Resource::new(
ResourceType::NonFungible,
None,
OwnerRule::None,
ResourceAccessRules::new(),
Metadata::from([(TOKEN_SYMBOL, "ID".to_string())]),
None,
None,
0,
false,
);
(PUBLIC_IDENTITY_RESOURCE_ADDRESS, value)
}

pub fn get_stealth_tari_resource(network: Network) -> (ResourceAddress, Resource) {
let symbol = if network.is_testnet() { "tXTR" } else { "XTR" };
let xtr_resource = Resource::new(
ResourceType::Stealth,
None,
OwnerRule::None,
ResourceAccessRules::new()
// These are defaults, but just for explicitness
.mintable(rule!(deny_all))
.burnable(rule!(deny_all))
.recallable(rule!(deny_all))
.freezable(rule!(deny_all))
.update_access_rules(rule!(deny_all)),
Metadata::from([(TOKEN_SYMBOL, symbol)]),
None,
None,
6,
// Disable total supply tracking for XTR. This is because it is not feasible to include "the fee exhaust" in
// the tracking (as that would require mutating the resource on every transaction). Tracking supply can
// be done by summing up the total burn claims (ClaimedOutputTombstone) and subtracting the total exhaust in
// fee receipts.
false,
);
(STEALTH_TARI_RESOURCE_ADDRESS, xtr_resource)
}
1 change: 1 addition & 0 deletions applications/tari_app_utilities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod common;
pub mod configuration;
pub mod epoch_oracle_config;
pub mod fee_tables;
pub mod genesis_resources;
pub mod keypair;
pub mod p2p_config;
pub mod seed_peer;
Expand Down
45 changes: 8 additions & 37 deletions applications/tari_validator_node/src/genesis_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use tari_engine_types::{
substate::{SubstateId, SubstateValue},
vault::Vault,
};
use tari_ootle_app_utilities::shared_consts::TXTR_FAUCET_INITIAL_SUPPLY;
use tari_ootle_app_utilities::{
genesis_resources::{get_public_identity_resource, get_stealth_tari_resource},
shared_consts::TXTR_FAUCET_INITIAL_SUPPLY,
};
use tari_ootle_common_types::{
Epoch,
Network,
Expand Down Expand Up @@ -69,41 +72,11 @@ where
return Ok(());
}

let value = Resource::new(
ResourceType::NonFungible,
None,
OwnerRule::None,
ResourceAccessRules::new(),
Metadata::from([(TOKEN_SYMBOL, "ID".to_string())]),
None,
None,
0,
false,
);
create_substate(tx, num_preshards, PUBLIC_IDENTITY_RESOURCE_ADDRESS, value)?;
let (public_identity_address, resource) = get_public_identity_resource();
create_substate(tx, num_preshards, public_identity_address, resource)?;

let symbol = if network.is_testnet() { "tXTR" } else { "XTR" };
let xtr_resource = Resource::new(
ResourceType::Stealth,
None,
OwnerRule::None,
ResourceAccessRules::new()
// These are defaults, but just for explicitness
.mintable(rule!(deny_all))
.burnable(rule!(deny_all))
.recallable(rule!(deny_all))
.freezable(rule!(deny_all))
.update_access_rules(rule!(deny_all)),
Metadata::from([(TOKEN_SYMBOL, symbol)]),
None,
None,
6,
// Disable total supply tracking for XTR. This is because it is not feasible to include "the fee exhaust" in
// the tracking (as that would require mutating the resource on every transaction). Tracking supply can
// be done by summing up the total burn claims (ClaimedOutputTombstone) and subtracting the total exhaust in
// fee receipts.
false,
);
let (xtr_address, xtr_resource) = get_stealth_tari_resource(network);
create_substate(tx, num_preshards, xtr_address, xtr_resource)?;

if network.is_testnet() {
// Create tXTR faucet
Expand All @@ -112,8 +85,6 @@ where
create_nft_faucet(tx, num_preshards)?;
}

create_substate(tx, num_preshards, STEALTH_TARI_RESOURCE_ADDRESS, xtr_resource)?;

Ok(())
}

Expand Down
14 changes: 5 additions & 9 deletions applications/tari_wallet_cli/src/command/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@ use tari_engine_types::{
};
use tari_ootle_address::OotleAddress;
use tari_ootle_common_types::{Epoch, SubstateAddress, SubstateRequirement};
use tari_ootle_wallet_sdk::{
apis::confidential_transfer::UtxoInputSelection,
crypto::memo::Memo,
models::BranchAndKeyId,
};
use tari_ootle_wallet_sdk::{apis::confidential_transfer::UtxoInputSelection, crypto::memo::Memo};
use tari_template_lib::{
constants::STEALTH_TARI_RESOURCE_ADDRESS,
models::{BucketId, NonFungibleAddress, NonFungibleId},
Expand Down Expand Up @@ -283,7 +279,7 @@ pub async fn handle_submit(args: SubmitArgs, client: &mut WalletDaemonClient) ->
let resp = client
.submit_transaction_dry_run(TransactionSubmitDryRunRequest {
transaction,
seal_signer: BranchAndKeyId::for_account(owner_key_id),
seal_signer: owner_key_id,
other_signers: vec![],
detect_inputs: common.detect_inputs.unwrap_or(true),
detect_inputs_use_unversioned: true,
Expand All @@ -294,7 +290,7 @@ pub async fn handle_submit(args: SubmitArgs, client: &mut WalletDaemonClient) ->
} else {
let request = TransactionSubmitRequest {
transaction,
seal_signer: BranchAndKeyId::for_account(owner_key_id),
seal_signer: owner_key_id,
other_signers: vec![],
detect_inputs: common.detect_inputs.unwrap_or(true),
detect_inputs_use_unversioned: true,
Expand Down Expand Up @@ -352,7 +348,7 @@ async fn handle_submit_manifest(
let resp = client
.submit_transaction_dry_run(TransactionSubmitDryRunRequest {
transaction,
seal_signer: BranchAndKeyId::for_account(owner_key_id),
seal_signer: owner_key_id,
other_signers: vec![],
detect_inputs: common.detect_inputs.unwrap_or(true),
detect_inputs_use_unversioned: true,
Expand All @@ -363,7 +359,7 @@ async fn handle_submit_manifest(
} else {
let request = TransactionSubmitRequest {
transaction,
seal_signer: BranchAndKeyId::for_account(owner_key_id),
seal_signer: owner_key_id,
other_signers: vec![],
detect_inputs: common.detect_inputs.unwrap_or(true),
detect_inputs_use_unversioned: true,
Expand Down
41 changes: 13 additions & 28 deletions applications/tari_walletd/src/handlers/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use tari_ootle_wallet_sdk::{
stealth_transfer::{StealthTransferParams, TransferOutput},
substate::ValidatorScanResult,
},
models::{BranchAndKeyId, KeyBranch, KeyId, NewAccountData, TransactionSubmittedEvent},
models::{KeyBranch, NewAccountData, TransactionSubmittedEvent},
};
use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS;
use tari_template_lib::{
Expand Down Expand Up @@ -483,9 +483,9 @@ pub async fn handle_claim_burn(
}

let (nonce, output_public_nonce) = RistrettoPublicKey::random_keypair(&mut OsRng);
let account_owner = sdk.key_manager_api().get_account_owner_key(account_owner_key_id)?;
let account_owner = sdk.key_manager_api().get_key(account_owner_key_id)?;
let account_owner_public_key = account_owner.to_public_key();
let view_only = sdk.key_manager_api().get_view_only_key(account.view_only_key_id())?;
let view_only = sdk.key_manager_api().get_key(account.view_only_key_id())?;
let view_only_public_key = view_only.to_public_key();
let memo = Memo::new_message("Claimed burned XTR from L1").expect("valid memo");
// NOTE: the confidential encryption format and the bullet proofs currently do not support amounts larger than
Expand Down Expand Up @@ -556,9 +556,7 @@ pub async fn handle_claim_burn(
.add_input(XTR)
.build();

let transaction = sdk
.local_signer_api()
.sign(KeyBranch::Nonce, public_signer_key.key_id, transaction)?;
let transaction = sdk.signer_api().sign(public_signer_key.key_id, transaction)?;

let tx_id = context.transaction_service().submit_transaction(transaction).await?;

Expand Down Expand Up @@ -661,9 +659,7 @@ pub async fn handle_create_free_test_coins(
.with_inputs(inputs.into_iter().map(|input| input.into_unversioned()))
.build();

let transaction = sdk
.local_signer_api()
.sign(KeyBranch::Account, account_owner_key_id, transaction)?;
let transaction = sdk.signer_api().sign(account_owner_key_id, transaction)?;

info!(
target: LOG_TARGET,
Expand Down Expand Up @@ -853,9 +849,7 @@ pub async fn handle_transfer(
.with_inputs(inputs.into_iter().map(|req| req.into_unversioned()))
.build();

let transaction = sdk
.local_signer_api()
.sign(KeyBranch::Account, account_owner_key_id, transaction)?;
let transaction = sdk.signer_api().sign(account_owner_key_id, transaction)?;

// If dry run we can return the result immediately
if req.dry_run {
Expand Down Expand Up @@ -1030,19 +1024,14 @@ pub async fn handle_stealth_transfer(
let additional_sig = transfer
.additional_signer
.as_ref()
.map(|s| {
sdk.local_signer_api()
.get_signature(s.branch, s.key_id, &main_pk, &transaction)
})
.map(|s| sdk.signer_api().get_signature(s.key_id, &main_pk, &transaction))
.transpose()?
.map(|sig| TransactionSignature::new(sig.public_key.to_byte_type(), sig.signature.to_byte_type()));

let transaction = transaction.build_with_signatures(additional_sig.into_iter().collect());

// Sign and seal the final transaction
let transaction =
sdk.local_signer_api()
.sign(transfer.main_signer.branch, transfer.main_signer.key_id, transaction)?;
let transaction = sdk.signer_api().sign(transfer.main_signer.key_id, transaction)?;

if req.dry_run {
// Release the lock immediately as dry run does not submit the transaction
Expand Down Expand Up @@ -1139,16 +1128,13 @@ pub async fn handle_create_stealth_transfer_statement(
.transpose()?;

let must_sign_with_account_key = inputs.as_ref().is_some_and(|i| i.revealed.is_positive());
let (signing_key_branch, signing_key_id) = if must_sign_with_account_key {
(KeyBranch::Account, sender_key_id)
let signing_key_id = if must_sign_with_account_key {
sender_key_id
} else {
let next_index = sdk.key_manager_api().next_derived_key_index(KeyBranch::Nonce)?;
(KeyBranch::Nonce, KeyId::derived(next_index))
sdk.key_manager_api().next_derived_key_id(KeyBranch::Nonce)?.into()
};

let required_signer = sdk
.key_manager_api()
.get_public_key(signing_key_branch, signing_key_id)?;
let required_signer = sdk.key_manager_api().get_public_key(signing_key_id)?;
let required_signer = required_signer.public_key.to_byte_type();

let outputs = req
Expand All @@ -1161,7 +1147,6 @@ pub async fn handle_create_stealth_transfer_statement(
let statement = sdk
.stealth_outputs_api()
.generate_transfer_statement(TransferStatementParams {
spend_key_branch: KeyBranch::Account,
spend_key_id: sender_key_id,
view_only_key_id: sender_account.view_only_key_id(),
resource_address: &req.resource_address,
Expand All @@ -1185,7 +1170,7 @@ pub async fn handle_create_stealth_transfer_statement(
required_signer,
})?;

required_signers.insert(BranchAndKeyId::new(signing_key_branch, signing_key_id));
required_signers.insert(signing_key_id);
statements.push(statement);
}

Expand Down
2 changes: 1 addition & 1 deletion applications/tari_walletd/src/handlers/confidential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub async fn handle_create_transfer_proof(
// TODO: Any errors from here need to unlock the outputs, ideally just roll back (refactor required but doable).

// TODO: Wrap up key/encrypted data handling in the wallet SDK
let account_key = sdk.key_manager_api().get_account_owner_key(account_owner_key_id)?;
let account_key = sdk.key_manager_api().get_key(account_owner_key_id)?;
let output_mask = sdk.key_manager_api().next_key(KeyBranch::ConfidentialMask)?;
let (_, public_nonce) = RistrettoPublicKey::random_keypair(&mut OsRng);

Expand Down
48 changes: 14 additions & 34 deletions applications/tari_walletd/src/handlers/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
use std::{collections::HashSet, fmt::Display};

use tari_engine_types::{component::derive_component_address_from_public_key, ToByteType};
use tari_ootle_common_types::{
optional::{IsNotFoundError, Optional},
SubstateRequirement,
};
use tari_ootle_common_types::{optional::Optional, SubstateRequirement};
use tari_ootle_wallet_sdk::{
apis::accounts::{AccountsApi, AccountsApiError},
models::{AccountWithAddress, DerivedKeyIndex, TransactionFinalizedEvent, WalletEvent},
network::{StatusResponseError, WalletNetworkInterface},
storage::WalletStore,
WalletSdk,
WalletSdkSpec,
};
use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS;
use tari_template_lib::models::ComponentAddress;
Expand Down Expand Up @@ -88,15 +84,10 @@ pub async fn wait_for_result_and_account(
}
}

pub fn get_account_with_inputs<TStore, TNetworkInterface>(
pub fn get_account_with_inputs<TSpec: WalletSdkSpec>(
account: Option<&ComponentAddressOrName>,
sdk: &WalletSdk<TStore, TNetworkInterface>,
) -> Result<(AccountWithAddress, HashSet<SubstateRequirement>), anyhow::Error>
where
TStore: WalletStore,
TNetworkInterface: WalletNetworkInterface,
TNetworkInterface::Error: IsNotFoundError + StatusResponseError,
{
sdk: &WalletSdk<TSpec>,
) -> Result<(AccountWithAddress, HashSet<SubstateRequirement>), anyhow::Error> {
let account = get_account_or_default(account, &sdk.accounts_api())?;
let inputs = if account.is_confirmed_on_chain() {
// Add all versioned account child addresses as inputs
Expand All @@ -109,41 +100,30 @@ where
Ok((account, inputs))
}

pub fn get_account<TStore, TNetworkInterface>(
pub fn get_account<TSpec: WalletSdkSpec>(
account: &ComponentAddressOrName,
accounts_api: &AccountsApi<'_, TStore, TNetworkInterface>,
) -> Result<AccountWithAddress, AccountsApiError>
where
TStore: WalletStore,
{
accounts_api: &AccountsApi<'_, TSpec>,
) -> Result<AccountWithAddress, AccountsApiError> {
match account {
ComponentAddressOrName::ComponentAddress(address) => Ok(accounts_api.get_account_by_address(address)?),
ComponentAddressOrName::Name(name) => Ok(accounts_api.get_account_by_name(name)?),
}
}

pub(crate) fn get_account_by_key_index<TStore, TNetworkInterface>(
sdk: &WalletSdk<TStore, TNetworkInterface>,
pub(crate) fn get_account_by_key_index<TSpec: WalletSdkSpec>(
sdk: &WalletSdk<TSpec>,
key_index: DerivedKeyIndex,
) -> Result<AccountWithAddress, AccountsApiError>
where
TStore: WalletStore,
TNetworkInterface: WalletNetworkInterface,
TNetworkInterface::Error: IsNotFoundError + StatusResponseError,
{
) -> Result<AccountWithAddress, AccountsApiError> {
let key = sdk.key_manager_api().derive_account_address(key_index)?;
let address =
derive_component_address_from_public_key(&ACCOUNT_TEMPLATE_ADDRESS, &key.address.account_key().to_byte_type());
sdk.accounts_api().get_account_by_address(&address)
}

pub fn get_account_or_default<TStore, TNetworkInterface>(
pub fn get_account_or_default<TSpec: WalletSdkSpec>(
account: Option<&ComponentAddressOrName>,
accounts_api: &AccountsApi<'_, TStore, TNetworkInterface>,
) -> Result<AccountWithAddress, anyhow::Error>
where
TStore: WalletStore,
{
accounts_api: &AccountsApi<'_, TSpec>,
) -> Result<AccountWithAddress, anyhow::Error> {
let result;
if let Some(a) = account {
result = get_account(a, accounts_api)
Expand Down
Loading
Loading