Homework 3: Analyze TER Code Paths

← Back to Transactors: Understanding the Lifecycle of a Transaction


Objective

Map out the conditions that lead to different TER codes for the CheckCreate transactor and create a decision tree.


Background

Understanding which conditions lead to which result codes is essential for:

  • Building applications that handle errors correctly

  • Debugging transaction failures

  • Implementing new transactors with appropriate error handling


Tasks

Part 1: Code Analysis

Review CreateCheck.cpp and identify every return statement with its result code.

Create a table:

Phase
Code
Condition
Description

preflight

temREDUNDANT

Account == Destination

Self-send

preflight

temBAD_AMOUNT

!isLegalNet(sendMax) || sendMax.signum() <= 0

Invalid amount

...

...

...

...


Part 2: Create a Decision Tree

Draw a flowchart showing how each result code can be reached:

You can use:

  • ASCII art (like above)

  • A drawing tool (Mermaid, draw.io, etc.)

  • Hand-drawn diagram (photo)


Part 3: Categorize by Phase

Group the result codes by phase:

Preflight (returns NotTEC):

  • temREDUNDANT

  • temBAD_AMOUNT

  • temBAD_CURRENCY

  • temBAD_EXPIRATION

Preclaim (can return TEC):

  • tecNO_DST

  • tecNO_PERMISSION

  • tecDST_TAG_NEEDED

  • tecFROZEN

  • tecEXPIRED

doApply (can return TEC):

  • tefINTERNAL

  • tecINSUFFICIENT_RESERVE

  • tecDIR_FULL

  • tesSUCCESS


Part 4: Identify Implicit Checks

Some checks are performed by the base Transactor class, not by CreateCheck itself:

  1. Fee validation: Where is this checked?

  2. Sequence validation: Where is this checked?

  3. Signature validation: Where is this checked?

Add these to your decision tree.


Part 5: Create Test Scenarios

For each possible result code, describe a test scenario that would trigger it:

Result Code
Test Scenario

temREDUNDANT

Create check with same source and destination account

temBAD_AMOUNT

Create check with SendMax = 0

tecNO_DST

Create check to non-existent account

...

...


Deliverables

  1. Complete table of all return statements and conditions

  2. Decision tree diagram showing all code paths

  3. Phase categorization with explanations

  4. Test scenario list for each result code


Analysis Questions

Answer the following:

  1. Why can't preflight return tec codes?

    • Explain the security implications

  2. What's the difference between tecNO_DST and temDST_NEEDED?

    • When would each be used?

  3. If a transaction fails with tecFROZEN, what exactly was frozen?

    • Identify all the freeze checks

  4. Can a CheckCreate ever fail in doApply with a result other than tesSUCCESS, tefINTERNAL, tecINSUFFICIENT_RESERVE, or tecDIR_FULL?

    • Explain why or why not

  5. What result code would you expect for each scenario:

    • Check with Expiration = 0

    • Check with SendMax = -100 XRP

    • Check to an AMM pool account

    • Check with destination tag when lsfRequireDestTag is set


Bonus Challenge

Create a similar analysis for CashCheck and compare the result code patterns. What codes are unique to each transaction type?


Resources

  • src/xrpld/app/tx/detail/CreateCheck.cpp - CheckCreate implementation

  • include/xrpl/protocol/TER.h - TER code definitions

  • src/xrpld/app/tx/detail/Transactor.cpp - Base class checks

Last updated