Gasless Transactions
Openfish provides a relayer that covers gas costs on behalf of users. You sign a meta-transaction, hand it off to the relayer, and the relayer broadcasts it on-chain. The only token you need to trade is USDC.e — no POL required.
How It Works
Section titled “How It Works”- Client requests a structured payload from
GET /relay-payloadspecifying the transaction type and parameters - Server builds an EIP-712 typed payload that includes the user’s next nonce
- Client signs the payload with their private key
- Client posts the signed result to
POST /submit - Relayer bumps the nonce, logs the transaction, and submits it on-chain
- Client polls
GET /transaction?id={id}to watch progress
Relayer Endpoints
Section titled “Relayer Endpoints”POST /submit
Section titled “POST /submit”Send a signed meta-transaction for on-chain execution. L2 authentication is required.
Request body:
{ "txType": "APPROVE", "data": { "signature": "0x...", "conditionId": "0x...", "amount": "1000000" }}Response:
{ "id": "a1b2c3d4-...", "status": "PENDING", "nonce": 1}GET /nonce
Section titled “GET /nonce”Retrieve the current meta-transaction nonce for an address. No authentication needed.
GET /nonce?address=0x...Response:
{ "nonce": 5}GET /relay-payload
Section titled “GET /relay-payload”Build an EIP-712 meta-transaction payload ready for the user to sign. The payload bundles the next nonce and every parameter needed for the on-chain call.
GET /relay-payload?address=0x...&txType=APPROVE&conditionId=0x...&amount=1000000Response:
{ "types": { "EIP712Domain": [ { "name": "name", "type": "string" }, { "name": "version", "type": "string" }, { "name": "chainId", "type": "uint256" } ], "MetaTransaction": [ { "name": "nonce", "type": "uint256" }, { "name": "from", "type": "address" }, { "name": "txType", "type": "string" }, { "name": "conditionId", "type": "bytes32" }, { "name": "amount", "type": "uint256" } ] }, "primaryType": "MetaTransaction", "domain": { "name": "Openfish CTF Relayer", "version": "1", "chainId": 137 }, "message": { "nonce": 6, "from": "0x...", "txType": "APPROVE", "conditionId": "0x...", "amount": "1000000" }}GET /deployed
Section titled “GET /deployed”Determine whether a proxy wallet has been deployed for a given address.
GET /deployed?address=0x...Response:
{ "deployed": true}GET /transaction
Section titled “GET /transaction”Look up the current state of a relay transaction by its ID.
GET /transaction?id=a1b2c3d4-...Response:
{ "id": "a1b2c3d4-...", "owner": "0x...", "txType": "APPROVE", "status": "CONFIRMED", "txHash": "0x...", "nonce": 1, "data": { ... }, "createdAt": "2025-01-15T10:30:00Z"}GET /transactions
Section titled “GET /transactions”List relay transactions for an address, with pagination support.
GET /transactions?address=0x...&limit=50&offset=0Meta-Transaction Signing Flow
Section titled “Meta-Transaction Signing Flow”Below is a complete Rust example that fetches a relay payload, signs it, and submits it:
use openfish_client_sdk::auth::{LocalSigner, Signer};use reqwest::Client as HttpClient;use serde_json::Value;
let http = HttpClient::new();let host = "https://api.openfish.fun";
// Step 1: Get the relay payloadlet payload: Value = http .get(format!("{host}/relay-payload")) .query(&[ ("address", signer.address().to_string().as_str()), ("txType", "APPROVE"), ]) .send() .await? .json() .await?;
// Step 2: Sign the EIP-712 payload with your wallet// (Use alloy's EIP-712 signing utilities to hash and sign the typed data)
// Step 3: Submit to the relayerlet response: Value = http .post(format!("{host}/submit")) .header("OPENFISH_ADDRESS", signer.address().to_string()) .header("OPENFISH_API_KEY", api_key) .header("OPENFISH_PASSPHRASE", passphrase) .header("OPENFISH_SIGNATURE", hmac_signature) .header("OPENFISH_TIMESTAMP", timestamp) .json(&serde_json::json!({ "txType": "APPROVE", "data": { "signature": signed_payload, } })) .send() .await? .json() .await?;
println!("Relay TX: {}", response["id"]);Transaction States
Section titled “Transaction States”| State | Terminal | Description |
|---|---|---|
PENDING | No | Transaction received by the relayer |
SUBMITTED | No | Submitted onchain, awaiting confirmation |
CONFIRMED | Yes | Finalized successfully |
FAILED | Yes | Transaction failed permanently |
Supported Operations
Section titled “Supported Operations”| Transaction Type | Description |
|---|---|
APPROVE | Approve the Exchange contract to spend USDC.e or outcome tokens |
SPLIT | Split USDC.e into Yes/No outcome token pairs |
MERGE | Merge outcome token pairs back into USDC.e |
REDEEM | Redeem winning tokens for USDC.e after market resolution |
Next Steps
Section titled “Next Steps”- Quickstart — Place your first order -> quickstart
- Matching Engine — How orders are matched after submission -> matching-engine