Skip to content

Commit

Permalink
Merge branch '2.0' into implicit-account-creation-transition
Browse files Browse the repository at this point in the history
  • Loading branch information
thibault-martinez authored Nov 21, 2023
2 parents 2be5e03 + 805f5df commit e6e6bbc
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 123 deletions.
2 changes: 1 addition & 1 deletion bindings/core/src/method_handler/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM
}
ClientMethod::GetOutputsIgnoreErrors { output_ids } => {
let outputs_response = client
.get_outputs_with_metadata_ignore_errors(&output_ids)
.get_outputs_with_metadata_ignore_not_found(&output_ids)
.await?
.iter()
.map(OutputWithMetadataResponse::from)
Expand Down
70 changes: 70 additions & 0 deletions bindings/nodejs/lib/types/block/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ enum AddressType {
Anchor = 24,
/** An implicit account creation address. */
ImplicitAccountCreation = 32,
/** A Multi address. */
Multi = 40,
/** An address with restricted capabilities. */
Restricted = 48,
}
Expand Down Expand Up @@ -78,6 +80,7 @@ abstract class Address {
throw new Error('Invalid JSON');
}
}

/**
* An Ed25519 Address.
*/
Expand Down Expand Up @@ -256,6 +259,70 @@ class RestrictedAddress extends Address {
}
}

/**
* A weighted address.
*/
class WeightedAddress {
/**
* The unlocked address.
*/
@Type(() => Address, {
discriminator: {
property: 'type',
subTypes: [
{ value: Ed25519Address, name: AddressType.Ed25519 as any },
{ value: AccountAddress, name: AddressType.Account as any },
{ value: NftAddress, name: AddressType.Nft as any },
{ value: AnchorAddress, name: AddressType.Anchor as any },
],
},
})
readonly address: Address;
/**
* The weight of the unlocked address.
*/
readonly weight: number;

/**
* @param address The unlocked address.
* @param weight The weight of the unlocked address.
*/
constructor(address: Address, weight: number) {
this.address = address;
this.weight = weight;
}
}

/**
* An address that consists of addresses with weights and a threshold value.
* The Multi Address can be unlocked if the cumulative weight of all unlocked addresses is equal to or exceeds the
* threshold.
*/
class MultiAddress extends Address {
/**
* The weighted unlocked addresses.
*/
readonly addresses: WeightedAddress[];
/**
* The threshold that needs to be reached by the unlocked addresses in order to unlock the multi address.
*/
readonly threshold: number;

/**
* @param addresses The weighted unlocked addresses.
* @param threshold The threshold that needs to be reached by the unlocked addresses in order to unlock the multi address.
*/
constructor(addresses: WeightedAddress[], threshold: number) {
super(AddressType.Multi);
this.addresses = addresses;
this.threshold = threshold;
}

toString(): string {
return JSON.stringify(this);
}
}

const AddressDiscriminator = {
property: 'type',
subTypes: [
Expand All @@ -267,6 +334,7 @@ const AddressDiscriminator = {
value: ImplicitAccountCreationAddress,
name: AddressType.ImplicitAccountCreation as any,
},
{ value: MultiAddress, name: AddressType.Multi as any },
{ value: RestrictedAddress, name: AddressType.Restricted as any },
],
};
Expand All @@ -281,5 +349,7 @@ export {
NftAddress,
AnchorAddress,
ImplicitAccountCreationAddress,
WeightedAddress,
MultiAddress,
RestrictedAddress,
};
2 changes: 1 addition & 1 deletion cli/src/wallet_cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ async fn print_outputs(mut outputs: Vec<OutputData>, title: &str) -> Result<(),
};

println_log_info!(
"{:<5}{}\t{}\t{}",
"{:<5}{} {:<16}{}",
i,
&output_data.output_id,
kind_str,
Expand Down
50 changes: 22 additions & 28 deletions sdk/src/client/node_api/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod routes;
use packable::PackableExt;

use crate::{
client::{Client, Result},
client::{node_api::error::Error as NodeApiError, Client, Error, Result},
types::block::output::{Output, OutputId, OutputMetadata, OutputWithMetadata},
};

Expand All @@ -31,51 +31,45 @@ impl Client {
futures::future::try_join_all(output_ids.iter().map(|id| self.get_output(id))).await
}

/// Requests outputs by their output ID in parallel, ignoring failed requests.
/// Requests outputs by their output ID in parallel, ignoring outputs not found.
/// Useful to get data about spent outputs, that might not be pruned yet.
pub async fn get_outputs_ignore_errors(&self, output_ids: &[OutputId]) -> Result<Vec<Output>> {
Ok(
futures::future::join_all(output_ids.iter().map(|id| self.get_output(id)))
.await
.into_iter()
.filter_map(Result::ok)
.collect(),
)
pub async fn get_outputs_ignore_not_found(&self, output_ids: &[OutputId]) -> Result<Vec<Output>> {
futures::future::join_all(output_ids.iter().map(|id| self.get_output(id)))
.await
.into_iter()
.filter(|res| !matches!(res, Err(Error::Node(NodeApiError::NotFound(_)))))
.collect()
}

/// Requests metadata for outputs by their output ID in parallel.
pub async fn get_outputs_metadata(&self, output_ids: &[OutputId]) -> Result<Vec<OutputMetadata>> {
futures::future::try_join_all(output_ids.iter().map(|id| self.get_output_metadata(id))).await
}

/// Requests metadata for outputs by their output ID in parallel, ignoring failed requests.
pub async fn get_outputs_metadata_ignore_errors(&self, output_ids: &[OutputId]) -> Result<Vec<OutputMetadata>> {
Ok(
futures::future::join_all(output_ids.iter().map(|id| self.get_output_metadata(id)))
.await
.into_iter()
.filter_map(Result::ok)
.collect(),
)
/// Requests metadata for outputs by their output ID in parallel, ignoring outputs not found.
pub async fn get_outputs_metadata_ignore_not_found(&self, output_ids: &[OutputId]) -> Result<Vec<OutputMetadata>> {
futures::future::join_all(output_ids.iter().map(|id| self.get_output_metadata(id)))
.await
.into_iter()
.filter(|res| !matches!(res, Err(Error::Node(NodeApiError::NotFound(_)))))
.collect()
}

/// Requests outputs and their metadata by their output ID in parallel.
pub async fn get_outputs_with_metadata(&self, output_ids: &[OutputId]) -> Result<Vec<OutputWithMetadata>> {
futures::future::try_join_all(output_ids.iter().map(|id| self.get_output_with_metadata(id))).await
}

/// Requests outputs and their metadata by their output ID in parallel, ignoring failed requests.
/// Requests outputs and their metadata by their output ID in parallel, ignoring outputs not found.
/// Useful to get data about spent outputs, that might not be pruned yet.
pub async fn get_outputs_with_metadata_ignore_errors(
pub async fn get_outputs_with_metadata_ignore_not_found(
&self,
output_ids: &[OutputId],
) -> Result<Vec<OutputWithMetadata>> {
Ok(
futures::future::join_all(output_ids.iter().map(|id| self.get_output_with_metadata(id)))
.await
.into_iter()
.filter_map(Result::ok)
.collect(),
)
futures::future::join_all(output_ids.iter().map(|id| self.get_output_with_metadata(id)))
.await
.into_iter()
.filter(|res| !matches!(res, Err(Error::Node(NodeApiError::NotFound(_)))))
.collect()
}
}
74 changes: 40 additions & 34 deletions sdk/src/client/secret/ledger_nano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use std::{collections::HashMap, ops::Range};
use async_trait::async_trait;
use crypto::{
keys::{bip44::Bip44, slip10::Segment},
signatures::secp256k1_ecdsa::{self, EvmAddress},
signatures::{
ed25519,
secp256k1_ecdsa::{self, EvmAddress},
},
};
use iota_ledger_nano::{
api::errors::APIError, get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index,
Expand All @@ -26,7 +29,7 @@ use crate::{
LedgerNanoStatus, PreparedTransactionData,
},
types::block::{
address::{AccountAddress, Address, AnchorAddress, Ed25519Address, NftAddress},
address::{AccountAddress, Address, AnchorAddress, NftAddress},
output::Output,
payload::signed_transaction::SignedTransactionPayload,
signature::{Ed25519Signature, Signature},
Expand Down Expand Up @@ -131,41 +134,44 @@ impl TryFrom<u8> for LedgerDeviceType {
impl SecretManage for LedgerSecretManager {
type Error = crate::client::Error;

async fn generate_ed25519_addresses(
async fn generate_ed25519_public_keys(
&self,
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
// current ledger app only supports IOTA_COIN_TYPE, SHIMMER_COIN_TYPE and TESTNET_COIN_TYPE
coin_type: u32,
account_index: u32,
address_indexes: Range<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, Self::Error> {
let options = options.into().unwrap_or_default();
let bip32_account = account_index.harden().into();

let bip32 = LedgerBIP32Index {
bip32_index: address_indexes.start.harden().into(),
bip32_change: u32::from(options.internal).harden().into(),
};

// lock the mutex to prevent multiple simultaneous requests to a ledger
let lock = self.mutex.lock().await;

// get ledger
let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?;
if ledger.is_debug_app() {
ledger
.set_non_interactive_mode(self.non_interactive)
.map_err(Error::from)?;
}

let addresses = ledger
.get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len())
.map_err(Error::from)?;

drop(lock);

Ok(addresses.into_iter().map(Ed25519Address::new).collect())
_coin_type: u32,
_account_index: u32,
_address_indexes: Range<u32>,
_options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<ed25519::PublicKey>, Self::Error> {
// need an update on the ledger C lib
todo!();
//
// let options = options.into().unwrap_or_default();
// let bip32_account = account_index.harden().into();

// let bip32 = LedgerBIP32Index {
// bip32_index: address_indexes.start.harden().into(),
// bip32_change: u32::from(options.internal).harden().into(),
// };

// // lock the mutex to prevent multiple simultaneous requests to a ledger
// let lock = self.mutex.lock().await;

// // get ledger
// let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?;
// if ledger.is_debug_app() {
// ledger
// .set_non_interactive_mode(self.non_interactive)
// .map_err(Error::from)?;
// }

// let addresses = ledger
// .get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len())
// .map_err(Error::from)?;

// drop(lock);

// Ok(addresses.into_iter().map(Ed25519Address::new).collect())
}

async fn generate_evm_addresses(
Expand Down
16 changes: 5 additions & 11 deletions sdk/src/client/secret/mnemonic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::ops::Range;

use async_trait::async_trait;
use crypto::{
hashes::{blake2b::Blake2b256, Digest},
keys::{bip39::Mnemonic, bip44::Bip44, slip10::Seed},
signatures::{
ed25519,
Expand All @@ -20,8 +19,7 @@ use super::{GenerateAddressOptions, SecretManage};
use crate::{
client::{api::PreparedTransactionData, Client, Error},
types::block::{
address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature,
unlock::Unlocks,
payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks,
},
};

Expand All @@ -40,13 +38,13 @@ impl std::fmt::Debug for MnemonicSecretManager {
impl SecretManage for MnemonicSecretManager {
type Error = Error;

async fn generate_ed25519_addresses(
async fn generate_ed25519_public_keys(
&self,
coin_type: u32,
account_index: u32,
address_indexes: Range<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, Self::Error> {
) -> Result<Vec<ed25519::PublicKey>, Self::Error> {
let internal = options.into().map(|o| o.internal).unwrap_or_default();

Ok(address_indexes
Expand All @@ -59,13 +57,9 @@ impl SecretManage for MnemonicSecretManager {
let public_key = chain
.derive(&self.0.to_master_key::<ed25519::SecretKey>())
.secret_key()
.public_key()
.to_bytes();

// Hash the public key to get the address
let result = Blake2b256::digest(public_key).into();
.public_key();

crate::client::Result::Ok(Ed25519Address::new(result))
crate::client::Result::Ok(public_key)
})
.collect::<Result<_, _>>()?)
}
Expand Down
Loading

0 comments on commit e6e6bbc

Please sign in to comment.