# Swap lifecycle

This page traces a single swap through the entire system, end-to-end, showing exactly which contract is invoked at which step and what state changes occur.

## Example: A buy of 1 ETH worth of TITHE

Assume a hypothetical state:

* TITHE price: 0.0000001 ETH per TITHE (i.e., 10,000,000 TITHE per ETH)
* Pool state: 730M TITHE / 73 ETH liquidity (initial)
* `accETHPerToken` in distributor: 0
* Buyer wallet: holds 0 TITHE, has 1 ETH

{% stepper %}
{% step %}

### Buyer initiates swap

Buyer's wallet (or router) calls `PoolManager.swap()` on the V4 pool manager:

```
swap(TITHE/ETH pool, params: {
    zeroForOne: true,        // currency0 (ETH) → currency1 (TITHE)
    amountSpecified: -1e18,  // exact input of 1 ETH
    sqrtPriceLimitX96: ...
})
```

{% endstep %}

{% step %}

### PoolManager calls `beforeSwap` on the hook

The PoolManager checks the pool's hook address and calls `CustomHook.beforeSwap()`:

```
beforeSwap(sender, key, params, hookData)
```

The hook executes:

1. Determines this is a buy (zeroForOne == true).
2. Computes the fee: `1e18 * 500 / 10000 = 5e16` (0.05 ETH = 5%).
3. Constructs a `BeforeSwapDelta` claiming 5e16 ETH from the input side.
4. Returns the delta.

The hook now has 0.05 ETH waiting to be settled via `PoolManager.take()` after the swap.
{% endstep %}

{% step %}

### PoolManager executes the swap

The pool's effective input is now `1e18 - 5e16 = 0.95e18` (0.95 ETH).

The constant-product (or concentrated liquidity) math runs on 0.95 ETH input, producing TITHE output. At the assumed price, approximately 9,500,000 TITHE.
{% endstep %}

{% step %}

### PoolManager calls `afterSwap` (no-op for buys)

`afterSwap` is invoked but returns a zero delta for buys (the fee was already taken on the input side).
{% endstep %}

{% step %}

### Hook settles its claim

After the swap is committed, the hook calls `PoolManager.take(currency: ETH, recipient: hook, amount: 5e16)` to actually receive its 0.05 ETH.
{% endstep %}

{% step %}

### Hook splits and forwards the fee

The hook now holds 0.05 ETH and needs to split it 4:1:

* `rewardAmount = 5e16 * 4 / 5 = 4e16` (0.04 ETH)
* `treasuryAmount = 5e16 * 1 / 5 = 1e16` (0.01 ETH)

The hook calls:

```
RewardDistributor.notifyReward{value: 4e16}();
treasury.call{value: 1e16}("");
```

After these calls, the hook's balance is back to zero. It holds no funds between swaps.
{% endstep %}

{% step %}

### Distributor updates the accumulator

Inside `notifyReward`:

```
accETHPerToken += (4e16 * 1e18) / totalEligibleSupply
                = (4e16 * 1e18) / 730e24       // assuming only LP holds TITHE
                = (4e34) / (730e24)
                = ~54,794 (in 1e18-scaled units)
```

Wait — at this stage, the only TITHE holder is the pool itself (LP), which is **excluded** from rewards. So `totalEligibleSupply` is effectively zero at this moment, and the deposit is held in the distributor but not yet distributed.

In practice, by the time this swap happens, the buyer is *about to receive* TITHE and the seed holders have already withdrawn some of their tokens from Sablier. So the eligible supply is non-zero, and the accumulator updates accordingly.
{% endstep %}

{% step %}

### Buyer receives TITHE

The PoolManager transfers \~9,500,000 TITHE to the buyer's wallet (or to the router, which forwards it).
{% endstep %}

{% step %}

### Token's settlement override fires

The TITHE token's `_beforeTokenTransfer` hook calls `RewardDistributor.settleRewards(pool, buyer)`:

* `_settle(pool)` is a no-op (pool is excluded).
* `_settle(buyer)` runs: the buyer's pre-transfer balance was 0, so their pending rewards are 0. Their `rewardDebt` is set to `0 * accETHPerToken / 1e18 = 0`.

After the transfer completes, the buyer's balance updates to \~9,500,000 TITHE. From this point forward, every increment to `accETHPerToken` will be reflected in their pending rewards.
{% endstep %}
{% endstepper %}

### Final state

* Buyer: 0 ETH, \~9,500,000 TITHE
* Pool: 73.95 ETH, 720,500,000 TITHE
* Hook: 0 ETH
* RewardDistributor: holds 0.04 ETH, `accETHPerToken` has incremented
* Treasury: gained 0.01 ETH
* Buyer's `pendingRewards()` view: 0 (just-arrived TITHE earns rewards from this point forward, not retroactively)

***

## Example: A sell of 1,000,000 TITHE

Assume the seller holds 1,000,000 TITHE and the price is unchanged.

{% stepper %}
{% step %}

### Swap submission and execution

Seller calls `swap` with `zeroForOne: false`, `amountSpecified: -1e6 * 1e18` (exact input of 1M TITHE).

The hook's `beforeSwap` is a no-op for sells (returns zero delta).

The pool executes the swap: 1M TITHE → \~0.099 ETH output (after slippage on the curve).
{% endstep %}

{% step %}

### PoolManager calls `afterSwap`

`afterSwap(sender, key, params, delta, hookData)` is called.

The hook reads `delta` to determine the ETH output (\~0.099e18 wei), computes the fee:

```
fee = 0.099e18 * 500 / 10000 = 4.95e15 (≈0.00495 ETH)
```

Returns an `AfterSwapDelta` claiming this fee from the output side.
{% endstep %}

{% step %}

### Hook splits and forwards

Same as steps 5–6 of the buy flow:

* 0.00396 ETH to distributor
* 0.00099 ETH to treasury
  {% endstep %}

{% step %}

### Seller receives ETH

PoolManager transfers `0.099 - 0.00495 = 0.09405` ETH to seller.
{% endstep %}

{% step %}

### Token's settlement override fires

The TITHE token's `_beforeTokenTransfer` fires when the seller sends TITHE to the pool. `RewardDistributor.settleRewards(seller, pool)` runs:

* `_settle(seller)`: computes the seller's accrued rewards based on their pre-transfer 1,000,000 TITHE balance and the current `accETHPerToken`, adds to `unclaimedRewards[seller]`.
* `_settle(pool)`: no-op (excluded).

So even when selling, the seller does **not** forfeit their accumulated rewards. They are settled into the seller's `unclaimedRewards` bucket and can be claimed at any future time, regardless of whether the seller still holds any TITHE.
{% endstep %}
{% endstepper %}

### Final state

* Seller: gained 0.09405 ETH, lost 1M TITHE
* Seller's `unclaimedRewards`: increased by their pro-rata share of all swap fees that occurred while they held the 1M TITHE
* Pool: lost \~0.099 ETH, gained 1M TITHE
* Hook: 0 ETH
* Distributor: holds an additional 0.00396 ETH
* Treasury: gained 0.00099 ETH

***

<details>

<summary>What if a swap fails to deposit?</summary>

If `RewardDistributor.notifyReward()` reverts for any reason, the hook's call reverts, which causes the entire `afterSwap` (or `beforeSwap`) to revert, which causes the entire swap to revert. The swap is atomic with the fee deposit.

This is the desired behavior. It is impossible to have a successful swap that did not pay the fee. It is also impossible to have a failed swap that nonetheless transferred fees — both succeed or both fail.

</details>

<details>

<summary>What if a holder claims?</summary>

Independent of swaps. A holder can call `RewardDistributor.claim()` at any time:

1. The distributor calls `_settle(claimer)` to bring their unclaimed balance up to date with the current accumulator.
2. Reads `unclaimedRewards[claimer]`, requires it to be > 0.
3. Zeroes the unclaimed balance.
4. Transfers ETH to the claimer.

The claim is one transaction. The claimer pays gas (\~50,000–80,000 on mainnet for a simple claim). The amount received is the full accumulated balance — no fee, no slippage.

</details>

## Summary

The lifecycle is deterministic and fully on-chain. Every swap produces exactly one fee event, exactly one distribution update, and exactly one treasury transfer. There are no off-chain components, no oracles, no relayer dependencies. The system runs entirely on Ethereum block-time semantics.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tithe-coin.gitbook.io/tithe-coin/swap-lifecycle.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
