# Tips on feed posts

A reader can tip a post's author a little MON, and the post shows what it has earned. A tip is an ordinary transfer
on Monad testnet from the reader's Orb Wallet to the author's. Orb never holds the money and takes nothing from it.
These are testnet tokens with no promised value; the feature is a way to see attention turn into something
directly, on a chain where a plain transfer needs about 0.002 MON of gas and is confirmed within a block or two.

Tips are opt-in. An author who has not switched them on cannot be tipped.

## How it works

1. **The author opts in.** On their own profile in the feed, a switch reads **Tips**. It needs an Orb Wallet, because
   tips arrive there; without one the switch explains what to set up first.
2. **The reader tips.** A post whose author accepts tips shows a **Tip** button to everyone else. It offers 0.01,
   0.05 or 0.1 MON. The reader's Orb Wallet signs a plain transfer to the author's Orb Wallet, with the reviewed
   signing flow Orb uses for its other wallet actions.
3. **Orb counts it once the chain confirms it.** The browser sends only the transaction hash. The server reads the
   transfer back from Monad and checks it before the post's counter moves. If counting fails after the money was
   sent, the reader is shown the transfer and a button to count it again.

## What the server checks

A transfer counts as a tip only when all of these are true:

- it succeeded, on Monad testnet (chain id 10143);
- it was sent from the Orb Wallet bound to the tipper's account, not from another wallet;
- it went to the Orb Wallet bound to the post author's account, who has tips switched on;
- it carries no call data: a tip is a transfer, not a contract call;
- the amount is between 0.001 MON and 100 MON;
- the transaction hash has not been counted before, and the post is public and not the tipper's own.

Sending the same hash again changes nothing. A transfer the chain has not mined yet is waited for briefly and then
reported as not confirmed, so a request alone can never raise a counter. Recording is rate limited per account.

## What a post and a profile show

A post shows how many tips it has and the total in MON. An author's profile shows the total they have received.
Who tipped is not shown in the interface; the transfers themselves are public on the chain, as every transfer is.

## What it does not do

- **No custody, no fee, no refund.** Orb is not a party to the transfer. A tip cannot be taken back by Orb.
- **No subscriptions or paywalls.** A tip is a single transfer.
- **It does not stop other transfers.** Anyone can send MON to an author's wallet at any time; only transfers sent
  through a post, and confirmed as above, are counted on it.
- **It does not give MON a value.** These are testnet tokens. Nothing here is an offer, a return or advice.
- **Amounts are public** on the chain like every transfer. Opting out hides the button and stops new tips from being
  counted; tips already counted stay on the post.

## Data

Two tables (migration `0055_orb_feed_tips.sql`): `orb_tip_settings` (who accepts tips) and `orb_feed_tips` (one row
per counted transfer: the hash, the post, both accounts and wallets, the exact amount in wei, the block). The amount
is also kept in millionths of a MON so a page of totals can be summed without overflowing a 64-bit integer.

## Tests

`npm run tips:test` runs the verification against a local EVM (chain id 10143) and a real database: opt-in, a real
tip counted from the chain, the same hash twice, a hash claimed by someone else, a transfer to the wrong wallet or
from the wrong wallet, dust, call data, an amount above the ceiling, a hash the chain has never seen, a failed
transfer, a transfer on another network, and opting out. It then drives the real feed components in a browser, with the
wallet and the server as fixtures: the amount choice, the exact transfer the wallet is asked to sign, a wallet that is not
the account's, a withdrawn author, a cancelled signature, and a failed count retried without a second transfer.
