Delegated Trading Guide
Complete guide to setting up and using delegated (gasless) trading.
Alpha Version
The Ostium Builder Service is in Alpha. API endpoints, specifications, and builder URLs may change without notice. Use with caution in production environments.
Overview
Delegated trading allows your application to execute trades on behalf of users without requiring them to pay gas fees or sign each transaction. This is ideal for:
- High-frequency trading applications
- Mobile apps with simplified UX
- Automated trading strategies
- Gasless user experiences
How It Works
- Delegate Wallet Creation: Create a smart account (delegate wallet) linked to a trader
- On-chain Approval: Trader approves the delegate wallet
- API Key Generation: Receive an API key for delegated actions
- Delegated Execution: Use the API key to execute trades
Step-by-Step Setup
1. Create a Delegate Wallet
curl -X POST https://builder.ostiscan.xyz/v1/auth/create \
-H "Content-Type: application/json" \
-H "X-Trader-Address: 0xYourWallet" \
-d '{}'Response:
{
"smartAccountAddress": "0x...",
"apiKey": "bsvc_...",
"delegateApprovalTx": {
"to": "0x...",
"data": "0x...",
"value": "0"
},
"usdcApprovalRequired": true,
"usdcApprovalTx": {
"to": "0x...",
"data": "0x...",
"value": "0"
},
"chainId": 42161
}2. Execute Approval Transactions
The trader must sign and submit both transactions:
// Using ethers.js
const signer = await provider.getSigner();
// Approve delegate
const delegateTx = await signer.sendTransaction(response.delegateApprovalTx);
await delegateTx.wait();
// Approve USDC spending (if required)
if (response.usdcApprovalRequired) {
const usdcTx = await signer.sendTransaction(response.usdcApprovalTx);
await usdcTx.wait();
}3. Verify the Delegate Wallet
curl -X POST https://builder.ostiscan.xyz/v1/auth/verify-auth \
-H "X-Trader-Address: 0xYourWallet" \
-H "X-API-Key: bsvc_..."Response:
{
"verified": true,
"smartAccountAddress": "0x...",
"allowance": "1000000"
}4. Execute Delegated Trades
Now use the API key for gasless trading:
curl -X POST https://builder.ostiscan.xyz/v1/exchange/open \
-H "Content-Type: application/json" \
-H "X-Trader-Address: 0xYourWallet" \
-H "X-API-Key: bsvc_..." \
-d '{
"open": {
"a": 0,
"b": true,
"p": "42500",
"s": "100",
"l": "10",
"t": "market"
}
}'Delegated response:
{
"txHash": "0x...",
"smartAccountAddress": "0x..."
}Important Considerations
Single Action Limitation
In delegated mode, only one action per request is supported. This means:
- One open object per request
- One position close per request
- Cannot batch multiple operations
Security Best Practices
- Store API keys securely - Never expose in client-side code
- Use HTTPS only - Never send API keys over unsecured connections
- Implement rate limiting - Protect against abuse
- Monitor usage - Track all delegated transactions
Revoking Access
To revoke delegated access:
curl -X POST https://builder.ostiscan.xyz/v1/auth/revoke \
-H "X-Trader-Address: 0xYourWallet"This returns a transaction to remove delegation plus a message to sign. After removing delegation and revoking USDC allowance on-chain, call:
curl -X POST https://builder.ostiscan.xyz/v1/auth/verify-revoke \
-H "Content-Type: application/json" \
-H "X-Trader-Address: 0xYourWallet" \
-d '{"message":"<message>","signature":"0x..."}'Error Handling
Common delegated mode errors:
401 UNAUTHORIZED: API key is invalid or delegate wallet not verified400 INVALID_REQUEST: Multiple actions in delegated mode500 INTERNAL_ERROR: Transaction failed on-chain
Example Integration
class DelegatedTrader {
constructor(apiKey, traderAddress) {
this.apiKey = apiKey;
this.traderAddress = traderAddress;
this.baseUrl = 'https://builder.ostiscan.xyz/v1';
}
async openPosition(asset, isLong, price, size, leverage) {
const response = await fetch(`${this.baseUrl}/exchange/open`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Trader-Address': this.traderAddress,
'X-API-Key': this.apiKey
},
body: JSON.stringify({
open: {
a: asset,
b: isLong,
p: price,
s: size,
l: leverage,
t: 'market'
}
})
});
if (!response.ok) {
throw new Error(`Trade failed: ${response.statusText}`);
}
return response.json();
}
}