GUIDELINE 09
Document the happy path and failure path
Users need to know what happened, whether anything was committed, and what action is safe next.
Model visible states
- Idle, validating, estimating, awaiting confirmation, submitting, accepted, executing, succeeded, failed, and timed out.
- Keep validation errors beside the field and execution errors beside the affected action.
- Separate offline/network failures from contract rejection and insufficient funds.
- Never say “failed” if the outcome is unknown. Re-query by transaction or wallet state.
- Allow a retry only when it cannot create an unintended duplicate.
Log safely
Log operation names, public addresses, transaction IDs, network, cluster, status, and sanitized error codes. Exclude passwords, mnemonics, keypairs, decrypted content, and unnecessary personal data.
Normalize errors without hiding detail
async function runWrite(makeTransaction) {
setState("estimating");
try {
const tx = makeTransaction();
const estimate = await itza.estimate_tx(tx);
if (!await confirmEstimate(estimate)) return setState("cancelled");
setState("submitting");
await itza.submit_tx_with_result(tx, event => setFinalState(event));
} catch (error) {
console.error("write failed", { message: error.message });
setState("failed", friendlyMessage(error));
}
}Bottom line
For each action, write down success, rejection, transport failure, timeout, and safe retry behavior before polishing the happy path.