diff --git a/AGENTS.md b/AGENTS.md index 3ac3482..ae64443 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,13 @@ These instructions apply to the `peer-cli` repo. - Prefer dry-run previews for write paths. Use the single `--yes` execution flag only when immediate broadcast is intended. - Keep `peer mcp --profile read-only` as the default. The `cash` profile may prepare unsigned transactions but must never accept signer material, sign, or broadcast. Use `full` only for the complete operator surface. - Keep `package.json`, `mcp.json`, `plugin.json`, `server.json`, and packaged skill versions aligned for a release. +- Stake and dispute-protection commands track the current `@zkp2p/sdk` names. + Protection is scoped by `(escrow, depositId, paymentMethod)`, and a zero risk + window means that payment method admits without stake. +- A prepared Peer Cash order can return several `accessPolicyPaymentMethods`. + The host must finalize the deposit, then submit one + `prepareAccessPolicy(depositId, paymentMethod)` transaction per returned + method. Access restriction is separate from stake-backed protection. - Do not log or print private keys, API keys, tokens, cookies, or other credential values. Persistent runtime files stay owner-only. - Keep tests hermetic unless a test is explicitly marked E2E. - `agents.peer.xyz` source lives in `zkp2p-clients/clients/agents`; this repo owns the executable runtime and generated contracts it documents. diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa77c5..d79e4a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,20 @@ # Changelog +## 0.4.0 + +- Updated to `@zkp2p/sdk@0.12.2-rc.3` and `@zkp2p/cash@0.4.11-rc.3` for the + current method-scoped dispute-protection and Peer Cash access-policy APIs. +- Replaced the retired chargeback-enabled read with + `stake dispute-protection-enabled`, including the required payment-method + hash, and updated matured-release calls to the current SDK names. +- Fixed `peer_cash_prepare_access_policy` to require and forward the exact + payment method returned by `accessPolicyPaymentMethods`. +- Updated the packaged skill, agent instructions, and generated catalogs for + the access-policy and Stake to Take cutovers. + ## 0.3.0 -- Added complete StakeVault and chargeback-protection CLI families, including +- Added complete StakeVault and dispute-protection CLI families, including authoritative and indexed state, preview-first writes, and matured-intent release operations. - Added IntentGuardian discovery, policy, live extension quotes, payer-funding diff --git a/CLAUDE.md b/CLAUDE.md index 9874b9b..6b5db4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,6 +12,9 @@ - The command registry, `src/mcp/cash.ts`, and the error catalog are runtime sources of truth. `npm run build` regenerates the agent contracts. - `peer mcp --profile read-only` is the default. `cash` exposes custody-separated Peer Cash tools; `full` exposes every tool. - `--yes` is the only flag that forces prepared generic writes to broadcast. +- Dispute protection is payment-method scoped. Use the current SDK method names, + and pass the payment method hash to protection reads and Cash access-policy + follow-ups. - Persistent config lives at `~/.peer/config.json`; checkout cache lives at `~/.peer/checkout-sessions.json`. - Persistent runtime files must remain owner-only, and debug output must redact secrets. - `--format table` only changes successful CLI rendering. Errors always emit JSON to stderr. diff --git a/README.md b/README.md index 2ea8ee8..4b85bb5 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ The package is `peer-protocol-cli`; do not install the unrelated unscoped `peer-cli` package. ```bash -npm install --global peer-protocol-cli@0.3.0 +npm install --global peer-protocol-cli@0.4.0 peer --help ``` Run without a global install: ```bash -npx -y peer-protocol-cli@0.3.0 quote --from USD --amount 100 --platform wise +npx -y peer-protocol-cli@0.4.0 quote --from USD --amount 100 --platform wise ``` Successful output is JSON by default. Errors always use the canonical JSON @@ -73,7 +73,7 @@ The current tool counts are generated in `agents/runtime-manifest.json`. "command": "npx", "args": [ "-y", - "peer-protocol-cli@0.3.0", + "peer-protocol-cli@0.4.0", "mcp", "--profile", "read-only" @@ -116,6 +116,11 @@ custody boundary are unchanged: 8. `peer_cash_prepare_access_policy`, `peer_cash_prepare_withdraw`, and `peer_cash_prepare_top_up` — prepare follow-up transactions. +For every method returned by `peer_cash_prepare` in +`accessPolicyPaymentMethods`, call `peer_cash_prepare_access_policy` after +finalization with both the finalized `depositId` and that exact +`paymentMethod`. Confirm every policy before presenting the order as ready. + Base USDC amounts are decimal strings in 6-decimal base units: 100 USDC is `100000000`. Estimates are not locked quotes; the binding Chainlink rate resolves when a buyer fills. @@ -160,8 +165,8 @@ The CLI covers: - deposit lifecycle, payment methods, currencies, oracle configuration, and batch updates - intents, pre-intent hooks, fulfillment, release, and cleanup -- StakeVault deposits, withdrawals, authorization, indexed freshness, and - matured chargeback releases +- StakeVault deposits, withdrawals, shared-stake authorization, method-scoped + dispute-protection reads, indexed freshness, and matured releases - IntentGuardian policy, live extension quotes, payer funding, and preview-first intent extension - ProtocolViewer and indexer reads, including a raw GraphQL escape hatch diff --git a/agents/tool-catalog.json b/agents/tool-catalog.json index 7191507..eced3da 100644 --- a/agents/tool-catalog.json +++ b/agents/tool-catalog.json @@ -3796,7 +3796,7 @@ "stake", "locked" ], - "description": "Read stake locked behind active chargeback windows.", + "description": "Read stake locked behind active dispute windows.", "parameter_schema": { "type": "object", "properties": { @@ -3963,7 +3963,7 @@ "stake", "admissions-paused" ], - "description": "Read whether chargebackable intent admissions are paused.", + "description": "Read whether dispute-protected intent admissions are paused.", "parameter_schema": { "type": "object", "properties": { @@ -4005,12 +4005,12 @@ "read_only": true }, { - "name": "peer stake chargeback-enabled", + "name": "peer stake dispute-protection-enabled", "path": [ "stake", - "chargeback-enabled" + "dispute-protection-enabled" ], - "description": "Read whether a deposit has chargeback coverage enabled.", + "description": "Read whether one deposit payment method has dispute protection enabled.", "parameter_schema": { "type": "object", "properties": { @@ -4022,6 +4022,10 @@ "type": "string", "description": "Numeric deposit ID." }, + "paymentMethodHash": { + "type": "string", + "description": "Payment method bytes32 hash." + }, "params": { "type": "object", "description": "Optional raw JSON params object merged underneath the typed CLI flags." @@ -4029,7 +4033,8 @@ }, "required": [ "escrow", - "depositId" + "depositId", + "paymentMethodHash" ] }, "auth_required": false, @@ -4226,7 +4231,7 @@ "stake", "release-matured" ], - "description": "Release one matured chargeback intent and unlock its stake cover.", + "description": "Release one matured protected intent and unlock its stake cover.", "parameter_schema": { "type": "object", "properties": { @@ -4236,7 +4241,7 @@ }, "policy": { "type": "string", - "description": "Optional snapshotted chargeback policy address." + "description": "Optional snapshotted dispute-protection policy address." }, "params": { "type": "object", @@ -4257,7 +4262,7 @@ "stake", "release-matured-batch" ], - "description": "Release multiple matured chargeback intents in one transaction.", + "description": "Release multiple matured protected intents in one transaction.", "parameter_schema": { "type": "object", "properties": { @@ -4267,7 +4272,7 @@ }, "policy": { "type": "string", - "description": "Optional snapshotted chargeback policy address." + "description": "Optional snapshotted dispute-protection policy address." }, "params": { "type": "object", diff --git a/llms.txt b/llms.txt index 69a7321..a09338d 100644 --- a/llms.txt +++ b/llms.txt @@ -24,7 +24,7 @@ catalogs own enumerations; prose must not duplicate a command inventory. ## MCP -Run `npx -y https://github.com/zkp2p/peer-cli/releases/download/v0.2.0/peer-protocol-cli-0.2.0.tgz mcp --profile `. +Run `npx -y https://github.com/zkp2p/peer-cli/releases/download/v0.4.0/peer-protocol-cli-0.4.0.tgz mcp --profile `. - read-only: generic and Peer Cash reads; no signing or broadcasting - cash: complete peer_cash_* surface; prepares unsigned plans and never accepts @@ -46,7 +46,8 @@ local stdio profiles. 3. peer_cash_prepare 4. host approval and ordered wallet submission 5. peer_cash_finalize after the confirmed createDeposit receipt -6. peer_cash_prepare_access_policy when required +6. for every accessPolicyPaymentMethods entry, call + peer_cash_prepare_access_policy with depositId and that paymentMethod 7. persist depositId and resume with peer_cash_order Base USDC uses 6 decimals. Treat estimates as approximate. Retry read failures diff --git a/package-lock.json b/package-lock.json index bfee5eb..53cd87b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "peer-protocol-cli", - "version": "0.3.0", + "version": "0.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "peer-protocol-cli", - "version": "0.3.0", + "version": "0.4.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.30.0", - "@zkp2p/cash": "^0.4.10", - "@zkp2p/sdk": "^0.12.1", + "@zkp2p/cash": "0.4.11-rc.3", + "@zkp2p/sdk": "0.12.2-rc.3", "commander": "^14.0.3", "viem": "^2.55.19", "zod": "^4.4.3" @@ -933,129 +933,159 @@ } }, "node_modules/@peculiar/asn1-cms": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.8.0.tgz", - "integrity": "sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.9.4.tgz", + "integrity": "sha512-cben7oxmQsUGZqotus7yt0srYdncOT6RNWcTQ77T2RFOXejYVYkXadrfePdRcrVpO9K95IRLKKglG2k38jKXuw==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", - "@peculiar/asn1-x509-attr": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "@peculiar/asn1-x509-attr": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-csr": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.8.0.tgz", - "integrity": "sha512-akbF8+uvleHs8sejNPQxwmVFuInAg6FMNHOwMILXfP518YfFJwdR3jr6oNUPOaEJfuEhn/vkNOCIT6ASUd4mbg==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.9.4.tgz", + "integrity": "sha512-xd4YN4vpRjkDAQWVfZZkeu12IEND7DOpkqaHSIHxZl1uggUNa9Ju0QxY2jHvDAS9pP0zhRBytg8ifsnGo3V0jw==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.8.0.tgz", - "integrity": "sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.9.4.tgz", + "integrity": "sha512-JJXefFshRAuVAjWQo/39bkg1ywc1VaiO44S8RRC+Ykvf/u2KDmYffoDb0ZBPCR5uJy4AGKQhl8mX+Q8ShcWaXQ==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-pfx": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.8.0.tgz", - "integrity": "sha512-5yof1ytoB++RQtaFbqSUJ8pxDJtZT6vbVqZ8XoJ61ph7UjNVvfFwAilnCodqkNsAodpy13gDhoxZXw00pghnyg==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.9.4.tgz", + "integrity": "sha512-khuGzHTzNzk4GDlIBEILyIs6Lce0yn0ZBdoI9v93kmNncfZRhD+AQ5ODFqdhvoE8cMJF/JMTQ8yA+t1D14kqCw==", "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.8.0", - "@peculiar/asn1-pkcs8": "^2.8.0", - "@peculiar/asn1-rsa": "^2.8.0", - "@peculiar/asn1-schema": "^2.8.0", + "@peculiar/asn1-cms": "^2.9.4", + "@peculiar/asn1-pkcs8": "^2.9.4", + "@peculiar/asn1-rsa": "^2.9.4", + "@peculiar/asn1-schema": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.8.0.tgz", - "integrity": "sha512-qAKXtLpBEw9LqhKpjw3ajZSXlBur+ipW+y2ivVBQAG6F6qRx94yO+1ZR4mvw+YaCfKSaOzLeYEzsPaBp4SJELA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.9.4.tgz", + "integrity": "sha512-duRdotlUx9eDZe6QrQpQKl61RbWykCHBCkKayP8V8XdEFwlKHZ8qGGDMyS6Pye7OX7nLFttTTpRkJeet78ckwQ==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.8.0.tgz", - "integrity": "sha512-b5nDWCnkV60+cQ141D6sVVwK9nz64R5n3zSVnklGd+ECdkW2Ol3U1a6yYFlalpSOaD557yuJB64A+q42jG7lUQ==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.9.4.tgz", + "integrity": "sha512-kaL4cNxBpdQE2dKlyZBqz4ygCrwffO+8wfoxTEqM1Z8RadvCeELBRzcv0dzM8aY9azHMwODO5nxU65zXmhToOQ==", "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.8.0", - "@peculiar/asn1-pfx": "^2.8.0", - "@peculiar/asn1-pkcs8": "^2.8.0", - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", - "@peculiar/asn1-x509-attr": "^2.8.0", + "@peculiar/asn1-cms": "^2.9.4", + "@peculiar/asn1-pfx": "^2.9.4", + "@peculiar/asn1-pkcs8": "^2.9.4", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", + "@peculiar/asn1-x509-attr": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.8.0.tgz", - "integrity": "sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.9.4.tgz", + "integrity": "sha512-pZ96eD1PptovcWQ/GSmuNFXd/7EQJNlKfDaNCyE2rx3W0v6QFelkzquVqRSRyyDXXCYD69ZXJDzZ8GhIiQzKoA==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.8.0.tgz", - "integrity": "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.9.4.tgz", + "integrity": "sha512-GjzePcT9Iw8NzeOPf73iNS9xM+TBhd/FilAfP+RQGkTMQJTVWtytN3JHJACCjf/ABNau5S7mS3g+DcuxmRgYEg==", "license": "MIT", "dependencies": { "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.8.0.tgz", - "integrity": "sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.9.4.tgz", + "integrity": "sha512-CxhBo/RdEbMMob7T31ZdQjGuoyRFLVwrDzTn25bihzBasRg9kRm/0IxIPvhgQtcK/9dNcO1XQL2fuPugwELL0Q==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.8.0.tgz", - "integrity": "sha512-tHjkfS/qhMnmrlB2J9NhflQlQ7In3khO3CfmVrriOlpTeErY9ZIKOso1hQ5JQiyrJ7ShvqVPk7E5fQmbclkSKA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.9.4.tgz", + "integrity": "sha512-ehQXbpQaQYycgu8OrvigwSPTFfVRcu0ECNYCWw+yzBp02Lw5paRqzzhUpfOgO2K38+WfFZuEz/0RPtam5g0OMg==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.8.0", - "@peculiar/asn1-x509": "^2.8.0", + "@peculiar/asn1-schema": "^2.9.4", + "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" } }, "node_modules/@peculiar/utils": { @@ -1627,7 +1657,6 @@ "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2100,13 +2129,13 @@ } }, "node_modules/@zkp2p/cash": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/@zkp2p/cash/-/cash-0.4.10.tgz", - "integrity": "sha512-mU/cXqehEHTtkCmaJ1ITPLQwE+Re5bFw3mCKBnKH6tkAxg6AtePVl8UABtjw2NRfCpwkkt0g8K5mXQcocbm4WA==", + "version": "0.4.11-rc.3", + "resolved": "https://registry.npmjs.org/@zkp2p/cash/-/cash-0.4.11-rc.3.tgz", + "integrity": "sha512-XOqQbHarik81C070ewCRfzF2Qvzj/TDRdluPgXsz29VCg44qSL9V1s/8NzPWTn9mPylJw20xe7v6+NcPPXzahA==", "license": "MIT", "dependencies": { "@relayprotocol/relay-sdk": "^7.0.1", - "@zkp2p/sdk": "0.12.1", + "@zkp2p/sdk": "0.12.2-rc.3", "zod": "^4.4.3" }, "engines": { @@ -2123,9 +2152,9 @@ } }, "node_modules/@zkp2p/contracts-v2": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@zkp2p/contracts-v2/-/contracts-v2-0.4.0.tgz", - "integrity": "sha512-wE4IfjRSUVfOiAULoh6eVUj5vExSlcMY6+VsRLOhGq+1q06uy/aS2lMYjzqoDAXibMpYPTVhsuy1MEB2jKGKqw==", + "version": "0.4.1-rc.9", + "resolved": "https://registry.npmjs.org/@zkp2p/contracts-v2/-/contracts-v2-0.4.1-rc.9.tgz", + "integrity": "sha512-ZT5L0TnXh7sNvYZTg5TlLBLJ24WiM6ENal1Uc9SucOFd7AIh+4/GetWM77Jy7TWTlHR1wBwjAixYe9GTfPaYdg==", "license": "MIT", "dependencies": { "abitype": "^1.0.0" @@ -2135,23 +2164,23 @@ } }, "node_modules/@zkp2p/indexer-schema": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@zkp2p/indexer-schema/-/indexer-schema-0.20.0.tgz", - "integrity": "sha512-EQsmFfp61hI0zzILYoh8aPzf+CGeduoiAQQ+FD27oIQBj5piKFqNQCfzhI14A7lBWtS69gXqjPuJJTo/BOaO3w==", + "version": "0.22.0-rc.3", + "resolved": "https://registry.npmjs.org/@zkp2p/indexer-schema/-/indexer-schema-0.22.0-rc.3.tgz", + "integrity": "sha512-3PAry2F3tlTi0dFjjaRx2BOvX87SP6JszLK6dlxo0pgB0fV9CF3JB7Q58jy4iwXe75CmTESTvqwnvkCzL/vPBQ==", "license": "MIT", "engines": { "node": ">=16" } }, "node_modules/@zkp2p/sdk": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@zkp2p/sdk/-/sdk-0.12.1.tgz", - "integrity": "sha512-pqt0jvYnzguRNB+ojvuZz6zfsCHZf+AfQ3UY40NEC/6QQWM+gco4op0aj69Hmtw8fkI1Py1QWAxKPezrW2iXOQ==", + "version": "0.12.2-rc.3", + "resolved": "https://registry.npmjs.org/@zkp2p/sdk/-/sdk-0.12.2-rc.3.tgz", + "integrity": "sha512-RE3h7wLMTo1l5ciaGr6iIXAH/E3nNMKH1a96s5auohPCaO9ke460XNUeRmQ+ZDGL5Ay6COmjTh1yGJUujUAA8A==", "license": "MIT", "dependencies": { - "@zkp2p/contracts-v2": "0.4.0", - "@zkp2p/indexer-schema": "0.20.0", - "@zkp2p/zkp2p-attestation": "2.0.0", + "@zkp2p/contracts-v2": "0.4.1-rc.9", + "@zkp2p/indexer-schema": "0.22.0-rc.3", + "@zkp2p/zkp2p-attestation": "3.0.1", "ethers": "^6.0.0", "ox": "^0.11.1" }, @@ -2169,9 +2198,9 @@ } }, "node_modules/@zkp2p/zkp2p-attestation": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@zkp2p/zkp2p-attestation/-/zkp2p-attestation-2.0.0.tgz", - "integrity": "sha512-m+HWDYTEW109xSqh0NWJFoWR0ZIoxJqQRguQltfr6RSkALBJFWv5WWDQrcPN0TiqTN2KdLI7BYQTDluZfjq2MA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@zkp2p/zkp2p-attestation/-/zkp2p-attestation-3.0.1.tgz", + "integrity": "sha512-f81RMhjA7UYy6Pp5t8fF5DOlBrDrZ/l4LKOW+sGRrYreF5G90+8X8Dtgx3yuh1pDICMJ5ybBVcj2pmV+LV9Dfw==", "dependencies": { "@peculiar/x509": "^1.14.0", "ethers": "^6.13.4" @@ -4743,9 +4772,9 @@ } }, "node_modules/pvutils": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", - "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", + "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", "license": "MIT", "engines": { "node": ">=16.0.0" diff --git a/package.json b/package.json index 23fe43e..31f05c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "peer-protocol-cli", - "version": "0.3.0", + "version": "0.4.0", "mcpName": "io.github.zkp2p/peer", "description": "Agent-first CLI and MCP server for the Peer (ZKP2P) protocol and Peer Cash", "bin": { @@ -77,8 +77,8 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.30.0", - "@zkp2p/cash": "^0.4.10", - "@zkp2p/sdk": "^0.12.1", + "@zkp2p/cash": "0.4.11-rc.3", + "@zkp2p/sdk": "0.12.2-rc.3", "commander": "^14.0.3", "viem": "^2.55.19", "zod": "^4.4.3" diff --git a/plugin.json b/plugin.json index e807005..7df1a29 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "peer", - "version": "0.3.0", + "version": "0.4.0", "description": "Operate the Peer protocol and prepare custody-separated Peer Cash transactions through one CLI and MCP server.", "author": { "name": "Peer", diff --git a/server.json b/server.json index 68a7bd5..f841a66 100644 --- a/server.json +++ b/server.json @@ -3,7 +3,7 @@ "name": "io.github.zkp2p/peer", "title": "Peer", "description": "Read Peer protocol, market, checkout, and Peer Cash data through one MCP server.", - "version": "0.3.0", + "version": "0.4.0", "websiteUrl": "https://agents.peer.xyz", "repository": { "url": "https://github.com/zkp2p/peer-cli", diff --git a/skills/peer-cash/SKILL.md b/skills/peer-cash/SKILL.md index a8fc308..e335202 100644 --- a/skills/peer-cash/SKILL.md +++ b/skills/peer-cash/SKILL.md @@ -14,7 +14,7 @@ broadcasts. Configure the host to run: ```bash -npx -y https://github.com/zkp2p/peer-cli/releases/download/v0.3.0/peer-protocol-cli-0.3.0.tgz mcp --profile cash +npx -y https://github.com/zkp2p/peer-cli/releases/download/v0.4.0/peer-protocol-cli-0.4.0.tgz mcp --profile cash ``` Keep optional `PEER_CASH_*` values in the host's secret or MCP configuration, @@ -36,9 +36,11 @@ without inspecting it and obtaining operator approval. purpose, and expected effect. Obtain explicit approval for that exact plan. 5. Have the host wallet submit each transaction in order and confirm the `createDeposit` receipt. -6. Call `peer_cash_finalize` with the confirmed transaction hash. If - `accessPolicyRequired` is true, prepare, approve, and submit the access-policy - transaction with the depositor wallet. +6. Call `peer_cash_finalize` with the confirmed transaction hash. For every + method in the prepare result's `accessPolicyPaymentMethods`, call + `peer_cash_prepare_access_policy` with the finalized `depositId` and that + exact `paymentMethod`, then approve, submit, and confirm the transaction with + the depositor wallet. 7. Persist the returned `depositId`; use `peer_cash_order` to resume. Use `peer_cash_orders` to list a maker's orders, diff --git a/src/commands/framework.ts b/src/commands/framework.ts index c9fe754..4077021 100644 --- a/src/commands/framework.ts +++ b/src/commands/framework.ts @@ -113,7 +113,7 @@ const GROUP_DESCRIPTIONS: Record = { oracle: 'Oracle helpers', pv: 'ProtocolViewer reads', indexer: 'Indexer reads', - stake: 'StakeVault and chargeback protection', + stake: 'StakeVault and dispute protection', guardian: 'Intent extension operations', }; diff --git a/src/commands/stake.ts b/src/commands/stake.ts index 88c981e..bcfdc8c 100644 --- a/src/commands/stake.ts +++ b/src/commands/stake.ts @@ -43,12 +43,12 @@ export const stakeDefinitions: CommandDefinition[] = [ const { client } = await context.getClient({ requireWallet: false }); const stakeOwner = await client.getStakeOwner(taker); const vault = client.getStakeVaultContract(); - const policy = client.getChargebackPolicyContract(); + const policy = client.getDisputeProtectionPolicyContract(); return client.indexer.getStakingState({ chainId: 8453, environment: context.config.env === 'staging' ? 'base_staging' : 'base', vaultAddress: vault.address, - chargebackPolicyAddress: policy.address, + disputeProtectionPolicyAddress: policy.address, taker, stakeOwner, }); @@ -63,7 +63,7 @@ export const stakeDefinitions: CommandDefinition[] = [ }, { path: ['stake', 'locked'], - description: 'Read stake locked behind active chargeback windows.', + description: 'Read stake locked behind active dispute windows.', readOnly: true, args: [addressArgument('owner', 'Stake owner address.')], handler: sdkReadHandler(['getLockedStake'], async (input) => [ensureAddress(input.owner, 'owner')]), @@ -111,7 +111,7 @@ export const stakeDefinitions: CommandDefinition[] = [ }, { path: ['stake', 'admissions-paused'], - description: 'Read whether chargebackable intent admissions are paused.', + description: 'Read whether dispute-protected intent admissions are paused.', readOnly: true, handler: sdkReadHandler(['getAdmissionsPaused'], async () => []), }, @@ -123,16 +123,18 @@ export const stakeDefinitions: CommandDefinition[] = [ handler: sdkReadHandler(['getRiskWindow'], async (input) => [ensureString(input.paymentMethodHash, 'paymentMethodHash')]), }, { - path: ['stake', 'chargeback-enabled'], - description: 'Read whether a deposit has chargeback coverage enabled.', + path: ['stake', 'dispute-protection-enabled'], + description: 'Read whether one deposit payment method has dispute protection enabled.', readOnly: true, args: [ addressArgument('escrow', 'Escrow address.'), { name: 'depositId', description: 'Numeric deposit ID.', schema: { type: 'string', description: 'Deposit ID.' }, optionFlags: ['--deposit-id '] }, + { name: 'paymentMethodHash', description: 'Payment method bytes32 hash.', schema: { type: 'string', description: 'Payment method hash.' }, optionFlags: ['--payment-method-hash '] }, ], - handler: sdkReadHandler(['isChargebackEnabled'], async (input) => [ + handler: sdkReadHandler(['isDisputeProtectionEnabled'], async (input) => [ ensureAddress(input.escrow, 'escrow'), asBigInt(input.depositId, 'depositId'), + ensureString(input.paymentMethodHash, 'paymentMethodHash'), ]), }, { @@ -244,28 +246,28 @@ export const stakeDefinitions: CommandDefinition[] = [ }, { path: ['stake', 'release-matured'], - description: 'Release one matured chargeback intent and unlock its stake cover.', + description: 'Release one matured protected intent and unlock its stake cover.', readOnly: false, requireWallet: true, args: [{ name: 'intentHash', description: 'Intent hash.', schema: { type: 'string', description: 'Intent hash.' }, optionFlags: ['--intent-hash '] }], - options: [{ name: 'policy', flags: '--policy
', description: 'Optional snapshotted chargeback policy address.', schema: { type: 'string', description: 'Chargeback policy address.' } }], - handler: sdkWriteHandler(['releaseMaturedChargebackIntent'], async (input) => ({ + options: [{ name: 'policy', flags: '--policy
', description: 'Optional snapshotted dispute-protection policy address.', schema: { type: 'string', description: 'Dispute-protection policy address.' } }], + handler: sdkWriteHandler(['releaseMaturedDisputeProtectionIntent'], async (input) => ({ intentHash: ensureString(input.intentHash, 'intentHash'), - ...(input.policy ? { chargebackPolicyAddress: ensureAddress(input.policy, 'policy') } : {}), + ...(input.policy ? { disputeProtectionPolicyAddress: ensureAddress(input.policy, 'policy') } : {}), })), }, { path: ['stake', 'release-matured-batch'], - description: 'Release multiple matured chargeback intents in one transaction.', + description: 'Release multiple matured protected intents in one transaction.', readOnly: false, requireWallet: true, args: [{ name: 'intentHashes', description: 'JSON array of intent hashes.', schema: { type: 'array', description: 'Intent hashes.' }, optionFlags: ['--intent-hashes '] }], options: [ - { name: 'policy', flags: '--policy
', description: 'Optional snapshotted chargeback policy address.', schema: { type: 'string', description: 'Chargeback policy address.' } }, + { name: 'policy', flags: '--policy
', description: 'Optional snapshotted dispute-protection policy address.', schema: { type: 'string', description: 'Dispute-protection policy address.' } }, ], - handler: sdkWriteHandler(['releaseMaturedChargebackIntents'], async (input) => ({ + handler: sdkWriteHandler(['releaseMaturedDisputeProtectionIntents'], async (input) => ({ intentHashes: parseJsonArray(input.intentHashes, 'intentHashes').map((hash, index) => ensureString(hash, `intentHashes[${index}]`)), - ...(input.policy ? { chargebackPolicyAddress: ensureAddress(input.policy, 'policy') } : {}), + ...(input.policy ? { disputeProtectionPolicyAddress: ensureAddress(input.policy, 'policy') } : {}), })), }, ]; diff --git a/src/mcp/cash.ts b/src/mcp/cash.ts index f9e033a..72d6689 100644 --- a/src/mcp/cash.ts +++ b/src/mcp/cash.ts @@ -207,6 +207,9 @@ const positiveInteger = z .regex(/^[1-9]\d*$/, 'Use a positive decimal integer in base units'); const address = z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Use an EVM address'); const hash = z.string().regex(/^0x[a-fA-F0-9]{64}$/, 'Use a transaction hash'); +const paymentMethod = z + .string() + .regex(/^0x[a-fA-F0-9]{64}$/, 'Use a payment method bytes32 hash'); const depositId = z .string() .regex(/^0x[a-fA-F0-9]{40}_[0-9]+$/, 'Use a composite Peer deposit id'); @@ -451,15 +454,18 @@ export function registerPeerCashTools( { title: 'Prepare an order access policy', description: - 'Prepare the unsigned verified-buyer access-policy transaction required for Venmo, Cash App, or PayPal orders after finalization.', - inputSchema: { depositId }, + 'Prepare one unsigned, method-scoped Peer Pay access-policy transaction required after finalizing a Venmo or PayPal order.', + inputSchema: { depositId, paymentMethod }, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, }, }, - ({ depositId: id }) => handleTool(() => client.prepareAccessPolicy(id)), + ({ depositId: id, paymentMethod: method }) => + handleTool(() => + client.prepareAccessPolicy(id, method as `0x${string}`), + ), ); server.registerTool( diff --git a/tests/cash-mcp.test.ts b/tests/cash-mcp.test.ts index c4faa78..d3251de 100644 --- a/tests/cash-mcp.test.ts +++ b/tests/cash-mcp.test.ts @@ -3,6 +3,7 @@ import { registerPeerCashTools } from '../src/mcp/cash.js'; const depositId = '0x1111111111111111111111111111111111111111_7'; const transactionHash = `0x${'ab'.repeat(32)}` as `0x${string}`; +const paymentMethod = `0x${'cd'.repeat(32)}` as `0x${string}`; function createHarness(includeWrites = false) { const registerTool = vi.fn(); @@ -103,6 +104,20 @@ describe('Peer Cash MCP tools', () => { expect(estimate.isError).not.toBe(true); }); + it('prepares access policy for the exact returned payment method', async () => { + const { client, handlers } = createHarness(true); + + await handlers.get('peer_cash_prepare_access_policy')!({ + depositId, + paymentMethod, + }); + + expect(client.prepareAccessPolicy).toHaveBeenCalledWith( + depositId, + paymentMethod, + ); + }); + it('exposes live source routing and analytics inputs without signer authority', async () => { const { client, handlers } = createHarness(); await handlers.get('peer_cash_fill_stats')!({}); diff --git a/tests/stake-commands.test.ts b/tests/stake-commands.test.ts index e7e4797..cf43e8e 100644 --- a/tests/stake-commands.test.ts +++ b/tests/stake-commands.test.ts @@ -6,6 +6,7 @@ import { createMockRuntime } from './helpers/mock-runtime.js'; const OWNER = '0x1111111111111111111111111111111111111111'; const TAKER = '0x2222222222222222222222222222222222222222'; const POLICY = '0x3333333333333333333333333333333333333333'; +const PAYMENT_METHOD = `0x${'44'.repeat(32)}`; function definition(path: string[]) { const result = commandDefinitions.find((entry) => entry.path.join(' ') === path.join(' ')); @@ -21,6 +22,8 @@ describe('staking and guardian commands', () => { expect(names.has('stake ensure-allowance')).toBe(true); expect(names.has('stake deposit')).toBe(true); expect(names.has('stake withdraw')).toBe(true); + expect(names.has('stake dispute-protection-enabled')).toBe(true); + expect(names.has('stake chargeback-enabled')).toBe(false); expect(names.has('stake release-matured-batch')).toBe(true); expect(names.has('guardian quote-extension')).toBe(true); expect(names.has('guardian extend-intent')).toBe(true); @@ -36,6 +39,11 @@ describe('staking and guardian commands', () => { expect(buildInputSchema(definition(['stake', 'deposit']))).toMatchObject({ required: ['amount'], }); + expect( + buildInputSchema(definition(['stake', 'dispute-protection-enabled'])), + ).toMatchObject({ + required: ['escrow', 'depositId', 'paymentMethodHash'], + }); expect(buildInputSchema(definition(['guardian', 'quote-extension']))).toMatchObject({ required: ['intentAmount', 'additionalSeconds'], }); @@ -49,7 +57,7 @@ describe('staking and guardian commands', () => { behaviors: { getStakeOwner: () => OWNER, getStakeVaultContract: () => ({ address: TAKER, stakeToken: OWNER, abi: [] }), - getChargebackPolicyContract: () => ({ address: POLICY, abi: [] }), + getDisputeProtectionPolicyContract: () => ({ address: POLICY, abi: [] }), 'indexer.getStakingState': (params: unknown) => ({ params, freshness: { indexedBlockNumber: '99' } }), }, }); @@ -66,12 +74,32 @@ describe('staking and guardian commands', () => { chainId: 8453, environment: 'base', vaultAddress: TAKER, - chargebackPolicyAddress: POLICY, + disputeProtectionPolicyAddress: POLICY, taker: TAKER, stakeOwner: OWNER, }); }); + it('reads method-scoped dispute protection with the current SDK call', async () => { + const runtime = createMockRuntime({ + behaviors: { isDisputeProtectionEnabled: () => true }, + }); + + const result = await executeDefinition( + definition(['stake', 'dispute-protection-enabled']), + { escrow: OWNER, depositId: '7', paymentMethodHash: PAYMENT_METHOD }, + {}, + runtime.deps, + ); + + expect(result).toMatchObject({ ok: true, data: true }); + expect( + runtime.calls.find( + (entry) => entry.path === 'isDisputeProtectionEnabled', + )?.args, + ).toEqual([OWNER, 7n, PAYMENT_METHOD]); + }); + it('previews stake and guardian writes until --yes is explicit', async () => { const stakeRuntime = createMockRuntime(); const stake = await executeDefinition(