Swagger

Allowances

One ERC-20 allowance per token, granted once, before the first gasless operation on the executor rail.

How an allowance is granted

The executor rail moves tokens against an allowance, so an account grants one once per token before its first gasless operation there.

A prepare that needs one is refused with 400 and code=EXECUTOR_ALLOWANCE_MISSING. POST /transaction/allowance-setup then answers what this token needs: kind "permit" returns EIP-712 typed data to relay through POST /transaction/setup-permit, and kind "approve" means the token has no EIP-2612 support, so the account signs an ordinary approve and UGTP broadcasts it through POST /transaction/setup-approval, which is bounded per account and per project. Neither call accepts a spender or an amount — both are decided server-side.

Worked example

Granting an allowance, end to end

Only on the executor rail, only once per token, and only after a prepare tells you it is missing.

  1. 01

    Ask what this token needs

    POST /transaction/allowance-setup

    Call it after a prepare is refused with EXECUTOR_ALLOWANCE_MISSING. The answer is kind "permit" when the token implements EIP-2612, and kind "approve" when it does not — you never choose the spender or the amount.

    Input — the request

    curl -X POST "https://api.ugtp.io/v1/transaction/allowance-setup" \
      -H "X-API-Key: $UGTP_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "networkId": "43114",
      "ownerAddress": "0x0a1758ad202a2059e8c2970b562597ca45d863c4",
      "tokenAddress": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7"
    }'

    Output — 200 response

    {
      "kind": "permit",
      "primaryType": "Permit",
      "domain": {},
      "types": {},
      "message": {},
      "deadline": 1780000000
    }

    Every status this call can answer with
    StatusWhen
    200What the account must sign
    400Invalid request body or query parameters
    401Missing or invalid credentials
    429Rate limit exceeded — retry after the number of seconds in the `Retry-After` response header
    500Internal server error
  2. 02

    Relay a permit

    POST /transaction/setup-permit

    The path for a token that supports EIP-2612, and the one to prefer: the account signs typed data and needs no native coin at all. A permit that already exists comes back as a 409, which makes the call safe to repeat.

    Input — the request

    curl -X POST "https://api.ugtp.io/v1/transaction/setup-permit" \
      -H "X-API-Key: $UGTP_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "networkId": "43114",
      "ownerAddress": "0x0a1758ad202a2059e8c2970b562597ca45d863c4",
      "tokenAddress": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7",
      "deadline": 1780000000,
      "signature": "0x..."
    }'

    Output — 200 response

    {
      "transactionHash": "0x...the approve transaction UGTP broadcast",
      "status": "confirmed",
      "allowance": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
    }

    Every status this call can answer with
    StatusWhen
    200Permit relayed
    400Invalid request body or query parameters
    401Missing or invalid credentials
    409code=PERMIT_ALREADY_GRANTED — this account already permitted the executor.
  3. 03

    Or broadcast a plain approve

    POST /transaction/setup-approval

    For a token with no permit. The account signs an ordinary approve and UGTP broadcasts it; the sender, token, spender and amount are all read from the signed bytes. One-time and tightly bounded per account and per project.

    Input — the request

    curl -X POST "https://api.ugtp.io/v1/transaction/setup-approval" \
      -H "X-API-Key: $UGTP_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "networkId": "43114",
      "rawTransaction": "0x02f8..."
    }'

    Output — 200 response

    {
      "fundingTransactionHash": "0xaaa...",
      "approvalTransactionHash": "0xbbb...",
      "approvalStatus": "confirmed",
      "allowance": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
    }

    Every status this call can answer with
    StatusWhen
    200Gas funded and the approval broadcast
    400The transaction is not a fundable approve — codes: APPROVAL_TX_UNPARSABLE, APPROVAL_TX_UNSUPPORTED_TYPE, APPROVAL_TX_WRONG_CHAIN,…
    401Missing or invalid credentials
    403code=APPROVAL_SENDER_BLOCKED — this account previously spent funded gas on a different transaction and is permanently ineligible for funded approvals.
    409Chain state says this approval should not be funded — codes: APPROVAL_TX_NONCE_STALE, APPROVAL_TX_NONCE_IN_FLIGHT (the account already has its own…
    429The project's hourly funding limit, the account's LIFETIME allowance of funded approvals, the network's hourly operation ceiling, or the hourly…
    502code=APPROVAL_FUNDING_FAILED (nothing was spent, retry), APPROVAL_FUNDED_BUT_NOT_BROADCAST (the gas was sent; the account can broadcast the…
    503No funder wallet is available for this network right now, the sponsorship budget cannot be verified (SPONSORSHIP_BUDGET_UNAVAILABLE — fail-closed),…
    504code=APPROVAL_FUNDING_NOT_CONFIRMED — the funding transfer has not confirmed yet; a retry resumes it without funding again.