Skip to content

feat: generic fee sponsorship - #43

Open
bwmx wants to merge 15 commits into
masterfrom
feat/fee-sponsorship
Open

bwmx wants to merge 15 commits into
masterfrom
feat/fee-sponsorship

Conversation

@bwmx

@bwmx bwmx commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds POST /v1/wallet/transactions/sponsor/, allowing the authenticated manager to sign a fee-pooling transaction without submitting the group.

Transaction group

  • Index 0: unsigned pay from manager → manager, amount 0, with enough fee to cover the group, and no rekeyTo or closeRemainderTo.
  • Indices 1..N: any signed (ed25519, msig, lsig or Falcon pqsig) or unsigned transactions, each with fee = 0. Unsigned transactions may be sent with or without the TX prefix.
  • Every transaction must share the correct canonical group ID.
  • The endpoint signs only index 0 and returns all companion transactions unchanged.
  • The caller handles remaining signatures and network submission.

Required fee

minFee × (N + 2 × pqsig-signed companions), since a Falcon-signed transaction costs 3× the minimum fee. An unsigned companion the caller will Falcon-sign later is counted at 1×, so the caller must add the extra 2× themselves.

The response contains only the base64-encoded transactions array. The manager address remains available through GET /v1/wallet/manager/.

No existing endpoints changed.

Validation

  • 363 unit tests
  • 56 e2e tests, including on-chain sponsored ed25519 and Falcon payments, and a Falcon group 1 µALGO short rejected by both the endpoint and algod simulation
  • Build, lint, and formatting checks

bwmx and others added 12 commits May 11, 2026 20:47
Co-authored-by: Copilot <copilot@github.com>
Require a manager-issued `fee-sponsorship-credential` SD-JWT VC on
POST /wallet/transactions/sponsor/. CredentialAuthGuard now resolves the
required vct from @RequiredCredential route metadata (defaulting to
device-attestation-credential, so existing routes are unchanged).
Possession of the credential is the entitlement — the manager only
issues it to users allowed to use sponsored-fee routes.

The sponsor route additionally requires every user transaction in the
group to be sent from the Algorand address bound to the presented
credential's did:key, so fees are only sponsored for the credential
holder's own transactions.

- Replace the credential-gated GET /wallet/sponsor/ with a public
  unauthenticated GET /wallet/manager/address so wallets can learn the
  Sponsor address before building a group; drop SponsorDetailDto and
  getSponsorInfo
- Add unit specs for CredentialAuthGuard (default and metadata-selected
  vct, cross-rejections, issuer/binding failures)
- Add e2e coverage for the full journey: register the custom
  configuration, issue and redeem the VC over OID4VCI, present it, and
  get the group sponsored — plus rejection of absent credentials,
  device-attestation credentials, and groups sent by other wallets

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Coverage report

St.❔
Category Percentage Covered / Total
🟡 Statements
74.8% (+0.52% 🔼)
2015/2694
🔴 Branches
57.3% (+0.83% 🔼)
416/726
🟡 Functions
69.03% (+0.58% 🔼)
263/381
🟡 Lines
75.23% (+0.51% 🔼)
1868/2483
Show new covered files 🐣
St.❔
File Statements Branches Functions Lines
🟢
... / sponsor-request.dto.ts
100% 100% 100% 100%
🟢
... / sponsor-response.dto.ts
100% 100% 100% 100%

Test suite run success

363 tests passing in 29 suites.

Report generated by 🧪jest coverage report action from 99dad50

This comment was marked as outdated.

Reject sponsor transactions that set rekeyTo or payment.closeRemainderTo,
validate transactions array elements are base64 strings, and fix the
manager address doc path to include the /v1 prefix.
@bwmx
bwmx marked this pull request as ready for review September 22, 2026 12:05
bwmx added 2 commits October 5, 2026 18:49
Resolved conflicts in wallet.service.ts and wallet.service.spec.ts: kept both
sponsorship and master's PQ/account-type changes; sponsor test now passes the
ManagerVaultTokenProvider constructor arg.
- Detect Falcon (pqsig) signed companions from the raw msgpack, since
  algokit's decodeSignedTransaction drops pqsig, and require 3x the minimum
  fee for each. Previously such groups passed validation at 1x and were
  then rejected by the network.
- Accept unsigned transactions with or without the "TX" prefix.
- Collapse the three group-id checks into one: every transaction must
  carry the group id recomputed from the submitted transactions.
- Rely on the request DTO (2..16 base64 entries) instead of re-checking
  array length in the service.
- Sign the re-encoded sponsor transaction directly; drop the per-envelope
  unsignedEncoded copy and the dead try/catch around groupTransactions.
- Use new Address(...) like the rest of the service instead of encodeAddress.
- Deduplicate sponsorship test fixtures and table-drive the sponsor field
  checks; add a DTO validation test.
- Add on-chain e2e coverage: sponsored ed25519 (2x) and Falcon (4x) payments
  confirm with the user paying no fee, and a Falcon group 1 µALGO short is
  rejected by both the endpoint and algod simulation.
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.

2 participants