Skip to content

v2.14.0 — Help builders only: spam-shaped samples removed, etiquette rules tightened, operator defences added

Latest

Choose a tag to compare

@paulgnz paulgnz released this 25 Oct 10:27
ea5ddf9

Project-wide "help builders only" review. Four independent reviewers read all 31 modules and the scripts with one question: does anything here help an agent attack, drain, spam, impersonate, or extract from the network or its users, rather than build on it? The policy layer (v2.11.0) was already pointed the right way and the v2.7.0 contract fixes held, but most code samples pre-dated the Network Etiquette rules and contradicted them on the same page. MINOR bump: substantial corrections across 24 files.

Policy

  • safety-guidelines.md — rule 3 is now a fixed number, not a default with a human-set override: 6 writes/min/account, raised only with an own node or paid plan, a written reason, and a hard ceiling of 60/min per operator; a bot that fires on every tick does not qualify at any number. Rule 6 says agents must decline liquidation, sniping, stop-loss-hunting, and arb bots, and must not offer a "slower", "scan off-chain, fire on-chain", or multi-account variant. Rule 7 bans whole-table re-reads for change detection. New rules 8–11: no account fleets or farming (faucets, airdrops, votes, anti-snipe windows, per-account caps); no impersonation of tokens, accounts, or people; testnet before mainnet for anything that moves value; rate limits, cooldowns, CORS allow-lists, and 403s are the operator's answer and are never routed around.
  • SKILL.md — policy blockquote restated with the new rules and the sentence "This skill helps builders; it does not help anyone attack, drain, spam, or extract from the network or its users." Routing table now sends anyone writing a bot, poller, keeper, cron, or signing script to safety-guidelines first, and surfaces rpc-queries' Endpoint Etiquette. New footer sections "Who this skill is for" and "Reporting problems with this skill" (GitHub issues only; there is no email).

Removed: content that taught the patterns we are fighting

  • simpledex.md — three statements that memo-based swaps bypass the 1-second cooldown, and the error-table advice "use memo-based swap" when the cooldown fires. The cooldown is now described as the floor for every swap path; chaining memos to skirt it is named as the spam this skill declines. Anti-snipe table kept, with "splitting a buy across transactions or accounts to beat the cap is sniping; agents must decline." graduate gets "do not run a poller that races to graduate tokens." The file now links the etiquette section (it had no link before).
  • troubleshooting.md, testing-debugging.md, backend-patterns.md — the "duplicate transaction" fix was to add nonce: Date.now() or "unique data"; that is the scanliq technique. Replaced with: a duplicate means the first push was accepted or in flight; do not resend; never add a nonce.
  • defi-trading.md — "Arbitrage Considerations" became "Why arbitrage loops are out of scope" (fee math kept as the reason; the "where to find price gaps" bullets removed). Grid bot and market maker fired one transaction per price level via Promise.all; both now build one actions[] and submit a single transaction, and the market maker gates requotes on minRequoteMs (≥10 s, 20 s recommended) and a mid-price delta. Contract rate-limit sample went from 10 orders per block to 6 per minute. Market-buy price sentinel corrected to the uint64 value metalx-dex documents.
  • metalx-dex.md — process / processsltp now say: called by the matching engine; at most one process in your own order transaction; never on a schedule, in a loop, or against other users' orders.
  • staking-governance.md — "Enterprise BOT runs 1M+ transactions daily" marketing line replaced; a paid plan raises your quota, not the write-budget rules.
  • loan-protocol.md — the one remaining sentence confirming liquidate is callable by ordinary accounts dropped; the whitelist point stands without it.

Fixed: sample code whose numbers contradicted the rules

  • backend-patterns.md — RateLimiter(10, 1000) / MAX_TPS=10 (600/min) → RateLimiter(6, 60_000) with a one-in-flight semaphore, MAX_TX_PER_MINUTE=6, and a config loader that refuses higher values without RATE_OVERRIDE_REASON and refuses above 60 outright. Minute cron that pushed up to 100 resolve writes now runs through the limiter with a mutex, remembers failed ids, and only pushes rows the read confirms are due. Batch mint spacing 1 s → 10 s. updateauth/linkauth signed @active, not @owner; the service and mint samples use linked pay/minter/resolve permissions instead of active. A2A_SIGNING_KEY=PVT_K1_… removed from the .env template. New paragraph on what an unattended host does with a locked keystore.
  • real-time-events.md, rpc-queries.md, payment-patterns.md — polling tables unified to rule 7 (≥3 s latency-sensitive, ≥10 s otherwise, 30–60 s background); "1–2 seconds is fine" deleted. while(true) whole-table diff at 5 s with limit: 1000 → cursor-keyed bounded query at 10 s with stop(), 403 stop, 429/503 backoff. ActionPoller and payment watcher 3 s → 10 s with status checks. Confirmation loop 1 s → 2 s then 3 s. SHIP example no longer names an operator's port or subscribes to the full firehose. politeFetch and queryWithFallback back off on the same endpoint on 429 (honouring Retry-After) and rotate only on 5xx/connection failure. getAllRows capped with maxPages and an inter-page delay; Hyperion skip paging replaced with cursors. processdue stub (unauthenticated no-op write) now requires auth and fails when nothing is due; SubscriptionBot paced to the budget.
  • examples.md — public cleanup action now fails with "Nothing to clean up" so an idle call is never included in a block (a public no-op write is a fleet spam vector at the contract's expense). Resolver-bot sites carry "exactly one resolve per resolvable challenge, never race or retry in a loop."
  • smart-contracts.md — the flagship MyToken.deposit(account, amount) credited balances from an action argument with no transfer; it is now a transfer notify handler with firstReceiver, symbol, recipient, and positivity checks.
  • token-creation.md — airdrop script: 500 ms batches → 10 s, journal and verify each batch, exponential backoff, linked airdrop permission, undefined variables and a non-existent transact options argument fixed. Wrap/unwrap now maintain stats.supply, check max_supply, and store the full checksum256 instead of an 8-byte fold.
  • nfts-atomicassets.md — holder airdrop paged and tied to "Bulk Minting Safely", with "only to holders who opted in or collections you author." Pinata JWT moved out of browser code behind a server route.
  • accounts-permissions.md, troubleshooting.md, cli-reference.md — eleven routine updateauth/linkauth/deleteauth examples signed @owner now sign @active; owner is for recovery only. Private keys no longer appear on proton key:add / key:remove command lines anywhere; the prompted form is shown, and rotation sequences end with proton key:lock.

Added: defensive guidance that was missing

  • node-operation.md — net_api_plugin removed from the public API-node config (its /v1/net/connect|disconnect are unauthenticated) and the nginx proxy now returns 403 for /v1/(net|producer|db_size|test_control)/; the limit_req line finally has its limit_req_zone. New "Defending against abusive traffic" section: nodeos actor-blacklist / contract-blacklist / sender-bypass-whiteblacklist (coordinate across producing BPs), http-max-in-flight-requests, max-body-size, nginx limit_conn. Block-signing key example now shows the keosd form live and the plaintext form as a testnet-only comment.
  • hyperion-setup.md — same 403 block, p2p per-host limits on the public seed, and a "Defending against abusive traffic" section with Hyperion action blacklists.
  • examples.md, webauth-identity.md, nfts-atomicassets.md — "Rendering on-chain strings": every memo, name, avatar, and NFT attribute is attacker-controlled input; escape on output, allow-list image sources to https: and IPFS CIDs, never innerHTML. The webauth KYC example no longer gates on the verified flag the file itself says is not KYC.
  • agent-bootstrap.md — the Pinata prompt no longer offers "paste the key in chat"; Secrets is the only path, the agent is told to refuse a key sent in conversation and ask for rotation, and the operator deletes the secret after provisioning. All git checkout v2.10.0 pins and git pull on main replaced with the latest release tag.
  • scripts/agent-bootstrap.sh — clones and updates at SKILL_REF (default v2.14.0), never main; the skill is the signing host's instruction set and is pinned like the packages are.
  • scripts/validate-skill.sh — key and personal-reference checks now cover README, bootstrap docs, scripts, and install.sh. Five new checks: 10 policy blocks and the etiquette section present; 11 no email or mailto anywhere; 12 no spam-shaped sample code (nonce de-duplication, sub-second limiters, timer-driven signing, "add unique data", cooldown-bypass wording); 13 key and bind hygiene (curl | bash, key on a key:add command line, "encrypted keychain" claims, 0.0.0.0 HTTP/SHIP binds); 14 warning sweep for liquidation wording outside the allowed files and loops around account creation or faucet claims.
  • README.md — stale "Current release: v2.6.0" replaced; validator list updated to 15 checks. Stale PR_DESCRIPTION.md removed from the tree and ignored.

Reported upstream

  • The SimpleDEX cooldown gap (enforced on the swap action but not on transfer-memo swaps) is a contract-level issue, not just a documentation one; a note for the SimpleDEX maintainers was drafted alongside this release.