QA gate rules
Every automated rule a contract deploy must satisfy before it can be Allowed into a block. Source: protocol crate boing-qa as of 26 August 2026. List contents (hashes, patterns, terms) are governance-mutable; rule IDs and matching logic are code.
Pre-flight: QA check · Live queue: QA transparency · Design spec: QUALITY-ASSURANCE-NETWORK.md
Loading QA gate rules…
Live public testnet vs intended policy
On 26 August 2026, boing_getQaRegistry at the public testnet RPC returned empty blocklist, scam_patterns, always_review_categories, and content_blocklist, with max bytecode 32,768 bytes. The intended public-testnet policy merges 132 English terms into the content blocklist. Those terms do not reject until the live registry contains them. Always trust the RPC you submit to.
Outcomes
| Outcome | RPC | Meaning |
|---|---|---|
| Allow | submit succeeds | Eligible for inclusion in a block. |
| Reject | -32050 | Never enters a block. Response includes rule_id and message. |
| Unsure | -32051 | Referred to the community QA pool. Not auto-included. |
Evaluation order
First match wins in check_contract_deploy_full_with_metadata.
- METADATA_TOO_LONG — name > 256 or symbol > 32 UTF-8 bytes
- Empty bytecode → MALFORMED_BYTECODE
- Init marker 0xFD with no body → MALFORMED_BYTECODE
- MAX_BYTECODE_SIZE (default 32,768)
- INVALID_OPCODE or MALFORMED_BYTECODE on the stream after optional 0xFD
- BLOCKLIST_MATCH — BLAKE3 of the full payload
- PURPOSE_DECLARATION_INVALID — non-empty purpose not in the valid set
- SCAM_PATTERN_MATCH — contiguous byte sequence
- CONTENT_POLICY_VIOLATION — name/symbol vs content_blocklist
- Always-review category → Unsure
- other with description_hash shorter than 4 bytes → Unsure
- Allow
Hard rules (Reject)
Necessary for Allow, not always sufficient — Unsure can still fire after these pass.
| ID | rule_id | Rule | If it fails |
|---|---|---|---|
| R1 | MALFORMED_BYTECODE | Bytecode must not be empty. bytecode.len() == 0 → “Bytecode must not be empty”. | Reject |
| R2 | MALFORMED_BYTECODE | Init-code prefix must have a body. Leading 0xFD (CONTRACT_DEPLOY_INIT_CODE_MARKER) with no following bytes is malformed. Opcode checks apply to bytes after the marker. | Reject |
| R3 | MAX_BYTECODE_SIZE | Bytecode size cap. Full payload (including optional 0xFD) must be ≤ registry max. Default 32,768 bytes (32 KiB). | Reject |
| R4 | INVALID_OPCODE | Opcode whitelist. Every instruction byte must be in the Boing VM table. PUSH immediates are data, not opcodes. | Reject |
| R5 | MALFORMED_BYTECODE | Well-formed instruction stream. PUSH1–PUSH32 must consume exactly 1–32 following bytes; the scan must end at len. Jump-target alignment is not checked at QA time. | Reject |
| R6 | BLOCKLIST_MATCH | Bytecode hash blocklist. BLAKE3-256 of the full payload must not match any registry.blocklist hash. Default list is empty. | Reject |
| R7 | PURPOSE_DECLARATION_INVALID | Purpose category when provided. If purpose is present and non-empty, it must be a valid category (case-insensitive). Missing purpose is allowed. | Reject |
| R8 | SCAM_PATTERN_MATCH | Scam byte patterns. Bytecode must not contain any registry.scam_patterns sequence as a contiguous window. Default list is empty. | Reject |
| R9 | METADATA_TOO_LONG | Metadata length. asset_name ≤ 256 UTF-8 bytes; asset_symbol ≤ 32 UTF-8 bytes (when those fields are sent). | Reject |
| R10 | CONTENT_POLICY_VIOLATION | Content policy on name / symbol. asset_name or asset_symbol must not match a content_blocklist term (see matching rules). Inert when the live list is empty. | Reject |
Valid purpose categories
Matching is case-insensitive. Missing purpose is allowed. Meme, community, and entertainment are first-class — “no traditional utility” is not a reject.
- dApp / dapp
- token
- NFT / nft
- meme
- community
- entertainment
- tooling
- other
Allowed opcodes
Any other opcode byte is INVALID_OPCODE. PUSH immediates are not whitelist-checked.
| Byte | Name |
|---|---|
| 0x00 | STOP |
| 0x01 | ADD |
| 0x02 | SUB |
| 0x03 | MUL |
| 0x04 | DIV |
| 0x06 | MOD |
| 0x08 | ADDMOD |
| 0x09 | MULMOD |
| 0x10 | LT |
| 0x11 | GT |
| 0x14 | EQ |
| 0x15 | ISZERO |
| 0x16 | AND |
| 0x17 | OR |
| 0x18 | XOR |
| 0x19 | NOT |
| 0x1B | SHL |
| 0x1C | SHR |
| 0x1D | SAR |
| 0x30 | ADDRESS |
| 0x33 | CALLER |
| 0x40 | BLOCKHEIGHT |
| 0x41 | TIMESTAMP |
| 0x51 | MLOAD |
| 0x52 | MSTORE |
| 0x54 | SLOAD |
| 0x55 | SSTORE |
| 0x56 | JUMP |
| 0x57 | JUMPI |
| 0x60–0x7F | PUSH1–PUSH32 |
| 0x80 | DUP1 |
| 0xA0–0xA4 | LOG0–LOG4 |
| 0xF1 | CALL |
| 0xF3 | RETURN |
| 0xF5 | CREATE2 |
Soft / policy rules (Unsure)
| ID | Rule | Outcome |
|---|---|---|
| U1 | Always-review category. If the trimmed, lowercased purpose is in registry.always_review_categories, the deploy goes to the pool. Default list is empty. | Unsure |
| U2 | other with almost no description. Purpose other plus description_hash shorter than 4 bytes (missing counts as 0) goes to the pool. other with ≥ 4-byte hash can Allow. | Unsure |
Content-policy matching
- Empty blocklist → skip. Names are trimmed and lowercased.
- Terms with spaces or punctuation: substring match (e.g. “kill yourself”).
- Alphanumeric terms of length ≥ 4: substring match (e.g. “shit” matches “ShitCoin”).
- Alphanumeric terms shorter than 4: whole-token match only (“ass” does not match “Classic”).
Content policy does not scan bytecode, purpose text, or off-chain URIs. It only sees deploy-time asset_name / asset_symbol.
Intended English content blocklist (132 terms)
a55hole, asshole, assholes, b1tch, badass, bastard, bastards, beaner, beaners, bestiality, bitch, bitches, bitchy, blowjob, bollocks, bukkake, bullshit, child porn, childporn, chink, chinks, clitoris, cocksucker, cocksuckers, cunt, cunts, dilf, dipshit, douche, douchebag, douchebags, dumbass, dyke, dykes, ejaculate, ejaculation, faggot, faggots, fagot, fck, fuck, fucked, fucker, fuckers, fuckface, fuckhead, fucking, fuckwit, fuk, fvck, gangbang, go die, gook, gooks, handjob, heil, hentai, hitler, jackass, kike, kikes, kill yourself, kys, masturbate, masturbation, mfucker, milf, motherfucker, motherfuckers, nazi, nazis, nigga, niggas, nigger, niggers, onlyfans, orgasm, paedophile, paedophilia, pedophile, pedophilia, penis, penises, phuck, porn, pornhub, porno, pornography, pussies, pussy, raghead, retard, retardation, retarded, rimjob, sandnigger, scrotum, sh1t, shit, shitbag, shitface, shithead, shits, shitshow, shitty, slut, sluts, slutty, spic, spics, swastika, testicle, testicles, towelhead, trannies, tranny, twat, twats, vagina, vaginas, vulva, wanker, wankers, wetback, wetbacks, whitepower, whore, whores, whoring, xvideos, xxx, zoophilia.
What is required for Allow
- Every applicable hard rule R1–R10 passes.
- Purpose is omitted, empty, or a valid category.
- Purpose is not in the always-review set.
- If purpose is other, description_hash is at least 4 bytes.
Not required: traditional utility, jump-target proofs, token/NFT ABI layout, off-chain websites, or vulgarity inside bytecode.
Community pool (Unsure)
Anyone with a 32-byte account may vote Allow, Reject, or Abstain (live public testnet has open voting). The deployer cannot vote on their own item. Counted votes are Allow+Reject; 2/3 of those decide after quorum. Default on the 7-day window expiry is reject. Pool voters should reject scams, phishing, rug-pulls, malware, impersonation, deceptive naming, Ponzi patterns, and spam — not memes or experimental work.
QA RPC error codes
| Code | Meaning |
|---|---|
-32050 | Rejected by protocol QA (rule_id + message). |
-32051 | Unsure — referred to the governance QA pool (pending tx_hash). |
-32052 | No pending pool item for that transaction hash. |
-32053 | Voter ineligible (not a member, deployer conflict, or stake). |
-32054 | QA pool disabled (no admins / zero capacity). |
-32055 | Global pool capacity reached. |
-32056 | Per-deployer pending cap reached. |
-32057 | Operator RPC auth required (X-Boing-Operator). |