Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 43 additions & 4 deletions REVIEW.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Review guidelines for AI agents

Repo-specific conventions for automated PR review (Codex, Cursor, Claude, and
any other AI reviewer). The two patterns below look like bugs in isolation
but are normal consequences of how Sei cuts releases and rolls out upgrades.
Do not report them as findings unless a concrete additional signal (see the
caveats under each) makes them real.
any other AI reviewer). The patterns below look like bugs in isolation
but are normal consequences of how Sei cuts releases, rolls out upgrades, and
processes transactions. Do not report them as findings unless a concrete
additional signal (see the caveats under each) makes them real.

## 1. Referencing a not-yet-created release tag is expected

Expand Down Expand Up @@ -61,3 +61,42 @@ If you believe a version gate is genuinely broken on its own logic (wrong
comparison direction, wrong constant, wrong context field), still report
it — this guidance only rules out the "the tag doesn't exist yet" and
"old code might run against post-upgrade state" false positives.

## 3. Some Cosmos transactions are gasless: don't require `--fees` on them

Do not flag a `seid tx` invocation (in tests, scripts, or docs) as broken for
omitting `--fees` before checking whether the message type is gasless. Sei's
ante handlers classify certain transactions as gasless and skip minimum-fee
validation entirely for them, so `minimum-gas-prices`-based fee arithmetic
(`ceil(min-gas-price × gas-limit)`) does not apply.

The classification lives in `IsTxGasless` (`app/antedecorators/gasless.go`)
and is consumed by both the CheckTx and DeliverTx ante paths
(`app/ante/cosmos_checktx.go`, `app/ante/cosmos_delivertx.go`), where
`CheckAndChargeFees` returns before any fee comparison when the transaction

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] CheckAndChargeFees exists only on the CheckTx path (app/ante/cosmos_checktx.go:346, called at line 123 with isGasless). DeliverTx calls ChargeFees (app/ante/cosmos_delivertx.go:80, called at line 73), which takes no isGasless argument and performs no minGasPrices comparison at all — it unconditionally deducts whatever fee coins the tx declared. So IsTxGasless is indeed consulted by both paths (cosmos_checktx.go:96, cosmos_delivertx.go:42), but only for gas metering on the DeliverTx side; the early return described here is CheckTx-only.

Suggested rewording: IsTxGasless is consulted by both ante paths, and on CheckTx CheckAndChargeFees (app/ante/cosmos_checktx.go) returns before any fee comparison when the tx is gasless; DeliverTx never performs a minimum-fee check to begin with. Worth also noting the non-legacy chain skips the wrapped DeductFeeDecorator via GaslessDecorator (app/ante.go:80), since that — not CheckAndChargeFees — is where the skip happens there.

is gasless. As of this writing the gasless set is:

- a single-message `MsgAssociate` (`seid tx evm native-associate`) whose
sender is **not yet associated** — the common case in bootstrap helpers and
association tests; the sender only needs a nonzero balance (at least 1 wei),
not a fee, and
- `MsgAggregateExchangeRateVote` from a validator without a vote in the
current window.

Consequences for review:
- A fee-less `native-associate` for a fresh (unassociated) account is
correct. Do not report "insufficient fees at CheckTx" for it, and do not
infer breakage from sibling commands that do pass `--fees` (e.g.
`bank send`, `associate-contract-address`) — those message types are not
gasless, so the asymmetry is intentional.
- Best-effort re-association of an already-associated account is not gasless
and its CheckTx would reject, but helpers written as try/catch plus a
poll for `associated == true` (e.g. `associateKey` in
`contracts/test/lib.js`) don't need the transaction to land in that case.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] associateKey (contracts/test/lib.js:306) runs seid tx evm associate-address, which does not build a MsgAssociate at all: CmdAssociateAddress (x/evm/client/cli/tx.go:78) signs an empty hash and POSTs a sei_associate JSON-RPC request, producing an EVM AssociateTx (MsgEVMTransaction with IsAssociateTx() true, handled in x/evm/ante/preprocess.go / app/ante/evm_checktx.go). Only native-associate produces the MsgAssociate that IsTxGasless classifies.

Citing it in this section conflates two independent association paths with different fee rules, and risks suppressing a genuine finding about the EVM path. Either drop the example or move it to its own note that says explicitly it is the EVM AssociateTx path and why fees don't apply there.


This becomes a real finding only when the diff makes a **non**-gasless
message's invocation fee-less, or when a test strictly requires a gasless-set
transaction to land for a sender that is already associated (or already voted)
at the time of broadcast — then the fee path does apply and the transaction is
rejected. When in doubt, check `IsTxGasless` for the authoritative set rather
than reasoning from `minimum-gas-prices` alone.
Loading