> For the complete documentation index, see [llms.txt](https://docs.xrpl-commons.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xrpl-commons.org/core-dev-bootcamp/module03bis/homework2.md).

# Homework 2: Implement a Custom Validation Check

[← Back to Transactors: Understanding the Lifecycle of a Transaction](/core-dev-bootcamp/module03bis.md)

***

### Objective

Add a custom preflight or preclaim check to an existing transactor and verify it works correctly with unit tests.

***

### Background

For this exercise, you'll add a new validation rule to the CheckCreate transactor. The goal is to understand how validation logic is added and tested.

***

### Scenario

Imagine a new business rule: **Checks cannot be created for amounts less than 1 XRP (1,000,000 drops)**.

This is a hypothetical requirement for learning purposes—it doesn't exist in the actual protocol.

***

### Tasks

#### Part 1: Identify Where to Add the Check

1. Open `src/xrpld/app/tx/detail/CreateCheck.cpp`
2. Determine whether this validation belongs in:
   * `preflight()` - stateless validation
   * `preclaim()` - ledger-state validation
3. **Question**: Which phase is appropriate and why?

***

#### Part 2: Implement the Validation

Add the following check to the appropriate phase:

```cpp
// Minimum check amount: 1 XRP
STAmount const sendMax{ctx.tx.getFieldAmount(sfSendMax)};

if (sendMax.native())
{
    // Only enforce for XRP
    if (sendMax < STAmount{1000000})
    {
        JLOG(ctx.j.warn()) << "Check amount below minimum (1 XRP)";
        return temBAD_AMOUNT;  // or appropriate code
    }
}
```

**Questions to consider:**

* Should this apply to non-XRP amounts?
* What result code is most appropriate?
* Should this be amendment-gated?

***

#### Part 3: Write a Unit Test

Create a test in `src/test/app/Check_test.cpp` (or a new test file):

```cpp
void testMinimumAmount()
{
    testcase("Minimum check amount");

    using namespace jtx;
    Env env(*this);

    Account const alice{"alice"};
    Account const bob{"bob"};

    // Fund accounts
    env.fund(XRP(10000), alice, bob);
    env.close();

    // Test: Check below minimum should fail
    {
        auto const seq = env.seq(alice);

        env(check::create(alice, bob, drops(999999)),
            ter(temBAD_AMOUNT));  // Expected failure
    }

    // Test: Check at minimum should succeed
    {
        auto const seq = env.seq(alice);

        env(check::create(alice, bob, drops(1000000)),
            ter(tesSUCCESS));  // Expected success
    }

    // Test: Check above minimum should succeed
    {
        auto const seq = env.seq(alice);

        env(check::create(alice, bob, XRP(100)),
            ter(tesSUCCESS));  // Expected success
    }
}
```

***

#### Part 4: Compile and Run Tests

1. Rebuild rippled:

```bash
cd build
cmake --build . --target rippled
```

2. Run the Check tests:

```bash
./rippled --unittest Check_test
```

3. Verify your new test passes.

***

#### Part 5: Edge Cases

Add tests for edge cases:

1. **Exactly 1 XRP**: Should this succeed or fail?
2. **Non-XRP amounts**: Should the minimum apply?
3. **Negative amounts**: How is this handled? (Already validated elsewhere?)

***

### Deliverables

1. **Modified code**: The validation check you added
2. **Test code**: Unit tests for the new validation
3. **Test output**: Results showing tests pass
4. **Analysis document** answering:
   * Why you chose preflight vs preclaim
   * Why you chose a particular result code
   * What edge cases you considered

***

### Discussion Questions

1. If this were a real feature, should it be amendment-gated? Why?
2. What would happen if you returned `tecBAD_AMOUNT` instead of `temBAD_AMOUNT`?
3. Could this check ever pass in preflight but fail in doApply? Under what circumstances?
4. How would you test this check in a live (non-standalone) environment?

***

### Bonus Challenge

Make the minimum amount configurable:

1. Add a new amendment flag
2. Only enforce the minimum when the amendment is enabled
3. Write tests for both enabled and disabled states

***

### Cleanup

**Important**: After completing this exercise, revert your changes to avoid affecting the actual codebase:

```bash
git checkout -- src/xrpld/app/tx/detail/CreateCheck.cpp
git checkout -- src/test/app/Check_test.cpp
```
