Repository navigation
004-02: Stake2Pay Plugin (House of Stake NEAR Staking) - #36
Merged
Merged
Conversation
…-02) Implements SubscriptionContract against the HoS staking contract via read-only JSON-RPC view calls; the wallet does all writes, so the plugin has no secrets (config-only registration in bos.config.json). - client.ts: minimal fetch-based view-call helper (base64 args, 15s timeout, typed error messages) - chain.ts: Zod schemas for on-chain JSON (product, price, subscription, lock, config, storage balance) - service.ts: chain -> contract mapping; listPlans (60s catalog cache, filters to active recurring prices), getSubscription (status derived from subscription + lock state: pending_unstake vs ended), wallet intents for lock / cancel_subscription / resume_subscription / update_subscription with storage_deposit auto-included when needed, range validation via BigInt - index.ts: Exit/Cause-based mapping of tagged service errors to typed oRPC errors (NOT_FOUND / BAD_REQUEST / SERVICE_UNAVAILABLE) - tests: 27 schema + 24 service unit tests (fixture chain JSON, fake RPC client) and 7 live read-only integration tests against hos-e2e-0601144939.testnet (skippable via SKIP_HOS_TESTNET=1) Closes #29 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FdKukDnRTrshKqkQ8JXwVj
This was referenced Jul 14, 2026
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #29. Part of Epic 004 (#27). Depends on #35 (merged).
What
plugins/stake2pay/now fully implementsSubscriptionContractagainst the House of Stake staking contract — a TypeScript port of the chain-facing half of nearai/chat-api PR #275, adapted to the aggregator's wallet-intent model. No secrets: all chain access is read-only JSON-RPC view calls; the user's wallet does all writes. Registered config-only inbos.config.json(plugins.stake2pay, nosecretsarray).How it maps chain state
listPlans←get_product+get_priceviews, filtered toActive+Recurring, with a 60s in-memory catalog cache. Range plans:minAmount= priceamount,maxAmount=metadata.max_amount.getSubscription←get_subscription_for_price+get_lock(last_lock_id)(never cached). Status derivation: chainActivewithin the period maps toactive/cancel_at_period_end; otherwise the lock decides — not-yet-withdrawn →pending_unstake, withdrawn/absent →ended;null→none. Deferred plan changes (pending_update) surface inmetadata.createSubscription→ multi-actionwallet_intent: auto-includesstorage_depositwhen the payer is unregistered (or when the contract'sper_lock_storage_stakerequires a top-up, read fromget_config), thenlockwith{price_id, duration_ns: null}and the chosen stake as deposit. Stake validated against the plan range via BigInt before the wallet ever opens.cancel/resume→ 1-yoctocancel_subscription/resume_subscriptionintents addressed byproduct_id(the contract keys lifecycle ops by product, not price — resolved from the live subscription).changePlan→update_subscriptionintent attaching the stake delta for increases (computed from the current lock) or 1 yocto for decreases (which the contract defers to the billing boundary).RPC failures and timeouts surface as typed oRPC errors (
SERVICE_UNAVAILABLE), unknown/non-recurring plans asNOT_FOUND, out-of-range amounts asBAD_REQUEST— mapped from tagged Effect errors viaExit/Cause, no message sniffing.Verification
hos-e2e-0601144939.testnet(skippable withSKIP_HOS_TESTNET=1; CI doesn't run plugin tests).bun run devboots andGET /api/subscriptions/plansreturns the seeded testnet tiers with correct NEAR ranges (Starter 1–10, Basic 10–40, Pro 40–400).bun run typecheckandbiome checkclean on all changed files.Chain shapes were verified against the live testnet contract (
get_product,get_price,get_subscription_for_price,storage_balance_bounds,get_config) and thefeat/stake-daobranch'sstaking-contract/docs/API.md+types.rs, not just the chat-api port.Still manual (per ticket)
One wallet-signed
lockagainst testnet to confirm end-to-end signability — planned alongside the 004-04 UI work, since the intent consumer is the UI's near-kit signer.🤖 Generated with Claude Code
https://claude.ai/code/session_01FdKukDnRTrshKqkQ8JXwVj