Smart contracts for msg, an on-chain messaging system for Antelope chains. Messages are actions on the msg contract; the contract stores no message content and instead authenticates the sender, validates the request, and notifies the channel's format contract and hook contracts, which validate content shape and gate access. Message history is read from an indexer that follows the action stream (greymass/msgindex).
| Contract | Role | Vaulta account | Jungle 4 account |
|---|---|---|---|
msg |
Channels, inboxes, and message actions | msg |
msg.gm |
allowlist |
Hook: only approved accounts may post | allow.msg |
allowlist.gm |
blocklist |
Hook: banned accounts may not post | block.msg |
blocklist.gm |
tokenreq |
Hook: posting requires a minimum token balance | tokenreq.msg |
tokengate.gm |
announce |
Hook: only owner-approved senders may post; reactions stay open | announce.msg |
announce.gm |
chat |
Format: plain UTF-8 text with a length cap | chat.msg |
chat.gm |
forum |
Format: packed {title, body, tags} |
forum.msg |
forum.gm |
blog |
Format: packed post with slug, tags, and categories | blog.msg |
blog.gm |
A channel is a row in the msg contract's channels table: an id, an owner, an optional format contract, and a list of hook contracts. Anyone can send to a channel unless a hook says otherwise. On every send, edit, del, reply, react, and unreact, the msg contract calls require_recipient() for the format and each hook. A hook rejects the action by asserting inside its notification handler; hooks are AND-gated, so every hook must accept. A format contract validates that the content matches its shape.
Hooks and formats read the msg contract's tables directly, at an account name baked into the WASM at compile time. A build for one chain is wrong on another chain.
Docker is the only requirement. Every build runs inside a container holding the Antelope CDT release pinned by CDT_VERSION in .env, installed from the official release package on a base image pinned by digest, so a rebuild of a tag reproduces the deployed bytes. Hosts on arm64, including Apple Silicon, run the image emulated, which is slower and produces identical output. Account names and node URLs also come from .env.
make docker/image # build the pinned CDT toolchain image
make build # production build of every contract
make build/<name>/production # one contract
make build/<name>/debug # debug build with the reset action, used by tests
make build/<name>/testnet # debug build baking the Jungle 4 msg account
Artifacts land in contracts/<path>/build/.
Tests run with Bun against in-process WASM through @vaulta/vert.
make test # debug build, codegen, all tests
make test/msg # one group (also test/hooks, test/formats)
make check # clang-format and ESLint
make testnet/<name> deploys a debug build to Jungle 4 and make mainnet/<name> deploys a production build to Vaulta, both through cleos on the host with an unlocked wallet. The mainnet target runs scripts/predeploy.sh first, which refuses debug or testnet artifacts, a dirty tree, or an untagged commit, and prints the local hash beside the on-chain one. Deploy msg before hooks and formats, one contract per invocation.