Repository navigation
Releases: XPRNetwork/xpr-network-dev-skill
Release list
v2.14.0 — Help builders only: spam-shaped samples removed, etiquette rules tightened, operator defences added
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."graduategets "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 addnonce: Date.now()or "unique data"; that is thescanliqtechnique. 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 viaPromise.all; both now build oneactions[]and submit a single transaction, and the market maker gates requotes onminRequoteMs(≥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/processsltpnow say: called by the matching engine; at most oneprocessin 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 confirmingliquidateis 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 withoutRATE_OVERRIDE_REASONand refuses above 60 outright. Minute cron that pushed up to 100resolvewrites 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/linkauthsigned@active, not@owner; the service and mint samples use linkedpay/minter/resolvepermissions instead ofactive.A2A_SIGNING_KEY=PVT_K1_…removed from the.envtemplate. 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 withlimit: 1000→ cursor-keyed bounded query at 10 s withstop(), 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.politeFetchandqueryWithFallbackback off on the same endpoint on 429 (honouringRetry-After) and rotate only on 5xx/connection failure.getAllRowscapped withmaxPagesand an inter-page delay; Hyperionskippaging replaced with cursors.processduestub (unauthenticated no-op write) now requires auth and fails when nothing is due; SubscriptionBot paced to the budget.examples.md— publiccleanupaction 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 oneresolveper resolvable challenge, never race or retry in a loop."smart-contracts.md— the flagshipMyToken.deposit(account, amount)credited balances from an action argument with no transfer; it is now atransfernotify 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, linkedairdroppermission, undefined variables and a non-existenttransactoptions argument fixed. Wrap/unwrap now maintainstats.supply, checkmax_supply, and store the fullchecksum256instead 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 routineupdateauth/linkauth/deleteauthexamples signed@ownernow sign@active; owner is for recovery only. Private keys no longer appear onproton key:add/key:removecommand lines anywhere; the prompted form is shown, and rotation sequences end withproton key:lock.
Added: defensive guidance that was missing
node-operation.md—net_api_pluginremoved from the public API-node config (its/v1/net/connect|disconnectare unauthenticated) and the nginx proxy now returns 403 for/v1/(net|producer|db_size|test_control)/; thelimit_reqline finally has itslimit_req_zone. New "Defending against abusive traffic" section: nodeosactor-blacklist/contract-blacklist/sender-bypass-whiteblacklist(coordinate across producing BPs),http-max-in-flight-requests,max-body-size, nginxlimit_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 tohttps:and IPFS CIDs, neverinnerHTML. The webauth KYC example no longer gates on theverifiedflag 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. Allgit checkout v2.10.0pins andgit pullonmainreplaced with the latest release tag.scripts/agent-bootstrap.sh— clones and updates atSKILL_REF(default v2.14.0), nevermain; 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 akey:addcommand line, "encrypted keychain" claims,0.0.0.0HTTP/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. StalePR_DESCRIPTION.mdremoved from the tree and ignored.
Reported upstream
- The SimpleDEX cooldown gap (enforced on the
swapaction 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)
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 nowxpr-agents, notopenclaw(0.9.0). OpenClaw 2026.9 added a core tool namedopenclaw; a plugin whose id matches a core tool is dropped from the tool registry, which hid all 89 tools. The install bullet now saysplugins.allow: ["xpr-agents"],tools.alsoAllow: ["xpr-agents"]andopenclaw 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_agentandxpr_submit_feedbackpay a configured registration/feedback fee automatically (0.8.x rejected those calls when a fee was configured).MAX_TRANSFER_AMOUNTcountingbuyram/stakexpris attributed to 0.9.0 (0.8.8 was never published).XPR_RPC_ENDPOINTadded to the env list.xpr-agents.md— sdk 0.5.3 pagination and amount fixes noted (listAgentsno longer repeats a row across pages,listJobsByClient/Agenthonour the cursor,listServicestakes a cursor, exact integer XPR quantities,A2AClientrejects non-http(s) endpoints); advice to pin>=0.5.3when paginating.scripts/agent-bootstrap.sh— pins bumped to@xpr-agents/openclaw0.9.2 and@xpr-agents/sdk0.5.3.@proton/jsstays 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
blockartskill 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 inXPRNetwork/xpr-agentswere read for the behavioural changes above. - All 21 hostnames referenced by the skill answered on 2026-10-25;
scripts/validate-skill.shpasses all 10 checks.
v2.12.0 — XPR Agents module updated for sdk 0.5.2 / openclaw 0.8.7
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 +listsvcin one transaction,buy:<id>[:notes],updatesvc/delistsvc/relistsvc/refundsvcfee, input forms (setsvcinput/svcinput), featured placement viaboost:<id>, whatsample_urimust 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 falseplus 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 andA2AClient, and Shellbook (contractshellbook, 15 tools).
Changed
backend-patterns.md:createCliSessiondocuments themaxTransferAmountcap; the install line distinguishes a Node process from an OpenClaw harness; the.envtemplate lists the plugin's optional settings with defaults.scripts/agent-bootstrap.shpins@xpr-agents/openclaw0.8.7 and@xpr-agents/sdk0.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.mdandREADME.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+chainIdin the digest,targetAccount/chainIdrequired onA2AClient), reputation scaled bymin(reviews, 5) / 5,ENABLE_MSIG_APPROVE,AGENT_MODEvalues andstart.shdefaults, indexer endpoint shapes and the 100 req/min limit, and an explicit OpenClaw 2026.9.x is not verified note. The bootstrap pins@proton/js28.1.2 to match the^28range both packages declare.
v2.11.0 — Liquidation how-to removed, Network Etiquette added
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; theperps.liquidationcontract row and the Liquidation Bot service row are removed. The liquidation-price preview for position holders stays.- Index rows in
SKILL.mdandREADME.mdno 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.mdgains 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 inmetalx-dex.md, Rate Limiting inbackend-patterns.md, and the signing section inxpr-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, aliquidateaction, or ascanliq-style action) reappears in any module.
v2.10.0 — NFT drop learnings: safe CLI scripting, bulk mint, rng callback safety
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()inproton-tsc0.3.58 /as-chaindeclaresget_code_hashwith 3 params, but the node intrinsic takes 4.setcodefails withwrong type for imported function get_code_hash. Added a workaround that ran on testnet and mainnet: an@external4-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_hasherror 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 saysmissing 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
rngoracle 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_idand ignore stale or cancelled callbacks (tested with a cancel and a retry in flight); nocheck()on normal paths inreceiverand(it runs insidesetrand); 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:setpromptsContinue? (y/N)and has no--yesflag. Scripts must pipeecho y |.contract:setcan deploy the ABI when the WASM is rejected, and still exit 0. Checkget_code_hashafter 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:setprint 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:pushneeds{"actions":[…]}. Plain action data goes throughproton action.- Buying a
resourcesplan from the CLI (deposit, thenbuyplan). 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_OWNERcreates accounts with no email step and prints no private key when-kis given. It is the recommended path for agent-driven testnet rehearsals.
Added — resources (staking-governance.md, troubleshooting.md, nfts-atomicassets.md)
buyplanpays from a deposit: transfer XPR toresourcesfirst (credited to the sender inresources::accounts), then callbuyplan. 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 typestring(["string","Qm…"]), including collectionimgincreatecoldata (the example now shows it).["ipfs",…]fails client-side withtype "ipfs" is not valid for variant. The value must be a CIDv0. - Template
immutable_datakeys must exist in the schema. For collections where every asset is unique, use an empty template withmax_supplyandburnable: 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_supplyis 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_mintfrom the AtomicAssets API is back-filled (0 at first). Verify mint order byasset_idinstead, and wait for the indexer count to matchissued_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_rowscan return fewer rows thanlimit(about 1,000 per call observed on AtomicAssetsassets, testnet). A one-page read missed 2,300 of 3,300 rows. Always loop onmore/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-sdk5.1.0 is GA (npmlatest). The version note had called 5.x "rc" and recommended pinning@4. Added the 5.x options shape (uiOptions.appInfo.{name,logo,logoRounded},selectorOptionslimited towalletType/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 callingsession.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 leaveslink.childWindownull, 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)
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 memoSimpleDEX V2: Multi-hop).- Exact protocol-fee math for quotes (BigInt), and the note that
minOutis 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
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 fromindex-templates.tson each start (updateIndexTemplates()). The advice now says to edit the definitions file (src/andbuild/), 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_headroomcaps, 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.mdoperations note corrected to match. - §5:
_disk_usageto find what actually uses the bytes;act_digestis dynamically mapped as text + keyword in 4.0.8 (~26% of an action partition). Mapping it askeywordwithoutdoc_valueskeeps 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-missingon a cron. - §11:
fill-missing --hosttakes the bare host; the headlessclearLinecrash happens after the request is sent; alert on/v2/healthmissing_blocks> 0 (43 missing blocks appeared on a healthy live node);scan-actionstakes ~15 s for full history.
v2.7.0 — Security and bug review: 55 verified fixes
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
transfernotify handler now checksthis.firstReceiveragainst 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.amountisi64andisValid()permits negatives, so everyburn/unwrap/ fee-transfer /mint/subBalance/addBalancepath now checksamount > 0. Without it a negative burn was a mint.payWinner,init, the four TableStore CRUD samples, and the subscriptionchargeaction gained therequireAuththey were missing.- CoinFlip is now a
transfernotify handler that derives the stake from the receivedquantity; the oldflip(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
resolveinstead of accepting it from the caller. The on-chain oracle sample checkspoints[].timefor 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
activeauthority is never acceptable. - Payment matching compares the token symbol and contract, not just the amount; the watcher assigns
merchantAccount(it wasundefined, so nothing ever matched) and waits for LIB before marking an invoice paid. - Compile errors:
TableStorescope is aName(new Name(sym.code()), not theu64),exists()takes au64,TransferArgsextendsActionData, capturing arrow functions and free functions usingthisreplaced with methods,Singletonimported, missing@primaryadded, vesting math inU128,days * 86400cast tou64before multiplying. - RNG section uses the shipped
sendRequestRandom/RNG_CONTRACT/rngChecksumToU64;eosio.codeis needed to sendrequestrand, not to receive the callback. - Per-transfer table scans replaced with a
@secondaryindex lookup;cleanupbounds its scan separately from its removal count. - Every
updateauthsnippet warns that it replaces the whole authority.isAdminis a method on a real contract class. Token precision comes from oneSUPPORTED_TOKENSmap (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 untilproton key:lock. Nine places called it "encrypted";key:lockis now a required step on any long-lived host. proton key:add <key>on the command line lands in shell history andps; documented at every occurrence, with interactive add preferred.proton key:getcarries an agent-facing warning that it prints the raw key.- Content fetched from
llms.txtor 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;sessionis threaded through. The startup check now parsesproton key:listfor the account instead of only testing the binary exists. .envtemplate: add it to.gitignorefirst.export PROTON_PRIVATE_KEYpersists in history and is inherited by child processes.sudo chown -R /usr/local/...replaced with a user npm prefix.transaction:pushtakes unsigned JSON (comment and example now agree).- Bootstrap:
curl … main/… | bashreplaced 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 binds127.0.0.1behind nginx, mandatory on a BP becauseproducer_api_pluginis enabled there. state-history-endpointbinds127.0.0.1:8080everywhere, matching the Hyperion guide's "never expose SHIP publicly".config.iniwith asignature-providerkey:chmod 600, never commit, KEOSD form noted. Wallet password file moves to~/.wallet_pass.txtwithchmod 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,
managementtag instead ofadministrator. Prometheus scrape targetsprometheus_plugin, not port 8888. - Redis temp-file cleanup is safe only for stale files; check
rdb_bgsave_in_progressfirst. ElasticsearchDELETEsteps gated on a_countcheck 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 useswss://.
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.shaborted on its first failed check: underset -e,((ERRORS++))returns non-zero when the counter is 0. Counters now useERRORS=$((ERRORS+1)). URL check no longer reports codes like404000.agent-bootstrap.shpins@xpr-agents/openclaw0.8.1,@xpr-agents/sdk0.4.0,@proton/js30.1.0,@proton/cli0.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
[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 returnsnull(returns a default instance); existence checks now usegetOrNull().TableStorehas nogetAll()/getBySecondaryIndex(); secondary lookups usegetBySecondaryU64(value, index)(single row or null).InlineActiontakes only the action name; sending is.act(contract, permission).send(data). Fixed in three places.- No
sendInline,formatAsset,getCaller,transfer,currentBlock,printI/printU,getRamUsage, orContract.requireRecipient— replaced withsendTransferToken(proton-tsc/token),Asset,hasAuth-based admin lookup,currentBlockNum,printi/printui, and the freerequireRecipient. - Oracle table in contracts: use
Data/DataVariantfromproton-tsc/oracles(aggregate.f64Value); a plainf64field mis-deserializes the variant. Off-chaindatarows have notimestamp— freshness comes frompoints[].time. - Build outputs are named after the source file (
mycontract.contract.wasm/.abi); the.contract.tsname is a convention, not a compiler requirement. @proton/vert:blockchain.createContract(name, folder)(noloadContract);addTimetakes aTimePointSec; bundledeosio.tokenlives inproton-tsc/external/eosio.token.proton actionhas no--verbose;stakexprparams arefrom, receiver, stake_xpr_quantity.- Real nodeos error texts for expired / CPU / RAM failures, with exception names;
unable to find keyis C++ CDT text, not proton-tsc. pricebattle:resolve(challenge_id, resolver)takes no price;Challengehasexpires_at; the deployed contract exposes no secondary index (frontend query now scans and filters);protonratingadmin pattern rewritten without a caller API.- Hyperion
get_actionsis GET-only (safety checklist curl fixed).localStoragecleanup clears everyproton-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.jsonunder the OS config dir (~/Library/Preferences/@proton/cli-nodejs/on macOS,~/.config/@proton/cli-nodejs/on Linux);~/.proton-clidoes not exist. proton account:createis the free Metal-identity flow with no flags; paid creation isaccount:create-funded -c -k -r.proton transaction:pushtakes unsigned{actions}JSON and signs from the keychain; bareproton transaction '<json>'does not parse its argument (still broken in 0.1.99).msig:proposetakes a JSON array of actions; msig example expiration is now computed (the old literal date had passed).key:listhides private keys by default but--reveal-privateprints them.- The
XPR_PRIVATE_KEYrefusal lives in thecreate-xpr-agentstarter'sstart.sh, not in@xpr-agents/openclaw(fixed in three files). session.link.transact({ actions })takes one argument; the two-arg form belongs tocreateCliApi().api.JsSignatureProvideris exported by@proton/js(noeosjsimport).@proton/web-sdk: the documented options are the 4.x shape;latestis 5.1.0-rc-4 withuiOptions.appInfo/uiOptions.themeand a two-fieldselectorOptions. Installs now pin@4,@proton/linkmust match web-sdk's major (not3.2.3-x),chainIdis fetched fromget_infowhen omitted,backButtondoes not exist (requestStatusdoes),removeSessiontakes(identifier, auth, chainId), and "Unknown Requestor" meansrequestAccountis 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
"."tolower_bound/upper_boundis rejected (chain_type_exception) on current nodeos — use the u64 encoding orkey_type: "name".get_table_by_scopebounds have the same integer-first bug. Helper unified assafeName(). /v2/history/get_transfersdoes not exist in Hyperion at all (not merely undeployed).get_transactionresponse shape (trx_id, lib, cached_lib, executed, actions[]…),get_accountstate shape (nestedaccount), andget_tokensamount: numbercorrected.- Light API:
tokenbalanceandusercountreturn text/plain numbers;keylookup is/api/key/{key}keyed by network;topholdersreturns[account, amount]pairs withlimit10–1000;decimalsis a string. - Streaming: stream objects emit
message, notdata(the doc's handlers never fired); unscoped requests are ackedstatus: FAIL, reason: invalid request; Hyperion 3.x servers deliver the handshake as amessage, 4.x as ahandshakeevent; bloxprod advertisestraces:false.block-streamis not on npm (clone the repo). control_portis read fromconnections.json, not the chain config. Snapshot mirror cited ashttps. Stream client 4.0.0-rc.3 is published under thelatesttag.- 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_typeis 1 limit / 2 stop-loss / 3 take-profit (per docs.metalx.com);show_error_msgisbool?; leaderboard takes repeatedmarket_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'sbase_currency/target_currencyare swapped relative to the on-chain table;accounttable is an order index, not balances; no/account/{name}/ordersendpoint; route endpoint is/swapRouter/getRoute; SDK has nocomputePoolAddress. - SimpleDEX:
dex.protonnz.comalready 308-redirects; 6-decimal quote tokens (XMD, XUSDC) scale ×1,000,000;sellfield isminXpr; moderation authority issimplesetup@activeor the 2-of-4 owner msig. - LOAN: liquidation memo is
liquidate,<borrower>,<LTOKEN>; one global 10%liquidation_incentive(no per-collateral table);borrowsrows have nohealth_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(voterclaimstto restake) —claimrewardsis 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/acare arrays of{field_0, field_1}tuples; KYC claim table gainsmetal.kyc:nationalidnumberand legacytrulioo:*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 beforeselectbidis now rejected by the contract (wedge behaviour was pre-Sept-2026). @xpr-agents/openclawships 75 MCP tools (four places);proton key:locktakes no argument; the openclaw package exports CLI helpers, not registry classes; bootstrap script re-runsnpm install, notnpm update; Pinata docs link points at the HTML page; version pins refreshed to@proton/cli0.1.99 and@xpr-agents/sdk0.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
[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.mdfrontmatter 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.mdAI-generated-code disclaimer collapsed from a bullet wall to one reasoned paragraph pointing at the full checklist insafety-guidelines.md.SKILL.mdmid-file "CRITICAL: Before Modifying Contracts" block removed — the same rule already routes in the module table and is recapped in Safety Reminders.agent-bootstrap.mdbootstrap chat prompt: the four key-handling rules (non-interactivekey:addonly, base-58 error means stop and re-send, never echo or store the key, confirm viakey:list) restated at normal volume with their reasons, replacing the boxed HARD RULES block.agent-bootstrap.mdtroubleshooting: PR numbers and "original publication" history removed from three symptom→fix entries.cli-reference.mdkey-management rule now states its reason and points at the key-isolation section instead of an exclamation.