Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ledger nano remainder finder #1496

Merged
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
1 change: 1 addition & 0 deletions sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `Account::claim_outputs()` if an input has less amount than min storage deposit;
- URLs aren't truncated after the hostname anymore;
- Ledger nano potentially failing to identify the correct remainder output;

## 1.1.1 - 2023-10-11

Expand Down
65 changes: 29 additions & 36 deletions sdk/src/client/secret/ledger_nano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,53 +294,46 @@ impl SecretManage for LedgerSecretManager {
.prepare_blind_signing(input_bip32_indices, essence_hash)
.map_err(Error::from)?;
} else {
// figure out the remainder address and bip32 index (if there is one)
// figure out the remainder output and bip32 index (if there is one)
#[allow(clippy::option_if_let_else)]
let (remainder_address, remainder_bip32): (Option<&Address>, LedgerBIP32Index) =
match &prepared_transaction.remainder {
Some(a) => {
if let Some(chain) = a.chain {
(
Some(&a.address),
LedgerBIP32Index {
bip32_change: chain.change.harden().into(),
bip32_index: chain.address_index.harden().into(),
},
)
} else {
(None, LedgerBIP32Index::default())
}
let (remainder_output, remainder_bip32) = match &prepared_transaction.remainder {
Some(remainder) => {
if let Some(chain) = remainder.chain {
(
Some(&remainder.output),
LedgerBIP32Index {
bip32_change: chain.change.harden().into(),
bip32_index: chain.address_index.harden().into(),
},
)
} else {
(None, LedgerBIP32Index::default())
}
None => (None, LedgerBIP32Index::default()),
};
}
None => (None, LedgerBIP32Index::default()),
};

let mut remainder_index = 0u16;
if let Some(remainder_address) = remainder_address {
if let Some(remainder_output) = remainder_output {
match &prepared_transaction.essence {
TransactionEssence::Regular(essence) => {
// find the index of the remainder in the essence
// this has to be done because outputs in essences are sorted
// lexically and therefore the remainder is not always the last output.
// The index within the essence and the bip32 index will be validated
// by the hardware wallet.
// The outputs in the essence already are sorted
// at this place, so we can rely on their order and don't have to sort it again.
'essence_outputs: for output in essence.outputs().iter() {
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
if let Output::Basic(s) = output {
if let Some(address) = s.unlock_conditions().address() {
if *remainder_address == *address.address() {
break 'essence_outputs;
}
}
} else {
// Find the index of the remainder in the transaction because it is not always the last output.
// The index within the transaction and the bip32 index will be validated by the hardware
// wallet.
for output in essence.outputs().iter() {
if !output.is_basic() {
log::debug!("[LEDGER] unsupported output");
return Err(Error::MiscError.into());
}

if remainder_output == output {
break;
}

remainder_index += 1;
}

// was index found?
// Was index found?
if remainder_index as usize == essence.outputs().len() {
log::debug!("[LEDGER] remainder_index not found");
return Err(Error::MiscError.into());
Expand All @@ -355,15 +348,15 @@ impl SecretManage for LedgerSecretManager {
"[LEDGER] {:?} {:02x?} {} {} {:?}",
input_bip32_indices,
essence_bytes,
remainder_address.is_some(),
remainder_output.is_some(),
remainder_index,
remainder_bip32
);
ledger
.prepare_signing(
input_bip32_indices,
essence_bytes,
remainder_address.is_some(),
remainder_output.is_some(),
remainder_index,
remainder_bip32,
)
Expand Down
Loading