Skip to content

crinkl-protocol/campaigns

Repository files navigation

Crinkl Campaigns

Anchor program for the Crinkl campaign settlement GCD.

This public repository backs the crinkl-protocol/campaigns repo. It is intentionally separate from crinkl-onchain-processor: the existing processor publishes reward commitment roots, while this program is the current GCD-only campaign settlement commitment surface.

Crinkl Campaigns is the product-facing on-chain lane name. The current implementation does not yet implement full campaign operations. It freezes campaign rules and anchors settlement roots so the public can prove that Crinkl did not silently change the campaign rule after the fact, did not publish a settlement root detached from that rule, did not expose private buyer data on-chain, and did not let random actors mutate the record.

Plan Anchor

Canonical plan:

/home/azureuser/crinkl-knowledge-private/pages/analyses/campaign-settlement-gcd-program-plan-2026-05-16.md

Current implementation scope:

CampaignRuleV1 commitment
-> CampaignEpochV1 epochId + ruleSetHash
-> CampaignSettlementLeafV1 root
-> CAMPAIGN_SETTLEMENT_COMMITTED public anchor

Current Scope

The program exposes only:

  • initialize_config
  • rotate_authority
  • publish_campaign_commitment
  • commit_settlement_batch

It stores only:

  • ProgramConfig
  • CampaignCommitment
  • SettlementBatchCommitment

It deliberately does not implement:

  • permissionless campaign creation policy
  • CRINKL-token-holder campaign creation gates
  • funding deposits or escrow
  • SPL token transfers
  • FIFO promoter queues
  • per-conversion accounts
  • reward claiming
  • campaign-specific Spend Tokens
  • raw receipt, wallet, buyer, OCR, or raw Spend Token data on-chain

The on-chain account data stores hash commitments only. Campaign and settlement records now bind:

  • campaign_id_hash
  • epoch_id_hash
  • rule_set_hash
  • campaign_params_hash
  • settlement root and payout totals

The raw campaignId, epochId, ruleSetHash, campaignParamsHash, authority identity, and transaction reference remain recoverable through the public system-stream event history for CAMPAIGN_SETTLEMENT_COMMITTED.

The fixture layer now includes the required authority mapping:

Solana ProgramConfig.authority
-> System-Stream Authority Registry authorityId
-> signed CAMPAIGN_SETTLEMENT_COMMITTED event
-> Solana txRef anchor

The program signer is still checked on-chain. The System-Stream authority is checked off-chain by replaying the authority registry at committedAt and verifying the settlement event signature.

Fixture Harness

The Phase 0 fixture harness freezes the current eight launch Brand Boost campaigns as parameterized GCD examples.

Run:

pnpm gcd:fixtures

Outputs:

target/campaign-gcd-fixtures.json
target/campaign-gcd-e2e-report.md

The Markdown report states in plain business language what each test proves.

The generated fixtures use the frozen GCD shape:

CampaignRuleV1
-> CampaignEpochV1
-> campaign-defined runtime profile proof when required
-> CampaignSettlementLeafV1
-> CAMPAIGN_SETTLEMENT_COMMITTED metadata
-> System-Stream authority mapping

Settlement leaves include epochId and ruleSetHash, use SHA-256(0x00 || RFC8785_canonicalize(leaf)), and produce raw lowercase-hex settlement roots for the public event payload. The current launch Brand Boost leaves also bind a BOOST_LOCAL_AREA_MATCHING settlement-binding hash because those fixtures declare a campaign-defined runtime matching profile.

scripts/build-gcd-fixtures.mjs writes a deterministic fixture-only System-Stream chain to target/campaign-gcd-fixtures.json: one AUTHORITY_REGISTERED event followed by one signed CAMPAIGN_SETTLEMENT_COMMITTED event per launch campaign. During local-validator tests, CAMPAIGN_GCD_SOLANA_AUTHORITY is set to the provider wallet so the authority mapping binds the actual local Solana signer.

Validation

Useful checks:

pnpm install
pnpm gcd:fixtures
pnpm verify:gcd
pnpm ci:gcd
pnpm guard:security-coverage
pnpm guard:verifier-readiness
pnpm security:gcd
pnpm build
pnpm test
pnpm test:mollusk
pnpm test:trident:smoke
pnpm test:trident:audit
pnpm test:xray
pnpm devnet:verifier-binding

package.json pins pnpm@10.17.1 through Corepack so the GCD gate does not drift to a newer pnpm shim on this host.

pnpm test runs the Anchor local-validator E2E suite and appends plain business-language evidence to target/campaign-gcd-e2e-report.md.

pnpm test:mollusk builds the SBF program, loads campaign_settlement.so into Mollusk, and runs deterministic instruction-level security checks without starting a validator. The test output includes business-language Business check: lines for each security case.

pnpm test:trident:smoke builds the SBF program and runs a bounded guided Trident fuzz smoke with a fixed master seed. It exercises successful campaign/settlement commitments, duplicate PDA rejection, malformed campaign inputs, mismatched settlement rejection, authority rotation, and private-marker exclusion.

pnpm test:trident:audit runs the same GCD-only Trident target over multiple fixed seeds with more iterations and writes retained per-seed logs, metrics JSON, regression JSON, seeds, and counterexample files under /mnt/worktrees/crinkl-campaign-settlement-trident-artifacts/audit/<run-id>.

pnpm test:xray runs the open-source Sec3 X-Ray container against programs/campaign-settlement and writes reports/logs under /mnt/worktrees/crinkl-campaign-settlement-xray-report by default.

pnpm ci:gcd is the GitHub-compatible gate: fixture generation, GCD scope guard, formatting check for repo docs/scripts/workflows/tests, Rust format/check, and TypeScript typecheck. It avoids requiring the Anchor CLI so public CI can validate the GCD surface without local Solana tooling.

pnpm guard:gcd-scope checks that program source stays commitment-only, that private-data markers do not enter program accounts, and that Anchor, declare_id!, Trident config, and the Trident type shim all point at the same program id.

pnpm guard:security-coverage checks security/gcd-coverage-manifest.json against the actual Anchor program surface. If an instruction, account field, event, error, or guarded source fingerprint changes, the build fails until the manifest and targeted Anchor/Mollusk/Trident/X-Ray evidence are updated.

pnpm guard:verifier-readiness checks the generated verifier-key policy. It passes for the fixture/devnet lane only when productionReady: false; if a future policy claims production readiness, it requires CAMPAIGN_GCD_VERIFIER_READINESS_MANIFEST and validates custody, approval, publication, emergency revoke, and audit evidence references.

pnpm security:gcd is the current full local gate: fixture generation, Rust format/check, Rust lib tests, TypeScript typecheck, Anchor local-validator E2E, Mollusk, and Trident smoke.

pnpm devnet:gcd-replay publishes or reuses campaign commitments and commits one fresh settlement root for each of the eight launch Brand Boost campaigns on devnet. It writes target/campaign-gcd-devnet-replay.json and target/campaign-gcd-devnet-replay.md.

pnpm devnet:verifier-binding reads the devnet proof or replay artifact, rebuilds the signed System-Stream events, verifies the signed verifier-key registry and active-key window, verifies each verifier approval signature, checks the settlement leaf/root binding, confirms the devnet transaction referenced by txRef, and fetches the on-chain accounts to prove their stored hashes match the frozen rule and settlement root. It writes target/campaign-gcd-verifier-binding-proof.json and target/campaign-gcd-verifier-binding-proof.md.

Open-source X-Ray is wired as a GitHub Actions lane in .github/workflows/xray-open-source.yml. It uses the public ghcr.io/sec3-product/x-ray:latest container, scans programs/campaign-settlement, and uploads xray-report/ as a workflow artifact. It does not require SEC3_TOKEN.

On this host, keep heavy build outputs under /mnt; the current local setup uses /mnt/worktrees/cargo-home-anchor for the pinned Anchor CLI/tool cache, /mnt/worktrees/trident-cli-0.12.0/bin/trident for the isolated Trident CLI, /mnt/worktrees/crinkl-campaign-settlement-trident-target for Trident target output, and a workspace target symlink into /mnt/worktrees/crinkl-campaign-settlement-workspace-target.

Security Stress Standard

The GCD security ladder is:

  1. Anchor local-validator E2E for the actual public commitment flow.
  2. Mollusk for deterministic low-level SVM instruction tests and compute bounds.
  3. Trident for guided stateful fuzzing over instruction sequences and boundary inputs.
  4. Open-source X-Ray for static-analysis coverage of structural Solana mistakes.

Mollusk is implemented in programs/campaign-settlement/tests/gcd_security_mollusk.rs. It covers:

  • valid GCD config, campaign, and settlement commitment chain
  • authority rotation and old-authority rejection
  • default authority rejection
  • zero campaign parameter hash rejection
  • invalid campaign window rejection
  • wrong settlement authority rejection
  • mismatched campaign epoch rejection
  • mismatched rule-set rejection
  • System-Stream authority mapping and event-signature verification
  • empty settlement batch rejection
  • zero settlement root rejection
  • mismatched campaign params rejection
  • duplicate campaign PDA rejection
  • duplicate settlement batch PDA rejection
  • public account scan for private markers such as wallet, receipt, and buyer text

Trident smoke is implemented in trident-tests/gcd_smoke/test_fuzz.rs and run through scripts/run-trident-smoke.sh. It uses Trident 0.12.0 outside the core program lockfile and defaults to this fixed seed:

000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

The smoke flows cover:

  • successful config initialization
  • successful publish and settlement for matching commitments
  • duplicate campaign PDA rejection
  • invalid campaign window rejection
  • mismatched settlement campaign hash rejection with the rule-set PDA binding in the instruction path
  • authority rotation, old-authority rejection, and new-authority success
  • public account scan for private markers such as wallet, receipt, and buyer text

The audit command uses the same target with longer default coverage:

TRIDENT_GCD_AUDIT_ITERATIONS=128
TRIDENT_GCD_AUDIT_FLOW_CALLS=12

Override TRIDENT_GCD_AUDIT_SEEDS with whitespace-separated 64-character hex seeds to replay or extend an audit run. Any failing seed is copied into the run's counterexamples/ directory with its Trident log.

Mollusk, Trident, and X-Ray are security layers, not campaign semantics. They must test only the current GCD surface: config authority, campaign commitments, settlement batch commitments, canonical PDAs, duplicate rejection, schema/hash/window validation, and private-data exclusion.

security/gcd-coverage-manifest.json is the build-enforced security coverage contract. It records the current public program surface and maps each security requirement to concrete evidence in the Anchor E2E tests, Mollusk tests, Trident smoke, GCD scope guard, and X-Ray workflow. The CI-compatible pnpm ci:gcd gate runs pnpm guard:security-coverage, so adding or changing program functionality now requires an explicit coverage update instead of relying on generic tests.

The longer Trident audit command is local/manual for now; CI scheduling and regression comparison are still future work. Keep Trident isolated until version compatibility remains proven over longer runs. Current Trident docs target newer Rust/Solana SDK versions than the local SBF Cargo path, so install/cache it under /mnt and do not force it into the core program lockfile. Open-source X-Ray findings must be triaged against the GCD-only scope before changing code. The token-gated Sec3 Pro action is optional only; do not make paid/token-gated tooling required for this GCD lane.

Program ID

Current devnet-proof program id:

3rbQYVNFGXvyBNyP9ZnCHVZXmT8xG6VfXU3hhZ2re1eG

No deploy keypair is committed. The local devnet-proof keypair lives under ignored target/deploy/ on this host.

Devnet Proof

The devnet milestone is intentionally narrow: publish one campaign commitment and one settlement root, then write the real transaction evidence back into the GCD report.

Run:

PATH=/mnt/worktrees/cargo-home-anchor/bin:$PATH anchor build
PATH=/mnt/worktrees/cargo-home-anchor/bin:$PATH anchor deploy --provider.cluster devnet --provider.wallet ~/.config/solana/id.json
ANCHOR_PROVIDER_URL=https://api.devnet.solana.com ANCHOR_WALLET=~/.config/solana/id.json pnpm devnet:gcd-proof

Outputs:

target/campaign-gcd-devnet-proof.json
target/campaign-gcd-devnet-proof.md

The proof command does not add marketplace semantics. It only proves that the frozen campaign-rule commitment and settlement-root commitment can be anchored on devnet by the mapped authority, with a System-Stream settlement event bound to the real devnet txRef.

After pnpm devnet:gcd-proof or pnpm devnet:gcd-replay, run:

ANCHOR_PROVIDER_URL=https://api.devnet.solana.com pnpm devnet:verifier-binding

Outputs:

target/campaign-gcd-verifier-binding-proof.json
target/campaign-gcd-verifier-binding-proof.md

This command does not publish new transactions. It proves the evidence layer: signed verifier-key registry -> active verifier key -> verifier approval signature -> campaign-defined matching proof when required -> settlement leaf -> settlement root -> signed System-Stream settlement event -> real devnet txRef -> on-chain account hashes. The current launch Brand Boost fixtures declare the BOOST_LOCAL_AREA_MATCHING runtime profile, so their verifier-binding proof requires the hash-bound matching proof. Campaigns that do not declare a runtime matching profile still report matching/FIFO proof as not required.

The verifier-key registry is evidence-layer infrastructure. It records verifier key ids, public keys, signature algorithm, validity windows, predecessor key, status, registry event hash, and registry event signature. A retired key must close before the active key becomes valid, and verifier approvals must reference the active key registry event at approvedAt.

Production key operations are formalized in docs/VERIFIER_KEY_OPERATIONS.md. The current generated policy explicitly sets productionReady: false; fixture/devnet evidence is valid GCD evidence, but it is not a claim that production key custody is live.

The production readiness manifest shape is documented in docs/VERIFIER_PRODUCTION_READINESS_MANIFEST.example.json. It records evidence references only, not secrets.

Current verifier-key policy parameters:

Parameter Current Rule
Registry event signer System-Stream authority
Registry event chain Strict prevHash chain with a checked head hash
Allowed approval signature algorithm ed25519-sha256-canonical-json
Max active keys per verifier 1
Active key overlap 0 seconds
Retired/revoked key window Must have validUntil
Rotated active key Must name an earlier predecessor key
Approval time window validFrom <= approvedAt < validUntil, when validUntil is present
Approval registry binding Approval must include the active key's registry event hash
Activation delay 0 seconds for the current GCD fixture lane

Current production-operations parameters:

Parameter Current Rule
Production signer AWS KMS ECC_NIST_EDWARDS25519 key
Signing algorithm ED25519_SHA_512 with MessageType=RAW
Registry publisher crinkl-verifier-registry-publisher
Fixture keys in production Forbidden
Raw private-key export Forbidden
CI access to production key Forbidden
Human approval Two approvers: protocol owner and security owner
Registry publication lag Target 15 minutes
Emergency revoke publication Target 15 minutes with incident id
Access log retention At least 90 days
Key operation review cadence 30 days
Registry event retention Permanent

About

Crinkl Campaigns on-chain program for public campaign commitments, settlement anchoring, and future campaign execution primitives.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors