> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ankarachain.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Income, Liquidity & Title Records

> Pro-rata revenue distribution, RFQ/OTC secondary trading, land-title encumbrances and custody logs, and carbon-registry cross-references on Stellar.

Extensions to the RWA templates that production tokenization needs beyond representing
an asset. All are Stellar-only.

***

## Revenue distribution: `revenue-distributor`

`real-estate-token::declare_rental_distribution` and
`mining-rights-token::declare_royalty` only **record** an amount. The distributor
actually **pays** holders.

1. The asset token's **Manager** calls `create_distribution(creator, asset_token, payout_token, amount, claim_window_secs, memo)`.
   This takes a **balance snapshot** on the token and escrows `amount` of the payout
   token (for example a USDC SAC). Only the issuer can distribute, because the snapshot
   needs the token's Manager auth.
2. Each holder calls `claim(holder, id)` and receives `amount × balance_at_snapshot ÷ supply_at_snapshot`.
   Selling after the snapshot doesn't forfeit that period's payout.
3. `claim_many` claims up to 20 periods at once. With a claim window set, the creator can
   `reclaim` anything left after the deadline. That includes shares held by contracts
   that can't claim, such as an RFQ escrow.

For recurring income, create one distribution per period.

**Snapshots** come from `ankara-common`. Every fungible template now exposes
`snapshot()` (Manager), `current_snapshot_id()`, `balance_of_at(id, snapshot)` and
`total_supply_at(snapshot)`. A token that never takes a snapshot pays no extra storage.

```ts theme={null}
import { RevenueDistributor } from "@ankarachain/sdk";

const d = new RevenueDistributor(issuerAdapter, DISTRIBUTOR);
const { distributionId } = await d.createDistribution({
  assetToken: BUILDING_TOKEN, payoutToken: USDC_SAC, amount: 25_000_0000000n,
  claimWindowSecs: 180n * 86400n, memo: "Rent Q3 2026",
});
await new RevenueDistributor(holderAdapter, DISTRIBUTOR).claim(distributionId);
```

***

## Secondary liquidity: `rfq-market`

A single farm, invoice or building token will never have AMM depth. The RFQ market
matches a seller with specific buyers instead:

1. `post_intent`: the seller escrows `amount` of the RWA token and sets the payment
   token, a floor price and an expiry.
2. `submit_quote`: buyers post firm quotes. The quoted price is escrowed, so every quote
   is fundable.
3. `accept_quote`: the seller picks one. The asset goes to the buyer and the price, less
   an optional protocol fee (≤ 5%), goes to the seller, **atomically**.
4. `withdraw_quote` refunds losing quotes. `cancel_intent` refunds an unfilled intent.
   Both stay available while the market is paused.

If the token has an identity verifier, the market contract's address must be verified
on it to hold the escrow. The buyer is checked as normal.

```ts theme={null}
import { RfqMarket } from "@ankarachain/sdk";

const seller = new RfqMarket(sellerAdapter, RFQ);
const { intentId } = await seller.postIntent({ assetToken: FARM, amount: 400n, quoteToken: USDC_SAC, expiresAt: inOneWeek });
await new RfqMarket(buyerAdapter, RFQ).submitQuote(intentId, 15_000_0000000n, inOneDay);
const [best] = (await seller.getQuotes(intentId)).sort((a, b) => Number(b.totalPrice - a.totalPrice));
await seller.acceptQuote(intentId, best.id);
```

***

## Land & property titles: disputes, liens, chain of custody

`farmland-nft` and `real-estate-nft` gain:

| Function | Access |
| - | - |
| `set_dispute(token_id, Option<reference>)` / `set_lien(token_id, Option<reference>)` | Manager |
| `title_flags(token_id)` → `{ disputed, dispute_ref, liened, lien_ref, updated_at }` | anyone |
| `append_custody(token_id, owner, reference, effective_at)` (append-only) | Manager |
| `custody_count(token_id)`, `custody_log(token_id, start, limit ≤ 50)` | anyone |

Owners in the custody log are free-form strings, because prior owners usually pre-date
the token. The flags are informational: they don't block transfers.

```ts theme={null}
const title = new AssetRegistry(adapter, FARMLAND_NFT, "farmland-nft");
await title.setLien(1, "Bank of Agriculture lien #88");
await title.appendCustody(1, "Musa Family Trust", "Deed of Assignment 2011/33", 1_300_000_000n);
console.log(await title.getTitleFlags(1), await title.getCustodyLog(1));
```

***

## Carbon credits: external registry reference

`RetirementRecord` now has an optional `external_registry_id`, which links a retirement
to an independent verification body's record (for example a Verra retirement serial).
Set it at retirement with `retire_with_registry_ref(...)`, or attach it once later with
`set_retirement_registry_ref(index, id)` (Manager, write-once).

```ts theme={null}
const carbon = new AssetRegistry(adapter, CARBON_TOKEN, "carbon-credit");
await carbon.retireWithRegistryRef(100n, "Acme Corp", "FY26 offset", "VCS-RET-2026-0042");
```

<Warning>
  `RetirementRecord` gained a field. Carbon tokens deployed before this change should be
  upgraded before new retirements are written. Existing retirement records don't carry the
  field.
</Warning>

***

## Coupon-bearing instruments

The design decision is recorded in
[`packages/contracts-stellar/design/coupon-instrument.md`](https://github.com/ankarachain/ankara-core/blob/main/packages/contracts-stellar/design/coupon-instrument.md).
In short: a new `bond-token` template, not an `invoice-token` extension, with coupons
paid through `revenue-distributor`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.