This file provides guidance to coding agents (Claude Code, and others via @AGENT.md) when working
with code in this repository.
Cronos is an EVM-compatible Cosmos SDK blockchain (the Crypto.org EVM chain). It is built on top of
Ethermint (EVM execution, imported from github.com/crypto-org-chain/ethermint, a fork) and the
Cosmos SDK, with CometBFT consensus and IBC-go. The daemon binary is cronosd.
make build # -> build/cronosd (respects NETWORK=mainnet|testnet, LEDGER_ENABLED)
make install # go install ./cmd/cronosd
make test # go unit tests, ALWAYS with -tags=objstore
make lint # golangci-lint (v2.1.6) + go mod verify
make lint-fix # auto-fix Go lint issues
make lint-py # flake8 for integration_tests python
make lint-py-fix # isort + black
make vulncheck # govulncheck ./... over the resolved module graphThe objstore build tag is required for tests. Running go test ./... without it will fail to
compile parts of the store layer. Use:
go test -tags=objstore ./app/... # a package
go test -tags=objstore -run TestName ./x/cronos/keeper # a single test
make test-race-mempool # mempool concurrency tests (needs -race)Default build tags: netgo objstore pebbledb mainnet nativebyteorder (+ ledger if gcc present).
COSMOS_BUILD_OPTIONS=rocksdb make install builds with the RocksDB backend (needs cgo + rocksdb libs);
a bare go build/ls in this repo may print harmless "Package rocksdb was not found" pkg-config
warnings from cgo probing — ignore them.
Building and CI rely heavily on Nix. gomod2nix.toml mirrors go.mod — after changing Go deps run
gomod2nix generate to regenerate it, or CI will fail.
nix develop # default dev shell (go, gomod2nix, nixfmt)
nix develop .#rocksdb # adds rocksdb libs for the rocksdb backend
nix develop .#full # adds the integration-test environment (test-env)Integration tests live in integration_tests/ and drive real cronosd nodes with pystarport.
They are orchestrated with Nix, not plain pytest.
make run-integration-tests # runs everything via scripts/run-integration-tests
TESTS_TO_RUN=upgrade make run-integration-tests # run only tests with a given pytest marker
# Manual, inside the nix shell:
nix-shell ./integration_tests/shell.nix
cd integration_tests && pytest -k test_basic # select by name/marker
pytest -k cronos # some tests run on both geth and cronos; filter by platformTESTS_TO_RUN maps to pytest markers (see integration_tests/pytest.ini). Node topologies are defined
by jsonnet configs in integration_tests/configs/.
Proto sources are in proto/{cronos,e2ee,memiavl}. Generation runs in a Docker proto-builder image:
make proto-gen # regenerate Go from .proto
make proto-lint # buf lint
make proto-format # clang-format
make proto-check-breakingmemiavl protos are checked for breaking changes against the external cronos-store repo.
CronosApp composes standard Cosmos SDK modules + Ethermint's x/evm and x/feemarket + the two
custom modules below. Read app/app.go to find keeper wiring, store keys, ante handlers, and upgrade
handler registration. Related app-level files:
app/upgrades.go— chain upgrade handlers (each network upgrade adds a handler here).app/forks.go,app/unblockable.go,app/block_address.go— block-level address blocking / forks.app/mempool/— a custom app-side mempool with lock-free admission (preverify.go), gossip, and encode/decode caches. Concurrency-sensitive; changes here must passmake test-race-mempool.
Cronos does not use the vanilla IAVL store for production. Two swappable subsystems, both wired in
app/app.go and selected by app options / CLI flags:
- memiavl — an optimized IAVL replacement (from
github.com/crypto-org-chain/cronos-store). Set up viamemiavlstore.SetupMemIAVL(...). Note: memiavl's in-memory cache is only enabled when neither block-stm nor optimistic execution is active (it is not concurrency-safe). - versiondb — a separate historical-state store fed by a
StreamingService(enabled withversiondb.enable). When on, a custom store loader (app/storeloader.go) constrains the loaded IAVL version to not exceed the versiondb version to avoid gaps. Managed viacronosdsubcommands incmd/cronosd/cmd/versiondb.go. DB opening / migration lives incmd/cronosd/opendb/andcmd/cronosd/dbmigrate/.
The core custom module. It "glues IBC, gravity bridge, and Ethermint together through hooks and token
mapping" (see x/cronos/spec/). Key responsibilities:
- Token mapping: converts IBC / gravity assets to CRC20 (ERC20) contracts on arrival, and handles
the 8↔18 decimal conversion for the CRO gas token. State layout is in
x/cronos/spec/02_state.md. - EVM hooks (
keeper/evm_hooks.go):LogProcessEvmHooktranslates specific contract event logs into native Cosmos module calls (e.g. sending tokens over IBC from a contract). - Stateful precompiles (
keeper/precompiles/):bank,ica,relayerprecompiled contracts that let EVM contracts call native modules. They useExtStateDB.ExecuteNativeActionto run SDK logic inside EVM execution.keeper/permissions.gogates who can call what. - Middleware (
middleware/) and IBC callback wiring (keeper/ibc.go).
Lets users register encryption public keys on-chain and exchange encrypted messages. Includes a keyring
integration (x/e2ee/keyring/) and autocli command wiring.
main.go → cmd/root.go builds the root command. Custom subcommands beyond the standard SDK set:
versiondb, migrate_db/database/patch_db (DB maintenance), under cmd/cronosd/cmd/.
Address bech32 prefixes are network-dependent (cmd/cronosd/config/prefix_{mainnet,testnet}.go),
selected by the NETWORK build tag.
Most of Cronos's attack surface is not in this repo — it lives in a handful of large upstream
dependencies, and for the most important ones Cronos runs crypto-org-chain forks pinned via
replace directives in go.mod, not the upstream versions. When reviewing code, auditing behavior,
or scanning for vulnerabilities, you MUST read the forked source (the replace target), not the
upstream project on GitHub — the fork can and does differ. Resolve the actual code with
go list -m -f '{{.Dir}}' <module> or read it under vendor/.
| Concern | Module (import path) | Actual source after replace |
Pinned version |
|---|---|---|---|
| Cosmos SDK (app framework, auth/bank/gov/staking, ante handlers, baseapp) | github.com/cosmos/cosmos-sdk |
github.com/crypto-org-chain/cosmos-sdk (fork) |
v0.54.4-...20260805154329-743fc8dc9dbc |
EVM execution & JSON-RPC (x/evm, x/feemarket, statedb) |
github.com/evmos/ethermint |
github.com/crypto-org-chain/ethermint (fork) |
v0.22.1-...20260702171011-a639532d9759 |
| Consensus / networking / mempool | github.com/cometbft/cometbft |
github.com/crypto-org-chain/cometbft (fork) |
v0.0.0-...20260729145603-14b7b93046e3 |
| Custom store: memiavl, versiondb, store | github.com/crypto-org-chain/cronos-store/{memiavl,versiondb,store} |
crypto-org-chain/cronos-store (fork target pins) |
...20260806235227-c224b839a4b1 |
| EVM crypto / core types | github.com/ethereum/go-ethereum |
github.com/crypto-org-chain/go-ethereum (fork) |
v1.10.20-...20260521015249 |
| IBC | github.com/cosmos/ibc-go/v11 |
upstream | v11.1.0 |
Security-review scope, in priority order:
x/cronos(this repo) — precompiles, EVM hooks, token mapping, permissions: the bespoke, highest-risk custom logic (see architecture section).- cosmos-sdk fork — ante handlers, baseapp CheckTx/mempool path, module keepers. The fork diverges from upstream (e.g. mempool insert-before-commit, staking end-block changes — see CHANGELOG); audit the fork's diff, not upstream.
- ethermint fork — EVM state transition, gas/fee logic (EIP-1559 floor-data-gas, EIP-7702), signer pre-verification. Consensus- and value-critical.
- cronos-store fork (memiavl/versiondb) — state commitment and historical state; correctness bugs here corrupt state or break determinism.
- cometbft, go-ethereum, ibc-go — larger blast radius but less Cronos-specific customization.
When checking whether a known CVE applies, compare against the pinned fork commit, not the nominal
upstream version string — the v0.50.6/v1.10.20 prefixes are base tags; the real code is the pseudo-
version commit hash. make vulncheck (govulncheck ./...) scans the resolved module graph.
Style is enforced by make lint (golangci-lint v2.1.6, config in .golangci.yml) — treat that
config as the source of truth and run make lint-fix before committing rather than hand-formatting.
The rules below are the ones the linters actually enforce here:
- Formatting:
gofumpt(withextra-rules) +gci. Stricter thangofmt; let the tool format. - Import grouping (
gci, custom order). Four blocks, in this exact order, each separated by a blank line: (1) standard library; (2) third-party — this includesgithub.com/crypto-org-chain/...,evmos/ethermint,ibc-go, andethereum/go-ethereum; (3)cosmossdk.io/*; (4)github.com/cosmos/cosmos-sdk/*. Seex/cronos/keeper/keeper.gofor the canonical layout. - Errors — sentinel + wrap. Register module errors in
types/errors.gowitherrors.Register(ModuleName, code, msg), wherecodecomes from a privateiotablock (code 1 is reserved for internal errors). Wrap at call sites witherrorsmod.Wrap/Wrapf, aliasingcosmossdk.io/errorsaserrorsmod.errorlintis on: wrap dynamic errors with%wand compare witherrors.Is/errors.As— never==or a type assertion on an error. - Doc comments on exported identifiers.
revive'sexportedrule runs at error severity, so exported funcs/consts need a doc comment (bare exported types without any comment are tolerated). - No repeated string literals — extract a
const(goconst). - Tests: table-driven with
testifysuites. Use asuite.Suite(e.g.CronosTestSuite) and atestCasesslice of anonymous structs carrying anameand amalleate func()plus expected outcomes. Test/setup helpers must callt.Helper()(thelper). - Other enforced linters:
misspell(US spelling),unconvert(no redundant conversions),nakedret(avoid naked returns),ineffassign,copyloopvar, andnolintlint— every//nolintmust be used and target a specific linter (allow-unused: false).gosecruns but G101/G107/G404 (math/rand) and G115 (integer-overflow conversion) are intentionally excluded.
- CHANGELOG.md is mandatory for non-trivial PRs. Add an entry under
## UNRELEASEDin the correct section (Improvements,Bug fixes,Chores) formatted as* [#PR](https://github.com/crypto-org-chain/cronos/pull/PR) description. Entries describe the net user-facing effect, not the code change. - Commit / PR messages use conventional-commit prefixes:
feat,fix,chore, often scoped (fix(ante):,feat(app):,fix(versiondb):). - ABCI / consensus-affecting changes generally must be gated behind an upgrade handler in
app/upgrades.go— do not change deterministic behavior unconditionally. - Ethermint is a pinned fork; bumping it uses
scripts/go-update-ethermint.sh. After any Go dep change, regenerategomod2nix.toml.
The canonical written style reference for this repo is the Uber Go Style Guide
(https://github.com/uber-go/guide/blob/master/style.md). Treat Go Code Review Comments
(https://go.dev/wiki/CodeReviewComments) as the assumed baseline, since much of it is already encoded in
the linters (e.g. revive's exported-doc-comment rule). .golangci.yml remains the actual source of
truth for enforcement; the Uber guide just explains the intent behind those rules.