Relay
The AgentSwap relay submits transactions on behalf of users and agents. Its primary onboarding
function is sponsoring the deployment of a user’s execution proxy (UserProxyV6) through
POST /api/proxy.
Sponsoring a first intent
Section titled “Sponsoring a first intent”Before a user can submit an intent, their execution proxy must exist on-chain to handle trade settlement and token routing.
Without a relay, an onboarding user without a deployed proxy must sign and pay for two separate wallet transactions:
- Direct contract deployment via
UserProxyFactoryV6.deploy(owner). - An ERC-20 token approval to the predicted proxy address.
With the relay, POST /api/proxy sponsors the proxy deployment. The relay broadcasts the factory
deployment transaction and covers the gas fee. The user signs only the token approval from their
wallet. A first intent requires one wallet prompt.
Trust and allowance boundary
Section titled “Trust and allowance boundary”The proxy is the owner’s own contract:
UserProxyFactoryV6deploys a minimal clone whose address derives from the owner; the owner is fixed permanently to the user.- The relay never holds an allowance. Token approvals are granted exclusively to the owner’s own proxy; there is no Permit2 in this flow.
- The relay possesses no administrative rights, sweep functions, or withdrawal authority over the proxy.
- The relay cannot pull user tokens or alter execution routes.
Base URL
Section titled “Base URL”https://app.agentswap.coPublic HTTP contract
Section titled “Public HTTP contract”POST /api/proxy
Section titled “POST /api/proxy”Request a sponsored deployment for an owner proxy on a supported chain.
Request body
Section titled “Request body”{ "chainId": 8453, "owner": "0x1111111111111111111111111111111111111111", "tokenIn": "0x2222222222222222222222222222222222222222", "amountIn": "1000000"}| Field | Type | Description |
|---|---|---|
chainId |
integer | Target EVM chain ID (e.g. 8453, 42161, 4663, 56). |
owner |
string | The 0x address that will own the deployed proxy. |
tokenIn |
string | The 0x ERC-20 token address intended for the swap. |
amountIn |
string | number | The intended trade input amount in atomic integer units. |
Successful responses
Section titled “Successful responses”When a new proxy is deployed:
{ "txHash": "0x...", "proxy": "0x..."}When the owner already has a deployed proxy on this chain:
{ "proxy": "0x...", "existing": true}When a deployment transaction was recently broadcast and is recorded in the pending window:
{ "txHash": "0x...", "proxy": "0x..."}Admission gates
Section titled “Admission gates”Because proxy deployment happens before an intent order is signed, there is no signed commitment to
verify economically before gas is spent. To prevent resource exhaustion, POST /api/proxy evaluates
gates in strict order before broadcasting any transaction:
| Step | Gate | Condition | Rejection response |
|---|---|---|---|
| 1 | Proxy state | factory.proxyOf(owner) == 0 |
HTTP 200 { proxy, existing: true } (no broadcast) |
| 2 | Token balance | tokenIn.balanceOf(owner) >= amountIn |
HTTP 400 owner balance does not cover this amount |
| 3 | Native balance | getBalance(owner) > 0 |
HTTP 400 owner has no native balance |
| 4 | Simulation | factory.deploy(owner) simulation succeeds |
HTTP 400 simulation reverted: <reason> |
| 5 | Gas ceiling | Simulated gas <= 200,000 | HTTP 400 proxy deployment exceeds the sponsored gas cap |
| 6 | Fee ceiling | gas * feePerGas <= 0.0002 ETH (MAX_RELAY_FEE_WEI) |
HTTP 503 relay fee ceiling exceeded on this chain right now |
| 7 | Relayer funding | Relayer balance >= 0.001 ETH (MIN_RELAYER_BALANCE_WEI) |
HTTP 503 relay is not funded on this chain |
| 8 | Pending marker | No active marker in the 120-second pending window | HTTP 200 { txHash, proxy } (re-returns recorded transaction) |
| 9 | Hourly deploy cap | Hourly chain deploys < 60 (MAX_SPONSORED_DEPLOYS_PER_CHAIN_HOUR) |
HTTP 429 sponsored proxy deploy limit is exhausted this hour |
| 10 | Hourly spend budget | Hourly chain spend + fee <= 0.02 ETH (MAX_CHAIN_SPEND_PER_HOUR_WEI) |
HTTP 429 relay spend budget for this chain is exhausted this hour |
Why the native balance gate exists
Section titled “Why the native balance gate exists”The tokenIn address is supplied by the caller. An arbitrary contract can implement balanceOf and
report an arbitrarily large balance.
Checking tokenIn.balanceOf alone does not gate spam. The native balance check ensures the owner
address holds native gas currency on the chain. An attacker must fund each fresh account with native
tokens, bounding spam through real capital expenditure alongside the hourly count and spend limits.
Fallback and client behavior
Section titled “Fallback and client behavior”Client applications implement clear fallback paths to guarantee that relay failures do not block user execution:
- Fallback to wallet deployment: If
POST /api/proxyreturns an error status (such as HTTP 400, 429, 502, or 503) or encounters a network failure, the client falls back to requesting a directfactory.deploy(owner)transaction signed by the user’s wallet. - Unconfirmed deployments: If a sponsored deployment transaction is broadcast but does not confirm within the expected interval, the interface returns to the deploy prompt with the refusal reason. It does not advance to an allowance prompt that would fail against an undeployed address.
- Servability checks: Clients query relay servability (e.g. through
GET /api/intents). If a chain is unservable due to RPC degradation or depleted relayer funds, the client bypasses the relay and offers direct wallet deployment immediately.