Skip to content

Commit 869f15a

Browse files
chore: improve error message for 'dfx cycles convert'. (#4019)
* Improve error message for 'dfx cycles convert'. * Improve the diagnosis message. * Catch the error deeper and compose the DiagnosedError. * Discard the changes in 'diagnosis.rs'. * Remove context error message from DiagnosedError. * Update changelog. * Addressed review comments.
1 parent 065a8e9 commit 869f15a

File tree

5 files changed

+61
-3
lines changed

5 files changed

+61
-3
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ Please top up your cycles balance by converting ICP to cycles like below:
4848
'dfx cycles convert --amount=0.123'.
4949
```
5050

51+
### chore: improve `dfx cycles convert` messages.
52+
53+
If users run `dfx cycles convert` without enough ICP tokens, show additional messages to indicate what to do next.
54+
```
55+
Error explanation:
56+
Insufficient ICP balance to finish the transfer transaction.
57+
How to resolve the error:
58+
Please top up your ICP balance.
59+
60+
Your account address for receiving ICP from centralized exchanges: 8494c01329531c06254ff45dad87db806ae6ed935ad6a504cdbc00a935db7b49
61+
(run `dfx ledger account-id` to display)
62+
63+
Your principal for ICP wallets and decentralized exchanges: ueuar-wxbnk-bdcsr-dnrh3-rsyq6-ffned-h64ox-vxywi-gzawf-ot4pv-sqe
64+
(run `dfx identity get-principal` to display)
65+
```
66+
5167
# 0.24.3
5268

5369
### feat: Bitcoin support in PocketIC

e2e/tests-dfx/cycles-ledger.bash

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,10 @@ current_time_nanoseconds() {
898898

899899
deploy_cycles_ledger
900900

901+
# Test failed to convert ICP to cycles without enough ICP.
902+
assert_command_fail dfx cycles convert --amount 12.5 --identity alice
903+
assert_contains "Insufficient ICP balance to finish the transfer transaction."
904+
901905
assert_command dfx --identity cycle-giver ledger transfer --memo 1234 --amount 100 "$(dfx ledger account-id --of-principal "$ALICE")"
902906
assert_command dfx --identity cycle-giver ledger transfer --memo 1234 --amount 100 "$(dfx ledger account-id --of-principal "$ALICE" --subaccount "$ALICE_SUBACCT1")"
903907

src/dfx/src/lib/diagnosis.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ pub type Diagnosis = (Option<String>, Option<String>);
1717
pub const NULL_DIAGNOSIS: Diagnosis = (None, None);
1818

1919
#[derive(ThisError, Debug)]
20-
// This message will appear in the context trace of the stack. The diagnosis should not be displayed there yet.
21-
#[error("Diagnosis was added here.")]
2220
/// If you do not need the generic error diagnosis to run, you can add a DiagnosedError with .context(err: DiagnosedError).
2321
/// In that case, no extra diagnosis is attempted and the last-added explanation and suggestion are printed out.
2422
pub struct DiagnosedError {
@@ -29,6 +27,12 @@ pub struct DiagnosedError {
2927
pub action_suggestion: Option<String>,
3028
}
3129

30+
impl std::fmt::Display for DiagnosedError {
31+
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32+
Ok(())
33+
}
34+
}
35+
3236
impl DiagnosedError {
3337
pub fn new(error_explanation: String, action_suggestion: String) -> Self {
3438
Self {

src/dfx/src/lib/operations/ledger.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::lib::diagnosis::DiagnosedError;
12
use crate::lib::ledger_types::{AccountIdBlob, BlockHeight, Memo, TransferError};
23
use crate::lib::nns_types::account_identifier::Subaccount;
34
use crate::lib::{
@@ -8,7 +9,7 @@ use crate::lib::{
89
},
910
nns_types::{account_identifier::AccountIdentifier, icpts::ICPTs},
1011
};
11-
use anyhow::{bail, ensure, Context};
12+
use anyhow::{anyhow, bail, ensure, Context};
1213
use backoff::backoff::Backoff;
1314
use backoff::ExponentialBackoff;
1415
use candid::{Decode, Encode, Principal};
@@ -142,6 +143,12 @@ pub async fn transfer(
142143
info!(logger, "{}", TransferError::TxDuplicate { duplicate_of });
143144
break duplicate_of;
144145
}
146+
Err(TransferError::InsufficientFunds { balance }) => {
147+
return Err(anyhow!(TransferError::InsufficientFunds { balance }))
148+
.with_context(|| {
149+
diagnose_insufficient_funds_error(agent, from_subaccount)
150+
});
151+
}
145152
Err(transfer_err) => bail!(transfer_err),
146153
}
147154
}
@@ -164,6 +171,29 @@ pub async fn transfer(
164171
Ok(block_height)
165172
}
166173

174+
fn diagnose_insufficient_funds_error(
175+
agent: &Agent,
176+
subaccount: Option<Subaccount>,
177+
) -> DiagnosedError {
178+
let principal = agent.get_principal().unwrap(); // This should always succeed at this point.
179+
180+
let explanation = "Insufficient ICP balance to finish the transfer transaction.";
181+
let suggestion = format!(
182+
"Please top up your ICP balance.
183+
184+
Your account address for receiving ICP from centralized exchanges: {}
185+
(run `dfx ledger account-id` to display)
186+
187+
Your principal for ICP wallets and decentralized exchanges: {}
188+
(run `dfx identity get-principal` to display)
189+
",
190+
AccountIdentifier::new(principal, subaccount),
191+
principal.to_text()
192+
);
193+
194+
DiagnosedError::new(explanation.to_string(), suggestion)
195+
}
196+
167197
fn retryable(agent_error: &AgentError) -> bool {
168198
match agent_error {
169199
AgentError::CertifiedReject(RejectResponse {

src/dfx/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ fn print_error_and_diagnosis(err: Error, error_diagnosis: Diagnosis) {
7272

7373
// print error chain stack
7474
for (level, cause) in err.chain().enumerate() {
75+
if cause.to_string().is_empty() {
76+
continue;
77+
}
78+
7579
let (color, prefix) = if level == 0 {
7680
(term::color::RED, "Error")
7781
} else {

0 commit comments

Comments
 (0)