Skip to content

ads: pay through the shared payments module (one payment path) - #166

Merged
ralyodio merged 1 commit into
masterfrom
feat/ads-shared-payments
Nov 9, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/ads-shared-payments

Conversation

@ralyodio

@ralyodio ralyodio commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #162 (already squash-merged before #163 landed, so this could not go on the same PR).

Ads payouts now go through node/crates/c0mpute-core/src/payments.rs from #163, so there is exactly one payment path:

  • Each settlement line becomes a payments::Transfer keyed ads:<settlement hash>:<line> and is paid by payments::pay_all on the node's Rail (CoinPay payouts API with $C0MPUTE_COINPAY_PAYOUT_KEY; FakeRail in tests). The [payments] max_usd_per_round cap applies.
  • Idempotency comes from the shared payments::Ledger (payments.json next to each campaign), and the rail also refuses duplicate keys. If the ads ledger loses a line's reference (crash before save), the shared ledger fills it back in and the line is not paid again.
  • Ads' own PaymentRail, DisabledRail, FakeRail and CoinpayCliRail are removed, and nothing shells out to coinpay wallet send any more.
  • Still off by default. c0mpute ads settle --pay needs both [ads] payouts = true and [payments] enabled = true; without them it is a dry run. Real transfers have never been exercised.
  • Payout addresses are <COIN>:<address>, where COIN is the CoinPay currency code (USDC_POL, SOL), mapped to payments::Payee by billing::payee_of.
  • The fee and the 5/75/20 split stay in ads. Docs (docs/ads.md) and the three plugin status notes are updated. No version bump.

Tests:

  • The billing unit tests now cover the round cap, never paying twice, and filling lost references back in from the shared ledger.
  • ads_billing_e2e runs on payments::FakeRail and the shared ledger. Payouts still match the split exactly and equal the budget spent, overspend is refused, and the default config yields no rail.
  • ads_e2e still passes.

🤖 Generated with Claude Code

Ads billing no longer shells out to `coinpay wallet send`. Settlement lines
become payments::Transfer values keyed `ads:<settlement hash>:<line>` and go
through payments::pay_all on the node's one Rail (CoinPay payouts API via
$C0MPUTE_COINPAY_PAYOUT_KEY, FakeRail in tests), with the shared idempotent
payments ledger (`payments.json` per campaign) and the
`[payments] max_usd_per_round` cap. A lost ads-ledger reference is healed
from the shared ledger instead of paying twice.

- Removed ads' own PaymentRail, DisabledRail, FakeRail and CoinpayCliRail.
- `c0mpute ads settle --pay` needs both `[ads] payouts = true` and
  `[payments] enabled = true`; still a dry run otherwise.
- Payout addresses are `<COIN>:<address>` (CoinPay currency code), mapped
  to payments::Payee by billing::payee_of.
- Fee and split logic stay in ads. Docs and manifest notes updated.
- Tests: billing unit tests (cap, idempotency, heal), billing e2e on
  payments::FakeRail still checks payouts equal budget spent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

12 finding(s)

HIGH/CRITICAL: 1 | MEDIUM: 8 | LOW: 3

Severity Rule Location
HIGH js-ssrf-outbound-request apps/web/public/sw.js:24
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:53
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:80
MEDIUM sh-remote-script-execution scripts/dev-setup.sh:25
MEDIUM sh-eval-expansion scripts/dev-setup.sh:35
MEDIUM sh-remote-script-execution scripts/install.sh:173
MEDIUM sh-remote-script-execution scripts/install.sh:198
MEDIUM sh-remote-script-execution scripts/install.sh:316
MEDIUM sh-remote-script-execution scripts/install.sh:354
LOW py-ssrf-outbound-request examples/business-strategist-agent/chat.py:37
LOW py-ssrf-outbound-request examples/business-strategist-agent/train.py:54
LOW secret-generic-credential node/crates/c0mpute-core/src/webhook.rs:1165

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 62f8e92 into master Nov 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant