1
+ use crate :: lib:: diagnosis:: DiagnosedError ;
1
2
use crate :: lib:: ledger_types:: { AccountIdBlob , BlockHeight , Memo , TransferError } ;
2
3
use crate :: lib:: nns_types:: account_identifier:: Subaccount ;
3
4
use crate :: lib:: {
@@ -8,7 +9,7 @@ use crate::lib::{
8
9
} ,
9
10
nns_types:: { account_identifier:: AccountIdentifier , icpts:: ICPTs } ,
10
11
} ;
11
- use anyhow:: { bail, ensure, Context } ;
12
+ use anyhow:: { anyhow , bail, ensure, Context } ;
12
13
use backoff:: backoff:: Backoff ;
13
14
use backoff:: ExponentialBackoff ;
14
15
use candid:: { Decode , Encode , Principal } ;
@@ -142,6 +143,12 @@ pub async fn transfer(
142
143
info ! ( logger, "{}" , TransferError :: TxDuplicate { duplicate_of } ) ;
143
144
break duplicate_of;
144
145
}
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
+ }
145
152
Err ( transfer_err) => bail ! ( transfer_err) ,
146
153
}
147
154
}
@@ -164,6 +171,29 @@ pub async fn transfer(
164
171
Ok ( block_height)
165
172
}
166
173
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
+
167
197
fn retryable ( agent_error : & AgentError ) -> bool {
168
198
match agent_error {
169
199
AgentError :: CertifiedReject ( RejectResponse {
0 commit comments