Skip to content

Commit 497287d

Browse files
committed
docs: add Sub Rosa agent skill
1 parent 8b4e316 commit 497287d

4 files changed

Lines changed: 347 additions & 0 deletions

File tree

skills/sub-rosa/SKILL.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
---
2+
name: sub-rosa
3+
description: Integrate Sub Rosa sealed coordination into Stellar applications with @sub-rosa/sdk. Use when building sealed-bid asset auctions, confidential proposal or procurement rounds, Drand-timed reveal, SAC escrow and atomic lot settlement, permissionless round keepers, Core v2 receipts, or a Sub Rosa testnet pilot. Also use when choosing between Auction and ReceiptOnly, wiring Stellar wallets, or reviewing a Sub Rosa lifecycle and security boundary.
4+
---
5+
6+
# Sub Rosa
7+
8+
Build or review an integration against Sub Rosa Core v2. Prefer the public
9+
`@sub-rosa/sdk` templates over custom contract calls. Keep the current testnet
10+
and audit boundary explicit.
11+
12+
## Integration workflow
13+
14+
1. Inspect the application before changing it:
15+
- Identify its package manager, TypeScript/runtime version, Stellar wallet
16+
adapter, RPC configuration, asset contracts, and transaction-signing path.
17+
- Check the installed or current npm version of `@sub-rosa/sdk`; do not invent
18+
exports from an older version.
19+
- Read [references/integration.md](references/integration.md) for the concrete
20+
SDK flow and [references/security-and-lifecycle.md](references/security-and-lifecycle.md)
21+
before implementing value-moving code.
22+
23+
2. Choose exactly one reviewed mode:
24+
25+
| Requirement | Mode | Template |
26+
| --- | --- | --- |
27+
| Exchange a Stellar payment asset for a Stellar lot asset | `Auction` | `createAssetAuctionRound` |
28+
| Collect confidential proposals without asset custody | `ReceiptOnly` | `createSealedProposalRound` |
29+
30+
Use `Auction` only when atomic settlement is economically necessary. Use
31+
`ReceiptOnly` for procurement, RFP, judging, or design-partner flows where
32+
the organizer chooses off-chain. Do not add a custom settlement callback for
33+
a new vertical; express it as typed metadata over one of these modes.
34+
35+
3. Install the single partner-facing package:
36+
37+
```bash
38+
npm install @sub-rosa/sdk
39+
```
40+
41+
Import templates, Drand helpers, tlock helpers, receipt verification, and
42+
generated contract bindings from `@sub-rosa/sdk`. Install
43+
`@sub-rosa/tlock` or `@sub-rosa/round-bindings` directly only for low-level
44+
protocol work.
45+
46+
4. Pin the deployment tuple together:
47+
- RPC URL
48+
- network passphrase
49+
- round contract ID
50+
- expected WASM hash in deployment policy or configuration
51+
52+
Never combine a contract ID from one network with another network's RPC or
53+
passphrase. Let `SubRosaClient` perform its network and contract precheck
54+
before the first operation.
55+
56+
5. Plan the reveal window before creating the round:
57+
58+
```text
59+
now < commitDeadline < time(drandRound) < revealDeadline
60+
```
61+
62+
Derive the Drand round with `roundInSeconds(quicknet(), delaySeconds)`.
63+
Leave enough time after Drand publication for retry-safe, per-participant
64+
reveal transactions. Treat deadlines as Unix timestamps, not ledger numbers.
65+
66+
6. Create and submit through a high-level template:
67+
- Auction: custody the lot at creation, use one public `fixedEscrow` for all
68+
bidders, call `sealAssetBid`, then `submitV2` with escrow exactly equal to
69+
`fixedEscrow`.
70+
- ReceiptOnly: call `sealProposal`, then `submitV2` with `escrow: 0n`.
71+
- Add `eligibleParticipants` only when the partner needs a public allowlist.
72+
- Use integer base units for all Stellar asset amounts.
73+
74+
7. Preflight every wallet mutation before requesting a signature. Use the
75+
matching `preflight*V2` method, surface typed errors and fee/resource
76+
estimates, and stop on failure. Do not ask the user to sign a transaction
77+
that failed simulation.
78+
79+
8. Run the permissionless lifecycle in order:
80+
81+
```text
82+
Open -> openRevealV2 -> Revealing -> revealV2(each participant)
83+
-> clearV2 -> Cleared -> settleV2(Auction) -> Settled
84+
```
85+
86+
`ReceiptOnly` completes during `clearV2`. Reveal participants independently
87+
and skip already-revealed entries so retries are safe. Run at least one
88+
keeper and monitor incomplete reveal counts; permissionless does not mean
89+
automatic.
90+
91+
9. Export the Core v2 receipt with `exportReceiptV2`, verify it with
92+
`verifyReceiptV2`, and persist the canonical `serializeReceiptV2` output plus
93+
transaction hashes. Explain that offline verification checks internal
94+
consistency, while ledger provenance still requires querying the pinned
95+
contract and network.
96+
97+
10. Verify the integration at the appropriate depth:
98+
- Unit-test mode selection, base-unit conversion, payload encoding, and
99+
preflight failures.
100+
- Test an end-to-end testnet round with multiple independent participants.
101+
- Exercise duplicate lifecycle calls and the grace-period `voidV2` recovery
102+
path.
103+
- For auctions, reconcile seller payment, winner lot transfer, surplus, and
104+
losing-bidder refunds.
105+
106+
## Required safety language
107+
108+
Sub Rosa Core v2 has settled testnet proofs but no independent funds-handling
109+
audit. Describe it as testnet pilot infrastructure. Do not claim that the SDK,
110+
the hosted UI, or the legacy v1 mainnet smoke proves Core v2 is production-safe.
111+
Use participant and value caps until the contract deployment is independently
112+
reviewed.
113+
114+
## Sources
115+
116+
- SDK and protocol source: https://github.com/karagozemin/Sub-Rosa/tree/feat/core-v2
117+
- Integration docs: https://sub-rosa-web.vercel.app/#/docs
118+
- Published package: https://www.npmjs.com/package/@sub-rosa/sdk
119+
- Stellar smart contract docs: https://developers.stellar.org/docs/build/smart-contracts
120+
- Drand quicknet: https://docs.drand.love/dev-guide/developer/quicknet

skills/sub-rosa/agents/openai.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface:
2+
display_name: "Sub Rosa"
3+
short_description: "Integrate sealed Stellar auctions and proposals"
4+
default_prompt: "Use the Sub Rosa SDK to design, implement, or review a sealed auction or confidential proposal flow on Stellar."
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Sub Rosa Core v2 integration
2+
3+
Load this reference when implementing the SDK flow. Keep secrets server-side
4+
unless a browser wallet owns the signing step.
5+
6+
## Current testnet deployment
7+
8+
```text
9+
RPC: https://soroban-testnet.stellar.org
10+
Network passphrase: Test SDF Network ; September 2015
11+
Core v2 contract: CCOVGOQQZJKZ2R55GRWBLTJTGBAMSHXZVN3ICPG3WRVMLMM6RHISC5OV
12+
WASM SHA-256: 2c7bc6b4c91940ac185df38a3d0a8532b555140d818df94f03f894e5952ebf42
13+
Drand: quicknet / bls-unchained-g1-rfc9380
14+
```
15+
16+
Treat these as one deployment tuple. Reconfirm them against the project's
17+
current documentation before a new pilot.
18+
19+
## Configure a client
20+
21+
```ts
22+
import { SubRosaClient } from "@sub-rosa/sdk";
23+
24+
const client = new SubRosaClient({
25+
rpcUrl: "https://soroban-testnet.stellar.org",
26+
networkPassphrase: "Test SDF Network ; September 2015",
27+
contractId: process.env.SUB_ROSA_CONTRACT_ID!,
28+
secretKey: process.env.STELLAR_SECRET,
29+
});
30+
```
31+
32+
Omit `secretKey` for read-only clients. Browser applications may provide the
33+
generated `RoundContract` with wallet-backed `signTransaction` and
34+
`signAuthEntry` callbacks instead of exposing a secret.
35+
36+
## Create an asset auction
37+
38+
```ts
39+
import {
40+
createAssetAuctionRound,
41+
generateAuditorKeypair,
42+
quicknet,
43+
roundInSeconds,
44+
sealAssetBid,
45+
} from "@sub-rosa/sdk";
46+
47+
const drand = quicknet();
48+
const chain = await drand.chain().info();
49+
const revealRound = await roundInSeconds(drand, 300);
50+
const revealAt = Number(chain.genesis_time) + Number(chain.period) * revealRound;
51+
const auditor = generateAuditorKeypair();
52+
53+
const roundId = await createAssetAuctionRound(sellerClient, {
54+
itemRef, // 32-byte stable item reference
55+
paymentAsset: usdcSac,
56+
lotAsset: collectibleSac,
57+
lotAmount: 1n,
58+
fixedEscrow: 1_000_000_000n,
59+
revealRound,
60+
commitDeadline: revealAt - 15,
61+
revealDeadline: revealAt + 300,
62+
auditorPubkey: auditor.publicKey,
63+
maxParticipants: 10,
64+
eligibleParticipants: collectors, // omit for an open round
65+
});
66+
67+
const sealed = await sealAssetBid({
68+
round: Number(revealRound),
69+
drand,
70+
amount: 700_000_000n,
71+
payload: new TextEncoder().encode(JSON.stringify({ termsVersion: 1 })),
72+
});
73+
74+
await bidderClient.submitV2({
75+
roundId,
76+
sealed,
77+
escrow: 1_000_000_000n,
78+
});
79+
```
80+
81+
The seller authorizes lot custody at creation. Every bidder locks the same
82+
`fixedEscrow`; the private bid must be less than or equal to it. Settlement
83+
atomically transfers the winning amount and lot, refunds the winner's surplus,
84+
and refunds losing bidders.
85+
86+
## Create a sealed proposal round
87+
88+
```ts
89+
import { createSealedProposalRound, sealProposal } from "@sub-rosa/sdk";
90+
91+
const roundId = await createSealedProposalRound(organizerClient, {
92+
itemRef,
93+
revealRound,
94+
commitDeadline,
95+
revealDeadline,
96+
auditorPubkey: auditor.publicKey,
97+
maxParticipants: 12,
98+
eligibleParticipants: providers,
99+
});
100+
101+
const sealed = await sealProposal({
102+
round: Number(revealRound),
103+
drand,
104+
price: 25_000_000_000n,
105+
proposal: {
106+
timelineDays: 14,
107+
approach: "Manual review, fuzzing, and remediation report",
108+
metadata: { teamSize: "3", region: "EU" },
109+
},
110+
});
111+
112+
await providerClient.submitV2({ roundId, sealed, escrow: 0n });
113+
```
114+
115+
The organizer compares revealed proposals and chooses off-chain. Do not imply
116+
that `LowestBid` makes the business decision; ReceiptOnly produces a canonical
117+
submission/reveal receipt and moves no assets.
118+
119+
## Advance the lifecycle
120+
121+
```ts
122+
import { fetchRoundSignature, openPayload } from "@sub-rosa/sdk";
123+
124+
const round = await keeperClient.getRoundV2(roundId);
125+
const signature = await fetchRoundSignature(drand, Number(round.reveal_round));
126+
await keeperClient.openRevealV2(roundId, signature);
127+
128+
for (const bidder of await keeperClient.getBiddersV2(roundId)) {
129+
const state = await keeperClient.getSubmissionV2(roundId, bidder);
130+
if (state.revealed_envelope) continue;
131+
132+
const seal = await keeperClient.getSealV2(roundId, bidder);
133+
if (!seal) continue;
134+
const envelope = await openPayload(seal.ciphertext, drand);
135+
await keeperClient.revealV2({ roundId, bidder, envelope });
136+
}
137+
138+
await keeperClient.clearV2(roundId); // only after revealDeadline
139+
const finalRound = await keeperClient.getRoundV2(roundId);
140+
if (finalRound.status.tag === "Cleared" && finalRound.mode.tag === "Auction") {
141+
await keeperClient.settleV2(roundId);
142+
}
143+
```
144+
145+
Use the corresponding `preflightOpenRevealV2`, `preflightRevealV2`,
146+
`preflightClearV2`, and `preflightSettleV2` before wallet-backed calls.
147+
148+
## Verify a receipt
149+
150+
```ts
151+
import { serializeReceiptV2, verifyReceiptV2 } from "@sub-rosa/sdk";
152+
153+
const receipt = await reader.exportReceiptV2(roundId);
154+
const result = verifyReceiptV2(receipt);
155+
if (!result.valid) throw new Error(JSON.stringify(result.issues));
156+
157+
const canonicalJson = serializeReceiptV2(receipt);
158+
```
159+
160+
Store `canonicalJson`, round ID, network, contract ID, and transaction hashes.
161+
Requery the live contract when ledger provenance or receipt freshness matters.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Security and lifecycle checks
2+
3+
Load this reference for design review, test planning, incident handling, or any
4+
funds-handling integration.
5+
6+
## Invariants
7+
8+
- Bind ciphertext to the intended Drand round and canonical payload envelope.
9+
- Use `now < commitDeadline < time(R) < revealDeadline`.
10+
- Use the same non-zero `fixedEscrow` for every Auction bidder.
11+
- Require private bid amount `<= fixedEscrow`.
12+
- Require `escrow: 0n` and no settlement assets for ReceiptOnly.
13+
- Cap participants at the contract-supported limit; partner templates default
14+
to bounded cohorts and reject invalid values before RPC.
15+
- Treat the public eligibility list as an allowlist, not private identity, KYC,
16+
or reputation.
17+
- Pin RPC, passphrase, contract ID, and reviewed WASM hash as one deployment.
18+
19+
## Permissionless does not mean automatic
20+
21+
Any account may advance the round after Drand publishes `R`, but an external
22+
caller must still do so. Run at least one keeper and alert on:
23+
24+
- Drand round published but reveal not opened;
25+
- unrevealed participants after `openRevealV2`;
26+
- reveal deadline passed but round not cleared;
27+
- cleared Auction not settled;
28+
- grace period reached but recovery not executed.
29+
30+
Reveals are separate bounded transactions. One failed or malformed submission
31+
must not block processing of other participants. Retry by reading durable state
32+
and skipping completed actions.
33+
34+
## Recovery
35+
36+
Use `voidV2` only when the contract's grace path permits it. Preflight first,
37+
then verify that Auction escrow and lot custody are returned according to the
38+
round state. Preserve the void receipt and transaction hashes.
39+
40+
Do not create an operator-only emergency reveal or settlement path. The
41+
operator configures the round but should not gain early decryption or exclusive
42+
lifecycle authority.
43+
44+
## Receipt boundary
45+
46+
`verifyReceiptV2` recomputes canonical payload commitments and deterministic
47+
winner selection from the receipt. It does not connect to Stellar and therefore
48+
cannot prove that an exporter copied current ledger state honestly. For higher
49+
assurance:
50+
51+
1. Export after terminal settlement or void.
52+
2. Query the pinned contract and network directly.
53+
3. Export independently from more than one client and compare.
54+
4. Store transaction hashes with the canonical receipt.
55+
56+
## Current assurance statement
57+
58+
Core v2 has settled testnet proofs. It has not received an independent
59+
funds-handling audit. The legacy v1 mainnet settlement is protocol evidence,
60+
not a Core v2 production deployment. Keep pilots on testnet with explicit
61+
participant and value caps until deployment review, operational monitoring,
62+
and an independent audit are complete.

0 commit comments

Comments
 (0)