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.
- 01
Ask what this token needs
POST /transaction/allowance-setupCall 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
Status When 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 - 02
Relay a permit
POST /transaction/setup-permitThe 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
Status When 200Permit relayed 400Invalid request body or query parameters 401Missing or invalid credentials 409code=PERMIT_ALREADY_GRANTED — this account already permitted the executor. - 03
Or broadcast a plain approve
POST /transaction/setup-approvalFor 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
Status When 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.