Skip to content

Releases: XPRNetwork/xpr-network-dev-skill

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

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.

v2.13.0 — XPR Agents: plugin id is now xpr-agents (openclaw 0.9.2 / sdk 0.5.3)

Choose a tag to compare

@paulgnz paulgnz released this 25 Oct 09:17
3be96ce

XPR Agents tooling caught up with the 0.9.x plugin line. Three days after v2.12.0 was verified against @xpr-agents/openclaw 0.8.7, upstream published 0.9.0–0.9.2 and @xpr-agents/sdk 0.5.3; 0.9.0 is a breaking configuration change that made the module's install instructions wrong on current OpenClaw. MINOR bump: substantial correction.

Changed

  • xpr-agents.md — the OpenClaw plugin id is now xpr-agents, not openclaw (0.9.0). OpenClaw 2026.9 added a core tool named openclaw; a plugin whose id matches a core tool is dropped from the tool registry, which hid all 89 tools. The install bullet now says plugins.allow: ["xpr-agents"], tools.alsoAllow: ["xpr-agents"] and openclaw plugins inspect xpr-agents --runtime --json, gives the 0.8.x → 0.9.x upgrade steps (uninstall, reinstall with --accept-capabilities, rename the config keys), and replaces the "OpenClaw 2026.9.x is not verified" caveat with the upstream verification on 2026.9.6.
  • xpr-agents.md — 0.9.1: xpr_register_agent and xpr_submit_feedback pay a configured registration/feedback fee automatically (0.8.x rejected those calls when a fee was configured). MAX_TRANSFER_AMOUNT counting buyram/stakexpr is attributed to 0.9.0 (0.8.8 was never published). XPR_RPC_ENDPOINT added to the env list.
  • xpr-agents.md — sdk 0.5.3 pagination and amount fixes noted (listAgents no longer repeats a row across pages, listJobsByClient/Agent honour the cursor, listServices takes a cursor, exact integer XPR quantities, A2AClient rejects non-http(s) endpoints); advice to pin >=0.5.3 when paginating.
  • scripts/agent-bootstrap.sh — pins bumped to @xpr-agents/openclaw 0.9.2 and @xpr-agents/sdk 0.5.3. @proton/js stays at 28.1.2: both packages still declare ^28.1.2, so 30.x would install a second copy.
  • agent-bootstrap.md — sdk version in the smoke-test comment bumped to 0.5.3.

Verified

  • Tool count (89), bundled skill count (13 in the manifest; a 14th blockart skill ships in the tarball but is deliberately not auto-loaded), env var names and the plugin manifest were checked against the installed 0.9.2 package; the 0.9.0–0.9.2 and 0.5.3 release commits in XPRNetwork/xpr-agents were read for the behavioural changes above.
  • All 21 hostnames referenced by the skill answered on 2026-10-25; scripts/validate-skill.sh passes all 10 checks.

v2.12.0 — XPR Agents module updated for sdk 0.5.2 / openclaw 0.8.7

Choose a tag to compare

@paulgnz paulgnz released this 16 Oct 00:24
b7d9f1f

XPR Agents module brought up to date. The module was last verified against @xpr-agents/sdk 0.2.7 / @xpr-agents/openclaw 0.5.4 (v2.6.0); npm is now at 0.5.2 / 0.8.7. Every action the module already documented still matches the live ABIs field for field, so nothing was wrong, but the escrow contract and the plugin had grown a great deal the module did not mention. Verified against the installed packages' type declarations, the four mainnet ABIs, and xpragents.com/llms.txt. MINOR bump: new reference content.

Added — xpr-agents.md

  • Beyond the happy path: re-deliver, revise (at most twice), timeout / accpttimeout / cancel, agentcancel (full refund), withdrawbid, milestones (addmilestone / submitmile / approvemile), direct hire.
  • Job messages: askclient / answer, limits, and the etiquette that matters (ask once, never deliver a placeholder to ask a question).
  • Services: fixed-price listings end to end: svcfee: deposit + listsvc in one transaction, buy:<id>[:notes], updatesvc / delistsvc / relistsvc / refundsvcfee, input forms (setsvcinput / svcinput), featured placement via boost:<id>, what sample_uri must be, and how to find the job a purchase created.
  • Reviews / validation / arbitration lifecycle actions: job_hash = job id string, review disputes, challenge, unstake / withdraw, activatearb / deactarb / unstakearb / withdrawarb / cancelunstk, and why the reference runner only accepts trusted arbitrators.
  • Stopping an agent: setstatus false plus runner shutdown, what inactive blocks, how money is never stranded, and why there is no unregister.
  • Tooling rewritten for openclaw 0.8.7 / sdk 0.5.2: 89 tools + 13 skills, the two ways to run an agent and the harness install path (openclaw plugins install, env.vars.XPR_ACCOUNT, tools.alsoAllow, inspect --runtime), every plugin env var with its default, confirmHighRisk, housekeeping mode, the owner-permission lockdown command, the SDK's four registries and A2AClient, and Shellbook (contract shellbook, 15 tools).

Changed

  • backend-patterns.md: createCliSession documents the maxTransferAmount cap; the install line distinguishes a Node process from an OpenClaw harness; the .env template lists the plugin's optional settings with defaults.
  • scripts/agent-bootstrap.sh pins @xpr-agents/openclaw 0.8.7 and @xpr-agents/sdk 0.5.2 (were 0.8.1 / 0.4.0); the validator now checks both packages resolve.
  • Tool count corrected from 75 to 89 in agent-bootstrap.md and README.md; index rows updated.
  • Also folded in from the xpr-agents maintainers' review of the same drift: the 10 XPR valfee: validation deposit (confirmed on chain), escrow caps (5 unfunded jobs per client, 20 milestones / 20 messages per job, 10 listings), the SDK 0.5.0 A2A signing change (audience + chainId in the digest, targetAccount / chainId required on A2AClient), reputation scaled by min(reviews, 5) / 5, ENABLE_MSIG_APPROVE, AGENT_MODE values and start.sh defaults, indexer endpoint shapes and the 100 req/min limit, and an explicit OpenClaw 2026.9.x is not verified note. The bootstrap pins @proton/js 28.1.2 to match the ^28 range both packages declare.

v2.11.0 — Liquidation how-to removed, Network Etiquette added

Choose a tag to compare

@paulgnz paulgnz released this 15 Oct 23:53
9a7aba8

Liquidation how-to removed and network-spam rules added. Autonomous bots built from this kind of material were observed on mainnet firing nonce-bumped liquidation-scan actions hundreds of times per second through fleets of executor accounts, and arbitrage loops writing step / tradelog actions on every tick. XPR Network has no fees, so this costs the sender nothing and every block producer, history node, and public API a great deal. MINOR bump: content removed and a new skill-wide policy.

Removed — liquidation how-to (loan-protocol.md, defi-trading.md)

  • loan-protocol.md: the Check Liquidatable Borrows scanner, the Execute Liquidation command, and the Liquidation Incentive figures are gone. What remains is the borrower-side fact: health factor below 1.0 can be liquidated, keep yours above it.
  • defi-trading.md: the perps Liquidation System contract sample is replaced by a stub saying it is out of scope; the perps.liquidation contract row and the Liquidation Bot service row are removed. The liquidation-price preview for position holders stays.
  • Index rows in SKILL.md and README.md no longer advertise liquidations.

Added — Network Etiquette (safety-guidelines.md, SKILL.md)

  • New section Network Etiquette: Do Not Spam the Chain: what spam looks like (nonce scanning, executor fleets, on-chain bookkeeping, tight retry loops, polling with actions) and seven rules for agents and bots: reads off-chain, no speculative writes, a default write budget of 6 transactions per minute per account with one in flight, exponential backoff on failure, one account per purpose, liquidation / sniping / MEV bots out of scope (decline and cite the section), and polling intervals for RPC.
  • SKILL.md gains a third skill-wide policy block summarising the above, next to the signing and AI-code policies.
  • Cross-references from every bot surface: Trading Bot Patterns and Arbitrage Considerations in defi-trading.md, the DEX Bot section in metalx-dex.md, Rate Limiting in backend-patterns.md, and the signing section in xpr-agents.md.

Changed — validator (scripts/validate-skill.sh)

  • New check 10 fails the build if liquidation how-to content (the scanner function, the liquidate, transfer memo, a liquidate action, or a scanliq-style action) reappears in any module.

v2.10.0 — NFT drop learnings: safe CLI scripting, bulk mint, rng callback safety

Choose a tag to compare

@paulgnz paulgnz released this 16 Oct 00:25
a1d455e

Learnings from an AtomicAssets drop on XPR Network: a proton-tsc claim contract using the rng oracle, a
full-size testnet rehearsal (3,333 assets, 2026-09-24/25), and the mainnet mint that followed (2026-09-25).
Tools: @proton/cli 0.1.98 (source checked against 0.1.99), proton-tsc 0.3.58, @proton/vert 0.3.24,
@proton/web-sdk / @proton/link 5.1.0. MINOR bump: new reference content and some corrected notes. The
measured numbers come from one collection, so treat them as rough.

Added — contracts (smart-contracts.md, testing-debugging.md, troubleshooting.md)

  • Known SDK bug: getCodeHash() in proton-tsc 0.3.58 / as-chain declares get_code_hash with 3 params, but the node intrinsic takes 4. setcode fails with wrong type for imported function get_code_hash. Added a workaround that ran on testnet and mainnet: an @external 4-param import, plus the exact 43-byte packed layout (varuint32 struct_version | u64 code_sequence | checksum256 code_hash | u8 vm_type | u8 vm_version, no account field; hash at bytes 9..40). The helper fails safe on any unexpected length or version.
  • The local test VM does not check intrinsic signatures: vert 0.3.24 implements the same 3-param get_code_hash, and 15/15 tests passed with the broken import. Added "deploy to testnet early".
  • Troubleshooting entries for the get_code_hash error and for actions that report "status": "executed" on an account with an ABI but no code.
  • Chain vs vert auth wording: a node says missing authority of X, vert says missing required authority X. Fixed the vert test example, which used the chain wording and would not match.
  • Testnet checklist: oracle callbacks, a claimer with contract code, and "rehearse at full size".

Added — RNG (oracles-randomness.md)

  • The rng oracle is live on testnet. The callback arrived in about 1–3 s, as a separate transaction.
  • Best practices: use a never-reused request id as assoc_id and ignore stale or cancelled callbacks (tested with a cancel and a retry in flight); no check() on normal paths in receiverand (it runs inside setrand); don't auto-send results to accounts with contract code, which could reject the transfer and stall or re-roll the draw.

Added — CLI (cli-reference.md, testing-debugging.md, SKILL.md, safety-guidelines.md)

  • contract:set prompts Continue? (y/N) and has no --yes flag. Scripts must pipe echo y |.
  • contract:set can deploy the ABI when the WASM is rejected, and still exit 0. Check get_code_hash after every deploy (all zeros = no code). Added this check to the automated testing script.
  • New section, Scripting the CLI for bulk or high-value jobs:
    • transaction:push / action / contract:set print errors and exit 0.
    • The CLI signs with expireSeconds: 3000.
    • Header fields you supply (expiration, ref_block_*) override the CLI's.
    • How to tell "never broadcast" (the error names a read call) from "rejected by the node" from "ambiguous".
    • Resend only after irreversible time passes the expiration, reading state from the same endpoint.
    • The selected chain is global: check it before every signing step.
  • Don't grep CLI output for error, because successes include "error_code": null.
  • transaction:push needs {"actions":[…]}. Plain action data goes through proton action.
  • Buying a resources plan from the CLI (deposit, then buyplan). Faucet: 1,000 test XPR per account per 24 h.
  • SKILL.md safety reminder: a push response is not proof.

Added — accounts (accounts-permissions.md, cli-reference.md)

  • proton account:create-funded NAME -c CREATOR -k PUB_K1_… -o BACKUP_OWNER creates accounts with no email step and prints no private key when -k is given. It is the recommended path for agent-driven testnet rehearsals.

Added — resources (staking-governance.md, troubleshooting.md, nfts-atomicassets.md)

  • buyplan pays from a deposit: transfer XPR to resources first (credited to the sender in resources::accounts), then call buyplan. Verified on mainnet with plan 0 (Basic, 744 h).
  • Troubleshooting for transaction net usage is too high: X > Y: bulk jobs from one account use up the free NET allowance (~450 KB / 24 h observed on testnet). The node rejected the transaction, so retrying after buying a plan is safe.

Added — NFTs (nfts-atomicassets.md)

  • In action data, ipfs-typed attributes use the variant type string (["string","Qm…"]), including collection img in createcol data (the example now shows it). ["ipfs",…] fails client-side with type "ipfs" is not valid for variant. The value must be a CIDv0.
  • Template immutable_data keys must exist in the schema. For collections where every asset is unique, use an empty template with max_supply and burnable: false.
  • New Bulk Minting Safely pattern, used for 3,333 editions on testnet (with a deliberate crash and a real ambiguous push) and on mainnet (167/167 batches, no duplicates):
    • issued_supply is the progress counter, and editions are minted in order.
    • Every attempt is journaled with its own expiration before the push.
    • The chain decides the outcome, not the CLI.
    • Ambiguous batches are resent only after they can no longer land.
    • A lock file, resource checks, and a verify step.
  • template_mint from the AtomicAssets API is back-filled (0 at first). Verify mint order by asset_id instead, and wait for the indexer count to match issued_supply.
  • Measured:
    • ~280 B RAM per asset (3,333 assets, ~15 attributes, empty template data).
    • ~470–610 µs CPU per 10-asset mint.
    • ~5.6 KB NET per 20-asset mint. Free NET ran out after ~80 batches.

Added — RPC (rpc-queries.md, troubleshooting.md)

  • get_table_rows can return fewer rows than limit (about 1,000 per call observed on AtomicAssets assets, testnet). A one-page read missed 2,300 of 3,300 rows. Always loop on more / next_key.
  • Troubleshooting: A push returned a transaction_id, but nothing changed on chain. A non-producing API node executes the transaction speculatively against its own state. The producer rejected it, and it was dropped without an error (observed on testnet). Confirm by reading state.

Fixed — web SDK (web-sdk.md, troubleshooting.md, SKILL.md)

  • @proton/web-sdk 5.1.0 is GA (npm latest). The version note had called 5.x "rc" and recommended pinning @4. Added the 5.x options shape (uiOptions.appInfo.{name,logo,logoRounded}, selectorOptions limited to walletType/enabledWalletTypes), and the advice to match @proton/link@5.1.0. The 4.x examples are kept and labelled.
  • New pattern: login and transact in separate clicks, with nothing async before transact() in the click. Awaiting login and then calling session.transact() in the same click gets the WebAuth signing popup blocked.
  • The 5.1.0 WebAuth link opens its window synchronously in transact(). A blocked popup leaves link.childWindow null, and the promise never settles (added a detection snippet). A window closed by hand also leaves it pending. Treat that as an unknown outcome, not a cancel.
  • storagePrefix: key format documented. Scope saved sessions per chain and contract, so testnet and mainnet builds on one origin don't restore each other's sessions.
  • 5.1.0 login and cancel shapes ({ error } return, E_CANCEL / E_WALLET_TYPE, 'Closed') replace the "User cancelled" string check.

v2.9.0 — SimpleDEX route: memo multi-hop swaps (V2.1a live)

Choose a tag to compare

@paulgnz paulgnz released this 23 Sep 23:41
f72f6c9

SimpleDEX V2.1a is live on mainnet (contract simpledex, code c8cea09e…). MINOR bump: new reference content.

Added — simpledex.md

  • route: memo — single-transfer multi-hop swaps (route:<pool>,<pool>,...:<minOut>, 1–4 pools, direction derived per hop, protocol fee once at the summed fee rates, payout memo SimpleDEX V2: Multi-hop).
  • Exact protocol-fee math for quotes (BigInt), and the note that minOut is checked against the net amount.
  • Constraints: max swap ratio is per hop, paused pools rejected on every path, deposits accept only the pool's own tokens.

v2.8.0 — Hyperion operations: template persistence, real ES watermarks, act_digest mapping, restart gaps

Choose a tag to compare

@paulgnz paulgnz released this 23 Sep 20:15
3fb083e

Hyperion operations corrections from running the XPR mainnet full-history node in production. MINOR bump: one correction to existing advice plus new reference content. Every claim was checked against the Hyperion 4.0.8 source on the node and against live cluster settings.

Fixed — hyperion-operations-caveats.md §0/§5

  • "Edit the legacy template with PUT _template/proton-action" does not persist: the indexer master re-PUTs every legacy template from index-templates.ts on each start (updateIndexTemplates()). The advice now says to edit the definitions file (src/ and build/), restart gracefully and verify, and to treat it as a local patch that must be re-applied after upgrades.

Added

  • §3: the real ES disk watermarks (low/high/flood) and their max_headroom caps, which make the high watermark trip at 150 GB free on large drives (earlier than "90%"). Includes the absolute-watermark settings and advice to alert on free space at the next 10M-block partition boundary. hyperion-setup.md operations note corrected to match.
  • §5: _disk_usage to find what actually uses the bytes; act_digest is dynamically mapped as text + keyword in 4.0.8 (~26% of an action partition). Mapping it as keyword without doc_values keeps it in _source, in responses and searchable, and cuts ~18% of future partition size. Also a note to keep data (e.g. eosio::onblock) rather than blacklist on public nodes.
  • §11: every indexer restart leaves a block gap (the live reader resumes at head; a 30 s graceful restart left 59 missing blocks) — repair after restarts or automate quick-scan + fill-missing on a cron.
  • §11: fill-missing --host takes the bare host; the headless clearLine crash happens after the request is sent; alert on /v2/health missing_blocks > 0 (43 missing blocks appeared on a healthy live node); scan-actions takes ~15 s for full history.

v2.7.0 — Security and bug review: 55 verified fixes

Choose a tag to compare

@paulgnz paulgnz released this 16 Sep 21:13
82ed830

Security and bug review of the whole skill. Three shell scripts and all 31 modules were reviewed for leaked secrets, private hostnames, unsafe operational advice, and exploitable patterns in the contract samples. Nothing leaked. But because AI agents copy these samples verbatim, several samples were fund-draining as written, and the node chapter opened ports it should not. Every high-severity item was confirmed against the source line and, for proton-tsc claims, against the installed SDK (proton-tsc 0.3.58 / as-chain). MINOR bump: substantial corrections.

Fixed — contract samples (smart-contracts.md, token-creation.md, examples.md, oracles-randomness.md, nfts-atomicassets.md, payment-patterns.md, accounts-permissions.md, staking-governance.md)

  • Every transfer notify handler now checks this.firstReceiver against the token contract (eosio.token / atomicassets) and the symbol. Three of the four handlers in the skill omitted it, so a worthless token with the same symbol string would have been paid out or refunded in real XPR.
  • Asset.amount is i64 and isValid() permits negatives, so every burn / unwrap / fee-transfer / mint / subBalance / addBalance path now checks amount > 0. Without it a negative burn was a mint.
  • payWinner, init, the four TableStore CRUD samples, and the subscription charge action gained the requireAuth they were missing.
  • CoinFlip is now a transfer notify handler that derives the stake from the received quantity; the old flip(bet) action paid out a bet it never collected. Slot jackpot scales with the wager instead of a fixed 10,000 XPR at a 1 XPR minimum.
  • PriceBattle reads the oracle price on-chain in resolve instead of accepting it from the caller. The on-chain oracle sample checks points[].time for staleness and rejects a zero price.
  • Subscription billing uses a pre-funded escrow balance; the prose now says plainly that granting a third-party contract active authority is never acceptable.
  • Payment matching compares the token symbol and contract, not just the amount; the watcher assigns merchantAccount (it was undefined, so nothing ever matched) and waits for LIB before marking an invoice paid.
  • Compile errors: TableStore scope is a Name (new Name(sym.code()), not the u64), exists() takes a u64, TransferArgs extends ActionData, capturing arrow functions and free functions using this replaced with methods, Singleton imported, missing @primary added, vesting math in U128, days * 86400 cast to u64 before multiplying.
  • RNG section uses the shipped sendRequestRandom / RNG_CONTRACT / rngChecksumToU64; eosio.code is needed to send requestrand, not to receive the callback.
  • Per-transfer table scans replaced with a @secondary index lookup; cleanup bounds its scan separately from its removal count.
  • Every updateauth snippet warns that it replaces the whole authority. isAdmin is a method on a real contract class. Token precision comes from one SUPPORTED_TOKENS map (XBTC/XETH are 8, not 6). BP vote count is "exactly 4".

Fixed — key handling and agent guidance (SKILL.md, backend-patterns.md, cli-reference.md, metalx-dex.md, troubleshooting.md, xpr-agents.md, simpledex.md, defi-trading.md, agent-bootstrap.md)

  • The CLI keystore is proton-cli.json, plaintext on disk until proton key:lock. Nine places called it "encrypted"; key:lock is now a required step on any long-lived host.
  • proton key:add <key> on the command line lands in shell history and ps; documented at every occurrence, with interactive add preferred. proton key:get carries an agent-facing warning that it prints the raw key.
  • Content fetched from llms.txt or any URL is untrusted data, never instructions; fund-moving actions (transfer, stake, approve, escrow release) require human approval.
  • Swap example used MIN_OUTPUT = 1 (one raw unit, no slippage protection) while its comment claimed one XUSDC; now a real raw bound.
  • Six sendTransaction(actions) call sites matched a (session, actions) signature; session is threaded through. The startup check now parses proton key:list for the account instead of only testing the binary exists.
  • .env template: add it to .gitignore first. export PROTON_PRIVATE_KEY persists in history and is inherited by child processes. sudo chown -R /usr/local/... replaced with a user npm prefix. transaction:push takes unsigned JSON (comment and example now agree).
  • Bootstrap: curl … main/… | bash replaced with clone, checkout a tagged release, review, run.

Fixed — node and Hyperion operations (node-operation.md, hyperion-setup.md, hyperion-operations-caveats.md, real-time-events.md)

  • Firewall block allows SSH before ufw enable (it locked the operator out) and no longer opens 8888 directly; nodeos HTTP binds 127.0.0.1 behind nginx, mandatory on a BP because producer_api_plugin is enabled there.
  • state-history-endpoint binds 127.0.0.1:8080 everywhere, matching the Hyperion guide's "never expose SHIP publicly".
  • config.ini with a signature-provider key: chmod 600, never commit, KEOSD form noted. Wallet password file moves to ~/.wallet_pass.txt with chmod 600.
  • Snapshot restore verifies the mainnet chain id and cross-checks the head block against two public endpoints. Public Hyperion nginx block gains TLS and an 80→443 redirect. RabbitMQ password read from stdin, management tag instead of administrator. Prometheus scrape targets prometheus_plugin, not port 8888.
  • Redis temp-file cleanup is safe only for stale files; check rdb_bgsave_in_progress first. Elasticsearch DELETE steps gated on a _count check and operator confirmation.
  • Webhook HMAC signs the full {event, payload, timestamp} body from an env secret with a freshness window; socket server restricts CORS; SHIP client uses wss://.

Changed — Hyperion guides (hyperion-setup.md, hyperion-operations-caveats.md)

  • Operator attribution, the vendor-specific reference build, and first-person incident narration generalised to "a production full-history build"; sizing numbers, incident details, and the disk-split procedure are unchanged.

Fixed — scripts (scripts/validate-skill.sh, scripts/agent-bootstrap.sh)

  • validate-skill.sh aborted on its first failed check: under set -e, ((ERRORS++)) returns non-zero when the counter is 0. Counters now use ERRORS=$((ERRORS+1)). URL check no longer reports codes like 404000.
  • agent-bootstrap.sh pins @xpr-agents/openclaw 0.8.1, @xpr-agents/sdk 0.4.0, @proton/js 30.1.0, @proton/cli 0.1.99 (overridable via env) instead of pulling latest onto a host that then holds a key; the "env var cleared" message now says the console secret must be removed separately.

v2.6.0 — Full-skill accuracy pass

Choose a tag to compare

@paulgnz paulgnz released this 02 Sep 19:43
cb2cd49

[2.6.0] — 2026-09-03

Full-skill accuracy pass. Every module was re-verified against live mainnet ABIs and tables, the current npm packages (@proton/cli 0.1.99, @proton/web-sdk 5.1.0-rc-4 / 4.4.2, @proton/js 30.1.0, proton-tsc 0.3.58, @proton/vert 0.3.24, @xpr-agents/openclaw 0.5.4, @xpr-agents/sdk 0.2.7, @eosrio/hyperion-stream-client 4.0.0-rc.3), upstream sources (Hyperion 4.1.0, Leap 5.0.3, proton.contracts, alcor-ui, alcor-v2-sdk), docs.metalx.com and xpragents.com/llms.txt, and ~200 URLs. About 75 confirmed inaccuracies fixed across 24 files; nothing unverified was changed. MINOR bump: substantial corrections.

Fixed — proton-tsc / contracts (smart-contracts.md, testing-debugging.md, examples.md, safety-guidelines.md, troubleshooting.md, token-creation.md, oracles-randomness.md)

  • Singleton.get() never returns null (returns a default instance); existence checks now use getOrNull().
  • TableStore has no getAll() / getBySecondaryIndex(); secondary lookups use getBySecondaryU64(value, index) (single row or null).
  • InlineAction takes only the action name; sending is .act(contract, permission).send(data). Fixed in three places.
  • No sendInline, formatAsset, getCaller, transfer, currentBlock, printI/printU, getRamUsage, or Contract.requireRecipient — replaced with sendTransferToken (proton-tsc/token), Asset, hasAuth-based admin lookup, currentBlockNum, printi/printui, and the free requireRecipient.
  • Oracle table in contracts: use Data/DataVariant from proton-tsc/oracles (aggregate.f64Value); a plain f64 field mis-deserializes the variant. Off-chain data rows have no timestamp — freshness comes from points[].time.
  • Build outputs are named after the source file (mycontract.contract.wasm / .abi); the .contract.ts name is a convention, not a compiler requirement.
  • @proton/vert: blockchain.createContract(name, folder) (no loadContract); addTime takes a TimePointSec; bundled eosio.token lives in proton-tsc/external/eosio.token.
  • proton action has no --verbose; stakexpr params are from, receiver, stake_xpr_quantity.
  • Real nodeos error texts for expired / CPU / RAM failures, with exception names; unable to find key is C++ CDT text, not proton-tsc.
  • pricebattle: resolve(challenge_id, resolver) takes no price; Challenge has expires_at; the deployed contract exposes no secondary index (frontend query now scans and filters); protonrating admin pattern rewritten without a caller API.
  • Hyperion get_actions is GET-only (safety checklist curl fixed). localStorage cleanup clears every proton-storage-* key.
  • Appending a trailing BinaryExtension<T> field is the one supported additive table change; documented as the exception to the golden rule.

Fixed — CLI / SDK / backend (cli-reference.md, web-sdk.md, backend-patterns.md, accounts-permissions.md)

  • CLI store is one proton-cli.json under the OS config dir (~/Library/Preferences/@proton/cli-nodejs/ on macOS, ~/.config/@proton/cli-nodejs/ on Linux); ~/.proton-cli does not exist.
  • proton account:create is the free Metal-identity flow with no flags; paid creation is account:create-funded -c -k -r.
  • proton transaction:push takes unsigned {actions} JSON and signs from the keychain; bare proton transaction '<json>' does not parse its argument (still broken in 0.1.99).
  • msig:propose takes a JSON array of actions; msig example expiration is now computed (the old literal date had passed).
  • key:list hides private keys by default but --reveal-private prints them.
  • The XPR_PRIVATE_KEY refusal lives in the create-xpr-agent starter's start.sh, not in @xpr-agents/openclaw (fixed in three files).
  • session.link.transact({ actions }) takes one argument; the two-arg form belongs to createCliApi().api.
  • JsSignatureProvider is exported by @proton/js (no eosjs import).
  • @proton/web-sdk: the documented options are the 4.x shape; latest is 5.1.0-rc-4 with uiOptions.appInfo / uiOptions.theme and a two-field selectorOptions. Installs now pin @4, @proton/link must match web-sdk's major (not 3.2.3-x), chainId is fetched from get_info when omitted, backButton does not exist (requestStatus does), removeSession takes (identifier, auth, chainId), and "Unknown Requestor" means requestAccount is unset.

Fixed — RPC / Hyperion / Light API / streaming (rpc-queries.md, real-time-events.md, resources.md, node-operation.md, hyperion-setup.md, hyperion-operations-caveats.md)

  • All-numeric account names: appending "." to lower_bound/upper_bound is rejected (chain_type_exception) on current nodeos — use the u64 encoding or key_type: "name". get_table_by_scope bounds have the same integer-first bug. Helper unified as safeName().
  • /v2/history/get_transfers does not exist in Hyperion at all (not merely undeployed).
  • get_transaction response shape (trx_id, lib, cached_lib, executed, actions[]…), get_account state shape (nested account), and get_tokens amount: number corrected.
  • Light API: tokenbalance and usercount return text/plain numbers; key lookup is /api/key/{key} keyed by network; topholders returns [account, amount] pairs with limit 10–1000; decimals is a string.
  • Streaming: stream objects emit message, not data (the doc's handlers never fired); unscoped requests are acked status: FAIL, reason: invalid request; Hyperion 3.x servers deliver the handshake as a message, 4.x as a handshake event; bloxprod advertises traces:false. block-stream is not on npm (clone the repo).
  • control_port is read from connections.json, not the chain config. Snapshot mirror cited as https. Stream client 4.0.0-rc.3 is published under the latest tag.
  • Dropped two closed neftyblocks P2P peers; nodeos version guidance now says Leap 5.0.3 (final Leap) or Spring 1.2.x, matching mainnet's v5.0.0–v5.0.3. Anchor URL is anchorwallet.io.

Fixed — DeFi / DEX (metalx-dex.md, defi-trading.md, alcor-dex.md, simpledex.md, loan-protocol.md, staking-governance.md)

  • MetalX DEX order_type is 1 limit / 2 stop-loss / 3 take-profit (per docs.metalx.com); show_error_msg is bool?; leaderboard takes repeated market_ids= (bracketed form is a 400).
  • Alcor: mainnet market-creation fee is 2,000 XPR (×2 if base ≠ XPR; 50,000 XPR is testnet), paid by transfer with a new_market|… memo; the API's base_currency/target_currency are swapped relative to the on-chain table; account table is an order index, not balances; no /account/{name}/orders endpoint; route endpoint is /swapRouter/getRoute; SDK has no computePoolAddress.
  • SimpleDEX: dex.protonnz.com already 308-redirects; 6-decimal quote tokens (XMD, XUSDC) scale ×1,000,000; sell field is minXpr; moderation authority is simplesetup@active or the 2-of-4 owner msig.
  • LOAN: liquidation memo is liquidate,<borrower>,<LTOKEN>; one global 10% liquidation_incentive (no per-collateral table); borrows rows have no health_factor (compute it); the whitelist gates contract callers by code hash, not users; supply refreshed (~114.2B).
  • Staking: staker rewards are claimed with eosio::voterclaim (voterclaimst to restake) — claimrewards is the BP pay claim; vote for exactly 4 BPs (fewer is accepted but disqualifies rewards); RAM ≈0.0004 XPR/byte with a live-lookup pointer.

Fixed — identity / payments / agents (webauth-identity.md, payment-patterns.md, xpr-agents.md, agent-bootstrap.md, README.md)

  • usersinfo.aacts / ac are arrays of {field_0, field_1} tuples; KYC claim table gains metal.kyc:nationalidnumber and legacy trulioo:* sets (7–8 claims, order varies); contract snippet imports fixed.
  • XPR/USD is oracle feed 3 (payment example used a non-existent feed 1).
  • xpragents: an unset name reads as "" (not 13 dots); the indexer's CORS is allow-listed to xpragents.com/localhost; funding an open job before selectbid is now rejected by the contract (wedge behaviour was pre-Sept-2026).
  • @xpr-agents/openclaw ships 75 MCP tools (four places); proton key:lock takes no argument; the openclaw package exports CLI helpers, not registry classes; bootstrap script re-runs npm install, not npm update; Pinata docs link points at the HTML page; version pins refreshed to @proton/cli 0.1.99 and @xpr-agents/sdk 0.2.7.

Verified unchanged (for the record)

All 18 MetalX markets, the 19-live / 5-dormant oracle split, every LOAN collateral factor and feed index, SimpleDEX fees/thresholds, the four xpragents contract ABIs and every arity in xpr-agents.md, all resources.md token precisions and issuers, all Hyperion ops config keys and CLI subcommands against upstream 4.1.0, all 24 Leap config.ini keys, and the empty-memo DEX deposit behaviour (no refund action exists in the dex ABI).


v2.5.1 — Prompt audit: dedupe, normal register, no archaeology

Choose a tag to compare

@paulgnz paulgnz released this 02 Sep 19:21
33bf439

[2.5.1] — 2026-09-03

Prompt audit of the skill's model-facing text (SKILL.md, the agent bootstrap chat prompt, module rule lines) against current Claude models. No rule was dropped; every change removes duplication, shouting register, or archaeology while keeping each constraint and its reason.

Changed

  • SKILL.md frontmatter description now names the legacy brand and package namespace (Proton, proton-tsc, @proton/*) and the product areas the modules cover, so the skill triggers on questions that never say "XPR Network".
  • SKILL.md AI-generated-code disclaimer collapsed from a bullet wall to one reasoned paragraph pointing at the full checklist in safety-guidelines.md.
  • SKILL.md mid-file "CRITICAL: Before Modifying Contracts" block removed — the same rule already routes in the module table and is recapped in Safety Reminders.
  • agent-bootstrap.md bootstrap chat prompt: the four key-handling rules (non-interactive key:add only, base-58 error means stop and re-send, never echo or store the key, confirm via key:list) restated at normal volume with their reasons, replacing the boxed HARD RULES block.
  • agent-bootstrap.md troubleshooting: PR numbers and "original publication" history removed from three symptom→fix entries.
  • cli-reference.md key-management rule now states its reason and points at the key-isolation section instead of an exclamation.