Relayer Reference
The Ryze Relayer is an intent-based transaction execution service. Instead of users submitting on-chain transactions directly, they sign an intent (an EIP-712 typed message) and the relayer batches and executes it on their behalf -- handling gas, oracle price data, and batching for efficiency.
Base URLs
| Environment | Base URL |
|---|---|
| Mainnet | https://mainnet.relayer.ryze.pro/api/v1 |
| Testnet | https://sepolia.relayer.ryze.pro/api/v1 |
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /intents/submit | Submit a signed intent (swap, join, exit) |
GET | /intents/:intentId | Get intent execution status |
GET | /health | Service health check |
Intent Types
All intents go through the same /intents/submit endpoint. The type field determines the operation:
| Type | Description | Guide |
|---|---|---|
swap | Token-to-token swap (single or multi-hop) | Submit Swap |
join | Single-asset liquidity deposit | Submit Join |
joinProportional | Multi-asset proportional liquidity deposit | Submit Proportional Join |
exitProportional | Proportional liquidity withdrawal | Submit Exit |
How It Works
1. User gets a quote from the Router
2. User approves the MultiHopRouter to spend their tokens (ERC-20 approve)
3. User signs an EIP-712 intent message with their wallet
4. Frontend POSTs the signed intent to the Relayer
5. Relayer validates signature + nonce, queues the intent
6. Relayer batches intents, fetches oracle prices, executes on-chain
7. Frontend polls for status until confirmedAuthentication
No API keys. The relayer authenticates via EIP-712 signatures -- each intent must be signed by the user's wallet, proving they authorized the operation.
Rate Limiting
- 100 requests per minute per IP address
- Returns HTTP
429when exceeded
Common Prerequisites
Before submitting any intent:
1. Token Approval
The user must approve the MultiHopRouter contract to spend their input tokens:
import { erc20Abi } from 'viem';
const MULTIHOP_ROUTER = '0x662F15226f5b6Bf8aA10512374Af3115412C04bA';
const hash = await walletClient.writeContract({
address: tokenAddress,
abi: erc20Abi,
functionName: 'approve',
args: [MULTIHOP_ROUTER, amountIn], // or MaxUint256 for unlimited
});
await publicClient.waitForTransactionReceipt({ hash });2. Read Nonce
Each intent type has its own nonce counter on the contract. Read the current nonce before signing:
// For swaps
const nonce = await publicClient.readContract({
address: MULTIHOP_ROUTER,
abi: routerAbi,
functionName: 'swapNonces',
args: [userAddress],
});
// For single joins
const nonce = await publicClient.readContract({
address: MULTIHOP_ROUTER,
abi: routerAbi,
functionName: 'joinNonces',
args: [userAddress],
});
// For proportional joins
const nonce = await publicClient.readContract({
address: MULTIHOP_ROUTER,
abi: routerAbi,
functionName: 'joinProportionalNonces',
args: [userAddress],
});
// For exits
const nonce = await publicClient.readContract({
address: MULTIHOP_ROUTER,
abi: routerAbi,
functionName: 'exitProportionalNonces',
args: [userAddress],
});3. EIP-712 Domain
All intent types share this domain:
const domain = {
name: 'MultiHopRouter',
version: '1',
chainId: 8453, // Base mainnet (84532 for testnet)
verifyingContract: '0x662F15226f5b6Bf8aA10512374Af3115412C04bA',
};Error Format
{
"success": false,
"status": "error",
"message": "Verification failed: nonce mismatch: expected 1, got 0 (hint: use 1 for your next intent)"
}| Code | Common Causes |
|---|---|
400 | Invalid signature, nonce mismatch, expired deadline, bad path |
429 | Rate limit exceeded |
503 | Service unhealthy |