> ## Documentation Index
> Fetch the complete documentation index at: https://docs.darkpool.fun/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-Sponsorship

> Pure Sui-native sponsored-tx protocol. Our backend signs as gas owner.

The `POST /v1/sponsor` endpoint is DarkPool's gas onramp. It uses Sui's native sponsored-transaction protocol with no Enoki Portal allowlist, no third-party dependency, and the ability to sponsor any package. **Both zkLogin and wallet users** sign trades without holding any SUI.

## Why we shipped it

The user had configured `Allowed Addresses` in the Enoki Portal with the *package IDs* (wrong field; that section gates sender addresses, not Move targets), so every sponsorship attempt 403'd. Asking the user to redo the Portal config was both fragile and a third-party dependency. Self-sponsorship sidesteps it entirely.

Enoki sponsorship stays as **Strategy 1** for zk users. The user paid for the credits and we shouldn't waste them when the Portal is correctly configured.

## Wire protocol

<Frame caption="Frontend builds a PTB-kind, backend signs as gas owner, user co-signs the same bytes, then either side submits. Chain enforces sender = user.">
  <img src="https://mintcdn.com/dp-550c5f99/CtIm00nzcTad2EwA/images/sponsor-protocol.png?fit=max&auto=format&n=CtIm00nzcTad2EwA&q=85&s=a0f0a0dea57e22c421d8d5875e783ee4" alt="Self-sponsorship wire protocol. Step 1: Frontend builds a PTB. Step 2: Frontend POSTs to slash v1 slash sponsor with txKindBytes and sender. Backend runs Transaction.fromKind, setSender(user), setGasOwner(sponsor), setGasBudget(cap), then sponsor.sign(). Backend returns txBytes and sponsorSig. Step 3: User signs the same bytes (wallet via useSignTransaction; zk via EnokiKeypair.signTransaction). Step 4: Frontend calls suiClient.executeTransaction with the bytes and the array of sponsor and user signatures. Sponsor pays gas." width="1536" height="1024" data-path="images/sponsor-protocol.png" />
</Frame>

Chain enforces `sender == user` (their signature is mandatory). Gas comes from the sponsor.

## Abuse bounds

Three caps prevent a hostile PTB:

| Env var                          | Default | Bound                                |
| -------------------------------- | ------- | ------------------------------------ |
| `SPONSOR_MAX_GAS_BUDGET_SUI`     | `0.03`  | Per-tx hard ceiling on gas budget    |
| `SPONSOR_PER_USER_DAILY_CAP_SUI` | `0.5`   | Per-sender daily cap (Redis-tracked) |
| `SPONSOR_DAILY_CAP_SUI`          | `5`     | Global daily cap                     |

Redis keys `sponsor:user:<addr>:<yyyy-mm-dd>` and `sponsor:global:<yyyy-mm-dd>` use `INCRBYFLOAT` with `EXPIRE`-to-end-of-day.

Worst case: one bad actor at the per-user cap drains 0.5 SUI/day, the global cap drains 5 SUI/day total. Both fit a hackathon budget.

<Note>
  PTB-command inspection (reject `tx.gas` references in `TransferObjects` and `SplitCoins`) is a v0.4 hardening follow-up.
</Note>

## Frontend integration

`packages/frontend/src/lib/wallet.ts` is the three-strategy signer:

1. **Self-sponsor first.** Works for both wallet and zk users. Sponsors any package.
2. **Enoki sponsorship.** Zk users only, on `SponsorUnavailableError`.
3. **Direct execution.** User pays gas (last resort).

All 11 sign call sites flow through `useTxSigner()` which encapsulates the cascade.

## GET /v1/sponsor

```json theme={"system"}
{
  "enabled": true,
  "sponsorAddress": "0x…",
  "perUserDailyCapSui": 0.5,
  "globalDailyCapSui": 5,
  "maxGasBudgetSui": 0.03
}
```

The UI uses this to decide whether to show the "Gas sponsored" badge.
