# Swap LifeCycle

This page traces a single swap through the 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: locked LP at full range
* `rewardPerTokenStored` in hook: some current value `R`
* Buyer wallet: holds 0 TITHE, has 1 ETH

#### Step 1 — 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 (negative = exact-input)
    sqrtPriceLimitX96: ...
})
```

#### Step 2 — PoolManager calls `beforeSwap` on the hook

The PoolManager invokes `TitheHook.beforeSwap()`. The hook executes:

1. Checks `params.amountSpecified < 0` (exact-input). ✓
2. Checks that the specified currency is ETH. ✓
3. Computes the fee: `1e18 * 500 / 10000 = 5e16` (0.05 ETH).
4. Calls `poolManager.take(NATIVE, address(this), 5e16)` to claim 0.05 ETH from PM's flash accounting.
5. Splits the fee:
   * `treasuryAccrued += 5e16 * 100 / 500 = 1e16` (0.01 ETH)
   * `_accrue(5e16 * 400 / 500)` → `rewardPerTokenStored` increases by `4e16 * 1e18 / effectiveSupply`
6. Returns `BeforeSwapDelta(-5e16, 0)` — tells the pool that the input is reduced by 0.05 ETH.

#### Step 3 — PoolManager executes the swap

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

The concentrated-liquidity math runs on 0.95 ETH input, producing approximately 9,500,000 TITHE output (at the assumed price, before slippage).

#### Step 4 — PoolManager calls `afterSwap`

`afterSwap` is invoked but exits early — the hook detects this case was already handled in `beforeSwap`:

```solidity
bool handledInBefore = (params.amountSpecified < 0) && (
    params.zeroForOne
        ? key.currency0 == CurrencyLibrary.NATIVE
        : key.currency1 == CurrencyLibrary.NATIVE
);
if (handledInBefore) return (this.afterSwap.selector, 0);
```

#### Step 5 — Buyer receives TITHE

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

#### Step 6 — Token's `_update` override fires

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

* `_settle(pool)`: skipped because the pool is excluded by `_isRewardable`.
* `_settle(buyer)`: the buyer's pre-transfer balance is 0, so `owed = 0`. The hook sets `userRewardPerTokenPaid[buyer] = rewardPerTokenStored` (the current value, including the just-added increment from this swap).

After the transfer completes, the buyer's balance is \~9,500,000 TITHE. From this point forward, every future increment to `rewardPerTokenStored` will earn the buyer their proportional share.

#### Final state

* Buyer: 0 ETH, \~9,500,000 TITHE
* Pool: gained 0.95 ETH, lost \~9,500,000 TITHE
* Hook: holds 0.05 ETH (0.04 toward rewards, 0.01 toward treasury)
* `treasuryAccrued`: increased by 0.01 ETH
* `rewardPerTokenStored`: incremented to reflect the 0.04 ETH distributed
* Buyer's `pendingRewardsOf()`: 0 (just-arrived TITHE earns 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.

#### Step 1 — Seller initiates swap

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

#### Step 2 — Token's `_update` fires (TITHE moving from seller to pool)

When the seller's TITHE is moved into the pool, `_update` runs first. `settleRewards(seller, pool)`:

* `_settle(seller)`: computes the seller's accrued ETH based on their 1M TITHE balance and the current `rewardPerTokenStored`, adds it to `pendingRewards[seller]`, snapshots the new debt.
* `_settle(pool)`: skipped (excluded).

Critically: the seller's accrued rewards are settled into their `pendingRewards` bucket *before* their balance changes. They can claim those rewards at any future time, even after selling their entire position.

#### Step 3 — PoolManager calls `beforeSwap`

The hook checks: is ETH the specified currency? No — TITHE is. The hook returns `ZERO_DELTA` and does nothing.

#### Step 4 — Pool executes the swap

The pool produces approximately `0.099 ETH` output (after curve math on 1M TITHE input).

#### Step 5 — PoolManager calls `afterSwap`

The hook executes:

1. Detects this was not handled in `beforeSwap`.
2. Reads the ETH delta from `BalanceDelta` (negative, since pool sends ETH out).
3. Computes `ethAmount = 0.099e18`.
4. Computes `fee = 0.099e18 * 500 / 10000 = 4.95e15` (\~0.00495 ETH).
5. Calls `poolManager.take(NATIVE, address(this), 4.95e15)`.
6. Splits: \~0.00099 ETH to treasury, \~0.00396 ETH to reward accumulator.
7. Returns `hookDelta = 4.95e15` — tells PM to reduce the swapper's ETH output by this amount.

#### Step 6 — Seller receives ETH

PoolManager transfers `0.099e18 - 4.95e15 = ~0.09405 ETH` to the seller.

#### Final state

* Seller: gained \~0.09405 ETH, lost 1M TITHE
* Seller's `pendingRewards`: increased by their pro-rata share of all swap fees that occurred while they held their TITHE (settled in step 2)
* Pool: lost \~0.099 ETH, gained 1M TITHE
* Hook: holds an additional \~0.00495 ETH
* `treasuryAccrued`: increased by \~0.00099 ETH
* `rewardPerTokenStored`: incremented to reflect the \~0.00396 ETH distributed

The seller can still call `claim()` at any future time to receive the ETH that accrued to them during the time they held the 1M TITHE, even though they no longer hold any.

***

### What happens if anything in the swap reverts?

The hook's interactions with the PoolManager are atomic with the swap. If `poolManager.take()` fails, if `_accrue` reverts, if any internal math overflows — the entire swap reverts.

This is by design. 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.

### What happens when a holder claims?

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

1. The hook calls `_settle(claimer)` to bring their `pendingRewards` up to date.
2. Reads `pendingRewards[claimer]`, requires it to be > 0.
3. Zeroes the pending balance.
4. Transfers ETH to the claimer via low-level `call`.
5. Reverts if the transfer fails.

The claim is one transaction. The claimer pays gas. The amount received is the full accumulated balance — no fee, no slippage.

### What happens when the treasury withdraws?

The 3/5 treasury multisig calls `TitheHook.withdrawTreasury()`:

1. The hook verifies `msg.sender == treasury`.
2. Reads `treasuryAccrued`, requires it to be > 0.
3. Zeroes the accrued balance.
4. Transfers the full balance to the treasury address.

Same pull pattern as holder claims. The treasury chooses when to pull, on its own timing.

### Summary

The swap lifecycle is deterministic and fully on-chain. Every swap produces exactly one fee event, exactly one accumulator update, and exactly one treasury increment. 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/tithe-coin/architecture/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.
