Skip to content

Commit

Permalink
Merge branch '2.0' into feat/output-storage-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Thoralf-M authored Jan 10, 2024
2 parents 8400cfa + a2cfbe3 commit 42dd18f
Show file tree
Hide file tree
Showing 20 changed files with 353 additions and 226 deletions.
1 change: 1 addition & 0 deletions cli/src/wallet_cli/completer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustyline::{
const WALLET_COMMANDS: &[&str] = &[
"accounts",
"address",
"allot-mana",
"balance",
"burn-native-token",
"burn-nft",
Expand Down
54 changes: 49 additions & 5 deletions cli/src/wallet_cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use iota_sdk::{
api::plugins::participation::types::ParticipationEventId,
block::{
address::{Bech32Address, ToBech32Ext},
mana::ManaAllotment,
output::{
unlock_condition::AddressUnlockCondition, AccountId, BasicOutputBuilder, FoundryId, NativeToken,
NativeTokensBuilder, NftId, Output, OutputId, TokenId,
Expand Down Expand Up @@ -60,6 +61,8 @@ pub enum WalletCommand {
Accounts,
/// Print the wallet address.
Address,
/// Allots mana to an account.
AllotMana { mana: u64, account_id: Option<AccountId> },
/// Print the wallet balance.
Balance,
/// Burn an amount of native token.
Expand Down Expand Up @@ -325,12 +328,18 @@ pub async fn accounts_command(wallet: &Wallet) -> Result<(), Error> {
let output_id = account.output_id;
let account_id = account.output.as_account().account_id_non_null(&output_id);
let account_address = account_id.to_bech32(wallet.client().get_bech32_hrp().await?);
let bic = wallet
.client()
.get_account_congestion(&account_id)
.await?
.block_issuance_credits;

println_log_info!(
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n",
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic}\n",
"Output ID:",
"Account ID:",
"Account Address:"
"Account Address:",
"BIC:"
);
}

Expand All @@ -344,6 +353,32 @@ pub async fn address_command(wallet: &Wallet) -> Result<(), Error> {
Ok(())
}

// `allot-mana` command
pub async fn allot_mana_command(wallet: &Wallet, mana: u64, account_id: Option<AccountId>) -> Result<(), Error> {
let wallet_data = wallet.data().await;
let account_id = account_id
.or(wallet_data
.accounts()
.next()
.map(|o| o.output.as_account().account_id_non_null(&o.output_id)))
.or(wallet_data
.implicit_accounts()
.next()
.map(|o| AccountId::from(&o.output_id)))
.ok_or(WalletError::AccountNotFound)?;
drop(wallet_data);

let transaction = wallet.allot_mana([ManaAllotment::new(account_id, mana)?], None).await?;

println_log_info!(
"Mana allotment transaction sent:\n{:?}\n{:?}",
transaction.transaction_id,
transaction.block_id
);

Ok(())
}

// `balance` command
pub async fn balance_command(wallet: &Wallet) -> Result<(), Error> {
let balance = wallet.balance().await?;
Expand Down Expand Up @@ -497,7 +532,7 @@ pub async fn congestion_command(wallet: &Wallet, account_id: Option<AccountId>)
.next()
.map(|o| AccountId::from(&o.output_id))
})
.ok_or(WalletError::NoAccountToIssueBlock)?
.ok_or(WalletError::AccountNotFound)?
};

let congestion = wallet.client().get_account_congestion(&account_id).await?;
Expand Down Expand Up @@ -668,12 +703,18 @@ pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> {
let output_id = implicit_account.output_id;
let account_id = AccountId::from(&output_id);
let account_address = account_id.to_bech32(wallet.client().get_bech32_hrp().await?);
let bic = wallet
.client()
.get_account_congestion(&account_id)
.await?
.block_issuance_credits;

println_log_info!(
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n",
"{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic}\n",
"Output ID:",
"Account ID:",
"Account Address:"
"Account Address:",
"BIC:"
);
}

Expand Down Expand Up @@ -1173,6 +1214,9 @@ pub async fn prompt_internal(
match protocol_cli.command {
WalletCommand::Accounts => accounts_command(wallet).await,
WalletCommand::Address => address_command(wallet).await,
WalletCommand::AllotMana { mana, account_id } => {
allot_mana_command(wallet, mana, account_id).await
}
WalletCommand::Balance => balance_command(wallet).await,
WalletCommand::BurnNativeToken { token_id, amount } => {
burn_native_token_command(wallet, token_id, amount).await
Expand Down
15 changes: 13 additions & 2 deletions sdk/src/client/api/block_builder/input_selection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
types::block::{
address::{AccountAddress, Address, NftAddress},
input::INPUT_COUNT_RANGE,
mana::ManaAllotment,
output::{
AccountOutput, ChainId, FoundryOutput, NativeTokensBuilder, NftOutput, Output, OutputId, OUTPUT_COUNT_RANGE,
},
Expand All @@ -45,6 +46,7 @@ pub struct InputSelection {
slot_index: SlotIndex,
requirements: Vec<Requirement>,
automatically_transitioned: HashSet<ChainId>,
mana_allotments: u64,
}

/// Result of the input selection algorithm.
Expand Down Expand Up @@ -101,6 +103,8 @@ impl InputSelection {
}

fn init(&mut self) -> Result<(), Error> {
// Adds an initial mana requirement.
self.requirements.push(Requirement::Mana(self.mana_allotments));
// Adds an initial amount requirement.
self.requirements.push(Requirement::Amount);
// Adds an initial native tokens requirement.
Expand Down Expand Up @@ -190,6 +194,7 @@ impl InputSelection {
slot_index: SlotIndex::from(0),
requirements: Vec::new(),
automatically_transitioned: HashSet::new(),
mana_allotments: 0,
}
}

Expand Down Expand Up @@ -223,6 +228,12 @@ impl InputSelection {
self
}

/// Sets the mana allotments sum of an [`InputSelection`].
pub fn with_mana_allotments<'a>(mut self, mana_allotments: impl Iterator<Item = &'a ManaAllotment>) -> Self {
self.mana_allotments = mana_allotments.map(ManaAllotment::mana).sum();
self
}

fn filter_inputs(&mut self) {
self.available_inputs.retain(|input| {
// TODO what about other kinds?
Expand Down Expand Up @@ -373,8 +384,8 @@ impl InputSelection {
/// transaction. Also creates a remainder output and chain transition outputs if required.
pub fn select(mut self) -> Result<Selected, Error> {
if !OUTPUT_COUNT_RANGE.contains(&(self.outputs.len() as u16)) {
// If burn is provided, outputs will be added later
if !(self.outputs.is_empty() && self.burn.is_some()) {
// If burn or mana allotments are provided, outputs will be added later.
if !(self.outputs.is_empty() && (self.burn.is_some() || self.mana_allotments != 0)) {
return Err(Error::InvalidOutputCount(self.outputs.len()));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use super::{Error, InputSelection};
use crate::client::secret::types::InputSigningData;

impl InputSelection {
pub(crate) fn fulfill_mana_requirement(&mut self, allotments: u64) -> Result<Vec<InputSigningData>, Error> {
let required_mana = self.outputs.iter().map(|o| o.mana()).sum::<u64>() + allotments;
let mut selected_mana = self.selected_inputs.iter().map(|o| o.output.mana()).sum::<u64>();

if selected_mana >= required_mana {
log::debug!("Mana requirement already fulfilled");
Ok(Vec::new())
} else {
let mut inputs = Vec::new();

// TODO we should do as for the amount and have preferences on which inputs to pick.
while let Some(input) = self.available_inputs.pop() {
selected_mana += input.output.mana();
inputs.push(input);

if selected_mana >= required_mana {
break;
}
}

Ok(inputs)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) mod amount;
pub(crate) mod ed25519;
pub(crate) mod foundry;
pub(crate) mod issuer;
pub(crate) mod mana;
pub(crate) mod native_tokens;
pub(crate) mod nft;
pub(crate) mod sender;
Expand Down Expand Up @@ -39,6 +40,8 @@ pub enum Requirement {
NativeTokens,
/// Amount requirement.
Amount,
/// Mana requirement.
Mana(u64),
}

impl InputSelection {
Expand All @@ -56,6 +59,7 @@ impl InputSelection {
Requirement::Nft(nft_id) => self.fulfill_nft_requirement(nft_id),
Requirement::NativeTokens => self.fulfill_native_tokens_requirement(),
Requirement::Amount => self.fulfill_amount_requirement(),
Requirement::Mana(allotments) => self.fulfill_mana_requirement(allotments),
}
}

Expand Down
Loading

0 comments on commit 42dd18f

Please sign in to comment.