
Orderly One
- 12 installs
- 21 repo stars
- Updated August 3, 2026
- starchild-ai-agent/official-skills
Helps with ai & agent building tasks during AI-assisted development.
About
orderly-one is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- orderly-one
- AI & Agent Building
- AI-coding skill
Orderly One by the numbers
- 12 all-time installs (skills.sh)
- Ranked #11,618 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/starchild-ai-agent/official-skills --skill orderly-oneAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 12 |
|---|---|
| repo stars | ★ 21 |
| Last updated | August 3, 2026 |
| Repository | starchild-ai-agent/official-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Orderly One — DEX Builder
Build, customize, and manage your own decentralized exchange (DEX) on Orderly Network using the Orderly One DEX-as-a-Service platform. Your DEX inherits Orderly's shared liquidity, central limit orderbook, and cross-chain settlement infrastructure — you focus on branding, community, and growth.
Prerequisites
- Wallet: Agent must be running on Fly.io with
WALLET_SERVICE_URLconfigured (EIP-191 signing via Privy) - No API keys needed: Authentication uses the agent's EVM wallet address + JWT tokens
How It Works
Orderly One lets you launch a white-label DEX with:
- Shared orderbook liquidity from the entire Orderly Network
- Multi-chain deployment (Arbitrum, Optimism, Base, Polygon, etc.)
- Custom branding — name, logo, colors, domain
- AI-powered theming — generate themes from text prompts
- Graduation path — move from sandbox to production with your own broker ID
Authentication uses JWT tokens obtained via EIP-191 personal_sign (different from the Ed25519 auth used for Orderly trading).
Tool Reference
| Tool | Auth | Purpose |
|---|---|---|
orderly_one_networks | None | List supported chains for DEX deployment |
orderly_one_leaderboard | None | DEX rankings, broker stats by volume/users |
orderly_one_stats | None | Platform-wide aggregate statistics |
orderly_one_dex_get | JWT | Get your DEX config or a specific DEX by ID |
orderly_one_dex_create | JWT | Create a new DEX (name, chains, branding) |
orderly_one_dex_update | JWT | Update DEX configuration |
orderly_one_dex_delete | JWT | Delete a DEX (destructive) |
orderly_one_social_card | JWT | Update social links and OG metadata |
orderly_one_domain | JWT | Set or remove a custom domain |
orderly_one_visibility | JWT | Toggle leaderboard visibility |
orderly_one_deploy_status | JWT | Check deployment status, trigger upgrades |
orderly_one_theme | JWT | AI theme generation and fine-tuning |
orderly_one_graduation | JWT | Graduate DEX to production |
Workflows
Build a DEX
1. Check available networks: orderly_one_networks 2. Create your DEX: orderly_one_dex_create with broker name and chain IDs 3. Check deployment: orderly_one_deploy_status (action: "status") 4. Configure branding: orderly_one_social_card with social links 5. Generate a theme: orderly_one_theme (action: "generate", prompt: "your style")
Customize Your DEX
- Theme: Use
orderly_one_themewith action "generate" for full themes or "fine_tune" for specific elements - Domain: Use
orderly_one_domainto set a custom domain (requires DNS CNAME setup) - Social: Use
orderly_one_social_cardto configure Twitter, Discord, Telegram links and OG image - Visibility: Use
orderly_one_visibilityto show/hide on the public leaderboard
Graduate to Production
1. Check eligibility: orderly_one_graduation (action: "status") 2. Review fee options: orderly_one_graduation (action: "fees") 3. Make payment and verify: orderly_one_graduation (action: "verify", tx_hash, chain_id) 4. Finalize with admin wallet: orderly_one_graduation (action: "finalize", admin_wallet)
Monitor & Upgrade
- Check deployment status:
orderly_one_deploy_status(action: "status") - Check for upgrades:
orderly_one_deploy_status(action: "upgrade_check") - Trigger upgrade:
orderly_one_deploy_status(action: "upgrade") - View workflow run details:
orderly_one_deploy_status(action: "workflow", run_id)
Supported Chains
Use orderly_one_networks for the current list. Commonly supported:
| Chain | Chain ID |
|---|---|
| Arbitrum | 42161 |
| Optimism | 10 |
| Base | 8453 |
| Polygon | 137 |
| Mantle | 5000 |
| Sei | 1329 |
Error Handling
- 401 Unauthorized: JWT expired — automatically refreshed on retry
- 403 Forbidden: Wallet not authorized for this DEX
- 404 Not Found: DEX ID doesn't exist
- 429 Rate Limited: Too many requests — check
orderly_one_deploy_statusrate limit status
Environment Variables
| Variable | Default | Description |
|---|---|---|
WALLET_SERVICE_URL | Required | Privy wallet service URL |
ORDERLY_ONE_API_URL | https://api.dex.orderly.network | API base URL |
"""
Orderly One DEX Builder — Create and manage custom DEXes on Orderly Network.
Provides 13 tools for DEX management via the Orderly One API:
- 3 public tools: networks, leaderboard, stats
- 4 DEX CRUD tools: get, create, update, delete
- 3 branding tools: social card, domain, visibility
- 3 operations tools: deploy status, theme, graduation
Authentication: JWT via EIP-191 personal_sign (not Ed25519).
API server: https://api.dex.orderly.network
Environment Variables:
- WALLET_SERVICE_URL: Privy wallet service URL (required for signing)
- ORDERLY_ONE_API_URL: API base URL (default: https://api.dex.orderly.network)
Usage:
This skill is auto-loaded by the SkillToolLoader.
"""
import logging
from typing import List
logger = logging.getLogger(__name__)
def register(api) -> List[str]:
"""
Skill entry point — register all Orderly One tools.
Args:
api: ExtensionApi instance with registry and config
Returns:
List of registered tool names
"""
registered = []
try:
from .tools import (
# Public tools (3)
OrderlyOneNetworksTool,
OrderlyOneLeaderboardTool,
OrderlyOneStatsTool,
# DEX CRUD tools (4)
OrderlyOneDexGetTool,
OrderlyOneDexCreateTool,
OrderlyOneDexUpdateTool,
OrderlyOneDexDeleteTool,
# Branding tools (3)
OrderlyOneSocialCardTool,
OrderlyOneDomainTool,
OrderlyOneVisibilityTool,
# Operations tools (3)
OrderlyOneDeployStatusTool,
OrderlyOneThemeTool,
OrderlyOneGraduationTool,
)
# Public tools
api.register_tool(OrderlyOneNetworksTool())
api.register_tool(OrderlyOneLeaderboardTool())
api.register_tool(OrderlyOneStatsTool())
# DEX CRUD tools
api.register_tool(OrderlyOneDexGetTool())
api.register_tool(OrderlyOneDexCreateTool())
api.register_tool(OrderlyOneDexUpdateTool())
api.register_tool(OrderlyOneDexDeleteTool())
# Branding tools
api.register_tool(OrderlyOneSocialCardTool())
api.register_tool(OrderlyOneDomainTool())
api.register_tool(OrderlyOneVisibilityTool())
# Operations tools
api.register_tool(OrderlyOneDeployStatusTool())
api.register_tool(OrderlyOneThemeTool())
api.register_tool(OrderlyOneGraduationTool())
registered = [
# Public (3)
"orderly_one_networks",
"orderly_one_leaderboard",
"orderly_one_stats",
# DEX CRUD (4)
"orderly_one_dex_get",
"orderly_one_dex_create",
"orderly_one_dex_update",
"orderly_one_dex_delete",
# Branding (3)
"orderly_one_social_card",
"orderly_one_domain",
"orderly_one_visibility",
# Operations (3)
"orderly_one_deploy_status",
"orderly_one_theme",
"orderly_one_graduation",
]
logger.info(f"Registered Orderly One tools ({len(registered)} tools)")
except Exception as e:
logger.warning(f"Failed to load Orderly One tools: {e}")
return registered
# Extension metadata
EXTENSION_INFO = {
"name": "orderly-one",
"version": "1.0.0",
"description": "Orderly One DEX Builder — create and manage custom DEXes",
"tools": [
"orderly_one_networks",
"orderly_one_leaderboard",
"orderly_one_stats",
"orderly_one_dex_get",
"orderly_one_dex_create",
"orderly_one_dex_update",
"orderly_one_dex_delete",
"orderly_one_social_card",
"orderly_one_domain",
"orderly_one_visibility",
"orderly_one_deploy_status",
"orderly_one_theme",
"orderly_one_graduation",
],
"env_vars": [
"WALLET_SERVICE_URL",
"ORDERLY_ONE_API_URL",
],
}
"""
Orderly One JWT Authentication — EIP-191 personal_sign via Privy wallet.
Auth flow (different from Orderly Ed25519):
1. POST /api/auth/nonce { address } → get message with nonce
2. Sign message via Privy wallet service (EIP-191 personal_sign)
3. POST /api/auth/verify { address, signature } → get JWT token
4. Cache JWT, re-auth on 401 or after 1 hour TTL
Environment Variables:
- WALLET_SERVICE_URL: Privy wallet service URL (required for signing)
- ORDERLY_ONE_API_URL: Orderly One API base URL (default: https://api.dex.orderly.network)
"""
import asyncio
import logging
import os
import time
from typing import Optional
import aiohttp
from tools.wallet import _wallet_request, _is_fly_machine
logger = logging.getLogger(__name__)
DEFAULT_API_URL = "https://api.dex.orderly.network"
JWT_TTL_SECONDS = 3600 # 1 hour
# ── Module-level state (in-memory, lives as long as the process) ─────────────
_jwt_token: Optional[str] = None
_jwt_expiry: float = 0
_wallet_address: Optional[str] = None
_auth_lock = asyncio.Lock()
def _get_api_url() -> str:
return os.environ.get("ORDERLY_ONE_API_URL", DEFAULT_API_URL)
async def _get_wallet_address() -> str:
"""Get the agent's EVM address from Privy wallet service (cached)."""
global _wallet_address
if _wallet_address:
return _wallet_address
if not _is_fly_machine():
raise RuntimeError("Not running on Fly — wallet unavailable")
data = await _wallet_request("GET", "/agent/wallet")
wallets = data if isinstance(data, list) else data.get("wallets", [])
for w in wallets:
if w.get("chain_type") == "ethereum":
_wallet_address = w["wallet_address"]
return _wallet_address
raise RuntimeError("No ethereum wallet found")
async def _fetch_jwt(address: str) -> str:
"""
Authenticate with Orderly One API via EIP-191 personal_sign.
Steps:
1. POST /api/auth/nonce { address } → nonce message
2. Sign message via Privy wallet service
3. POST /api/auth/verify { address, signature } → JWT token
"""
api_url = _get_api_url()
# 1. Get nonce
async with aiohttp.ClientSession() as session:
url = f"{api_url}/api/auth/nonce"
async with session.post(
url,
json={"address": address},
timeout=aiohttp.ClientTimeout(total=15),
) as resp:
if resp.status >= 400:
body = await resp.text()
raise Exception(f"Failed to get auth nonce: HTTP {resp.status}: {body}")
data = await resp.json()
message = data.get("message") or data.get("data", {}).get("message")
if not message:
raise Exception(f"No message in nonce response: {data}")
logger.info("Orderly One auth: signing nonce message via wallet service...")
# 2. Sign via Privy (EIP-191 personal_sign)
result = await _wallet_request("POST", "/agent/sign", {"message": message})
signature = result.get("signature", "")
if not signature:
raise Exception(f"No signature in wallet response: {result}")
# 3. Verify and get JWT
async with aiohttp.ClientSession() as session:
url = f"{api_url}/api/auth/verify"
async with session.post(
url,
json={"address": address, "signature": signature},
timeout=aiohttp.ClientTimeout(total=15),
) as resp:
if resp.status >= 400:
body = await resp.text()
raise Exception(f"Failed to verify auth: HTTP {resp.status}: {body}")
data = await resp.json()
token = data.get("token") or data.get("data", {}).get("token")
if not token:
raise Exception(f"No token in verify response: {data}")
logger.info("Orderly One auth: JWT obtained successfully")
return token
async def ensure_jwt() -> str:
"""
Ensure we have a valid JWT token, refreshing if expired.
Idempotent — safe to call multiple times. Uses asyncio.Lock to prevent
concurrent auth attempts.
"""
global _jwt_token, _jwt_expiry
if _jwt_token and time.time() < _jwt_expiry:
return _jwt_token # Fast path, no lock
async with _auth_lock:
if _jwt_token and time.time() < _jwt_expiry:
return _jwt_token # Double-check after acquiring lock
address = await _get_wallet_address()
_jwt_token = await _fetch_jwt(address)
_jwt_expiry = time.time() + JWT_TTL_SECONDS
return _jwt_token
def invalidate_jwt() -> None:
"""Invalidate the cached JWT (e.g. on 401 response)."""
global _jwt_token, _jwt_expiry
_jwt_token = None
_jwt_expiry = 0
def get_jwt() -> Optional[str]:
"""Get the cached JWT token (None if not yet authenticated)."""
return _jwt_token
"""
Orderly One API Client — async HTTP client for DEX management via Orderly One.
Public endpoints: unauthenticated GET requests (networks, leaderboard, stats).
Private endpoints: JWT-authenticated requests for DEX CRUD, theming, graduation.
Base URL: https://api.dex.orderly.network
"""
import json
import logging
import os
from typing import Any, Dict, Optional
import aiohttp
from . import auth
logger = logging.getLogger(__name__)
DEFAULT_API_URL = "https://api.dex.orderly.network"
class OrderlyOneClient:
"""
Async Orderly One client for DEX management.
- Public methods: GET requests (no auth)
- Private methods: JWT-authenticated requests
"""
def __init__(self, api_url: Optional[str] = None):
self.api_url = api_url or os.environ.get(
"ORDERLY_ONE_API_URL", DEFAULT_API_URL
)
# ── Internal helpers ─────────────────────────────────────────────────
async def _public_get(self, path: str, params: Optional[dict] = None) -> Any:
"""Unauthenticated GET request."""
url = f"{self.api_url}{path}"
async with aiohttp.ClientSession() as session:
async with session.get(
url,
params=params,
timeout=aiohttp.ClientTimeout(total=15),
) as resp:
if resp.status >= 400:
body = await resp.text()
raise Exception(f"Orderly One API {resp.status}: {body}")
data = await resp.json()
return data.get("data", data)
async def _private_request(
self,
method: str,
path: str,
params: Optional[dict] = None,
body: Optional[dict] = None,
retry_on_401: bool = True,
) -> Any:
"""JWT-authenticated request."""
token = await auth.ensure_jwt()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
url = f"{self.api_url}{path}"
async with aiohttp.ClientSession() as session:
kwargs = {
"headers": headers,
"timeout": aiohttp.ClientTimeout(total=30),
}
if method.upper() == "GET":
kwargs["params"] = params
elif body is not None:
kwargs["data"] = json.dumps(body)
async with session.request(method.upper(), url, **kwargs) as resp:
if resp.status == 401 and retry_on_401:
auth.invalidate_jwt()
return await self._private_request(
method, path, params, body, retry_on_401=False
)
if resp.status >= 400:
resp_body = await resp.text()
logger.error(
f"Orderly One API error: {method.upper()} {path} → "
f"{resp.status}: {resp_body}"
)
raise Exception(f"Orderly One API {resp.status}: {resp_body}")
data = await resp.json()
return data.get("data", data)
# ── Public Methods (no auth) ─────────────────────────────────────────
async def get_networks(self) -> Any:
"""Get available blockchain networks for DEX deployment."""
return await self._public_get("/api/dex/networks")
async def get_leaderboard(
self,
broker_id: Optional[str] = None,
page: int = 1,
size: int = 20,
) -> Any:
"""Get DEX leaderboard rankings."""
params = {"page": page, "size": size}
if broker_id:
params["broker_id"] = broker_id
return await self._public_get("/api/leaderboard", params=params)
async def get_broker_stats(self, broker_id: str) -> Any:
"""Get detailed stats for a specific broker/DEX."""
return await self._public_get(f"/api/leaderboard/broker/{broker_id}")
async def get_platform_stats(self) -> Any:
"""Get platform-wide statistics."""
return await self._public_get("/api/stats")
# ── DEX Management (JWT auth) ────────────────────────────────────────
async def get_my_dex(self) -> Any:
"""Get current user's DEX configuration."""
return await self._private_request("GET", "/api/dex")
async def get_dex(self, dex_id: str) -> Any:
"""Get a specific DEX by ID."""
return await self._private_request("GET", f"/api/dex/{dex_id}")
async def create_dex(
self,
broker_name: str,
chain_ids: list,
**kwargs,
) -> Any:
"""Create a new DEX."""
body = {
"broker_name": broker_name,
"chain_ids": chain_ids,
**kwargs,
}
return await self._private_request("POST", "/api/dex", body=body)
async def update_dex(self, dex_id: str, **kwargs) -> Any:
"""Update DEX configuration."""
return await self._private_request("PUT", f"/api/dex/{dex_id}", body=kwargs)
async def delete_dex(self, dex_id: str) -> Any:
"""Delete a DEX."""
return await self._private_request("DELETE", f"/api/dex/{dex_id}")
# ── Branding & Social ────────────────────────────────────────────────
async def update_social_card(self, **kwargs) -> Any:
"""Update DEX social card / branding info."""
return await self._private_request("PUT", "/api/dex/social-card", body=kwargs)
async def set_custom_domain(self, dex_id: str, domain: str) -> Any:
"""Set a custom domain for a DEX."""
return await self._private_request(
"POST", f"/api/dex/{dex_id}/custom-domain", body={"domain": domain}
)
async def remove_custom_domain(self, dex_id: str) -> Any:
"""Remove custom domain from a DEX."""
return await self._private_request(
"DELETE", f"/api/dex/{dex_id}/custom-domain"
)
async def set_board_visibility(self, dex_id: str, show: bool) -> Any:
"""Toggle leaderboard visibility for a DEX."""
return await self._private_request(
"POST", f"/api/dex/{dex_id}/board-visibility", body={"show": show}
)
# ── Deployment & Upgrades ────────────────────────────────────────────
async def get_workflow_status(self, dex_id: str) -> Any:
"""Get current deployment workflow status."""
return await self._private_request("GET", f"/api/dex/{dex_id}/workflow-status")
async def get_workflow_run(self, dex_id: str, run_id: str) -> Any:
"""Get details of a specific workflow run."""
return await self._private_request(
"GET", f"/api/dex/{dex_id}/workflow-runs/{run_id}"
)
async def get_upgrade_status(self, dex_id: str) -> Any:
"""Check if a DEX upgrade is available."""
return await self._private_request(
"GET", f"/api/dex/{dex_id}/upgrade-status"
)
async def upgrade_dex(self, dex_id: str) -> Any:
"""Trigger a DEX upgrade to the latest version."""
return await self._private_request("POST", f"/api/dex/{dex_id}/upgrade")
async def get_rate_limit_status(self) -> Any:
"""Get current API rate limit status."""
return await self._private_request("GET", "/api/dex/rate-limit-status")
# ── Theme ────────────────────────────────────────────────────────────
async def modify_theme(self, prompt: str) -> Any:
"""Generate a theme using AI from a text prompt."""
return await self._private_request(
"POST", "/api/theme/modify", body={"prompt": prompt}
)
async def fine_tune_theme(self, element: str, style: str) -> Any:
"""Fine-tune a specific theme element."""
return await self._private_request(
"POST", "/api/theme/fine-tune", body={"element": element, "style": style}
)
# ── Graduation ───────────────────────────────────────────────────────
async def get_graduation_status(self) -> Any:
"""Get graduation eligibility status."""
return await self._private_request("GET", "/api/graduation/status")
async def get_graduation_fees(self) -> Any:
"""Get graduation fee options."""
return await self._private_request("GET", "/api/graduation/fee-options")
async def verify_graduation_tx(self, tx_hash: str, chain_id: int) -> Any:
"""Verify a graduation payment transaction."""
return await self._private_request(
"POST",
"/api/graduation/verify-tx",
body={"tx_hash": tx_hash, "chain_id": chain_id},
)
async def finalize_graduation(self, admin_wallet: str) -> Any:
"""Finalize graduation with admin wallet address."""
return await self._private_request(
"POST",
"/api/graduation/finalize-admin-wallet",
body={"admin_wallet": admin_wallet},
)
# ── Module-level singleton ───────────────────────────────────────────────────
_client: Optional[OrderlyOneClient] = None
def _get_client() -> OrderlyOneClient:
global _client
if _client is None:
_client = OrderlyOneClient()
return _client
"""
Orderly One DEX Builder Tools — BaseTool subclasses for agent use.
Public tools (3): orderly_one_networks, orderly_one_leaderboard, orderly_one_stats
DEX CRUD (4): orderly_one_dex_get, orderly_one_dex_create, orderly_one_dex_update,
orderly_one_dex_delete
Branding (3): orderly_one_social_card, orderly_one_domain, orderly_one_visibility
Operations (3): orderly_one_deploy_status, orderly_one_theme, orderly_one_graduation
"""
import logging
from core.tool import BaseTool, ToolContext, ToolResult
from .client import _get_client
logger = logging.getLogger(__name__)
# ── Public Tools (3) — No Auth ───────────────────────────────────────────────
class OrderlyOneNetworksTool(BaseTool):
"""List available blockchain networks for DEX deployment."""
@property
def name(self) -> str:
return "orderly_one_networks"
@property
def description(self) -> str:
return """List available blockchain networks for deploying a DEX on Orderly One.
Use this to check which chains are supported before creating a DEX.
Returns: array of supported networks with chain IDs and names"""
@property
def parameters(self) -> dict:
return {"type": "object", "properties": {}}
async def execute(self, ctx: ToolContext, **kwargs) -> ToolResult:
try:
client = _get_client()
data = await client.get_networks()
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneLeaderboardTool(BaseTool):
"""Get DEX rankings and broker stats."""
@property
def name(self) -> str:
return "orderly_one_leaderboard"
@property
def description(self) -> str:
return """Get the Orderly One DEX leaderboard — rankings of DEXes by volume and activity.
Parameters:
- broker_id: (optional) Filter by specific broker/DEX ID for detailed stats
- page: Page number (default: 1)
- size: Results per page (default: 20)
Returns: ranked list of DEXes with volume, users, and performance metrics"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"broker_id": {
"type": "string",
"description": "Specific broker ID for detailed stats (optional)",
},
"page": {
"type": "integer",
"description": "Page number (default: 1)",
},
"size": {
"type": "integer",
"description": "Results per page (default: 20)",
},
},
}
async def execute(
self,
ctx: ToolContext,
broker_id: str = "",
page: int = 1,
size: int = 20,
**kwargs,
) -> ToolResult:
try:
client = _get_client()
if broker_id:
data = await client.get_broker_stats(broker_id)
else:
data = await client.get_leaderboard(page=page, size=size)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneStatsTool(BaseTool):
"""Get platform-wide statistics."""
@property
def name(self) -> str:
return "orderly_one_stats"
@property
def description(self) -> str:
return """Get Orderly One platform-wide statistics.
Returns: total volume, active DEXes, total users, and other aggregate metrics"""
@property
def parameters(self) -> dict:
return {"type": "object", "properties": {}}
async def execute(self, ctx: ToolContext, **kwargs) -> ToolResult:
try:
client = _get_client()
data = await client.get_platform_stats()
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
# ── DEX CRUD Tools (4) — JWT Auth ───────────────────────────────────────────
class OrderlyOneDexGetTool(BaseTool):
"""Get DEX configuration."""
@property
def name(self) -> str:
return "orderly_one_dex_get"
@property
def description(self) -> str:
return """Get DEX configuration from Orderly One.
If dex_id is omitted, returns the current user's DEX.
If dex_id is specified, returns that specific DEX.
Parameters:
- dex_id: (optional) Specific DEX ID. Omit to get your own DEX.
Returns: DEX configuration including broker name, chains, branding, domain, status"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"dex_id": {
"type": "string",
"description": "DEX ID (optional — omit for your own DEX)",
},
},
}
async def execute(self, ctx: ToolContext, dex_id: str = "", **kwargs) -> ToolResult:
try:
client = _get_client()
if dex_id:
data = await client.get_dex(dex_id)
else:
data = await client.get_my_dex()
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneDexCreateTool(BaseTool):
"""Create a new DEX on Orderly One."""
@property
def name(self) -> str:
return "orderly_one_dex_create"
@property
def description(self) -> str:
return """Create a new DEX on Orderly One (DEX-as-a-Service).
This provisions a complete DEX with orderbook trading, powered by Orderly Network's
shared liquidity. The DEX will be deployed to the specified chains.
Parameters:
- broker_name: Name for your DEX/broker (required)
- chain_ids: Array of chain IDs to deploy on (required, e.g. [42161] for Arbitrum)
- logo_url: URL to your DEX logo (optional)
- description: Short description of your DEX (optional)
- primary_color: Brand primary color hex (optional, e.g. "#FF6B00")
Returns: DEX ID, broker ID, deployment status"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"broker_name": {
"type": "string",
"description": "Name for your DEX (e.g. 'MyDEX')",
},
"chain_ids": {
"type": "array",
"items": {"type": "integer"},
"description": "Chain IDs to deploy on (e.g. [42161] for Arbitrum)",
},
"logo_url": {
"type": "string",
"description": "URL to DEX logo image (optional)",
},
"description": {
"type": "string",
"description": "Short description of the DEX (optional)",
},
"primary_color": {
"type": "string",
"description": "Brand primary color hex (e.g. '#FF6B00')",
},
},
"required": ["broker_name", "chain_ids"],
}
async def execute(
self,
ctx: ToolContext,
broker_name: str = "",
chain_ids: list = None,
logo_url: str = "",
description: str = "",
primary_color: str = "",
**kwargs,
) -> ToolResult:
if not broker_name or not chain_ids:
return ToolResult(
success=False, error="'broker_name' and 'chain_ids' are required"
)
try:
client = _get_client()
extra = {}
if logo_url:
extra["logo_url"] = logo_url
if description:
extra["description"] = description
if primary_color:
extra["primary_color"] = primary_color
data = await client.create_dex(
broker_name=broker_name, chain_ids=chain_ids, **extra
)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneDexUpdateTool(BaseTool):
"""Update DEX configuration."""
@property
def name(self) -> str:
return "orderly_one_dex_update"
@property
def description(self) -> str:
return """Update an existing DEX configuration on Orderly One.
Parameters:
- dex_id: DEX ID to update (required)
- broker_name: New broker name (optional)
- chain_ids: Updated chain IDs (optional)
- logo_url: New logo URL (optional)
- description: New description (optional)
- primary_color: New primary color hex (optional)
Returns: updated DEX configuration"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"dex_id": {
"type": "string",
"description": "DEX ID to update",
},
"broker_name": {
"type": "string",
"description": "New broker name (optional)",
},
"chain_ids": {
"type": "array",
"items": {"type": "integer"},
"description": "Updated chain IDs (optional)",
},
"logo_url": {
"type": "string",
"description": "New logo URL (optional)",
},
"description": {
"type": "string",
"description": "New description (optional)",
},
"primary_color": {
"type": "string",
"description": "New primary color hex (optional)",
},
},
"required": ["dex_id"],
}
async def execute(
self,
ctx: ToolContext,
dex_id: str = "",
broker_name: str = "",
chain_ids: list = None,
logo_url: str = "",
description: str = "",
primary_color: str = "",
**kwargs,
) -> ToolResult:
if not dex_id:
return ToolResult(success=False, error="'dex_id' is required")
try:
client = _get_client()
updates = {}
if broker_name:
updates["broker_name"] = broker_name
if chain_ids:
updates["chain_ids"] = chain_ids
if logo_url:
updates["logo_url"] = logo_url
if description:
updates["description"] = description
if primary_color:
updates["primary_color"] = primary_color
if not updates:
return ToolResult(
success=False, error="At least one field to update is required"
)
data = await client.update_dex(dex_id, **updates)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneDexDeleteTool(BaseTool):
"""Delete a DEX."""
@property
def name(self) -> str:
return "orderly_one_dex_delete"
@property
def description(self) -> str:
return """Delete a DEX from Orderly One.
WARNING: This is a destructive action. The DEX and its configuration will be removed.
Parameters:
- dex_id: DEX ID to delete (required)
Returns: deletion confirmation"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"dex_id": {
"type": "string",
"description": "DEX ID to delete",
},
},
"required": ["dex_id"],
}
async def execute(self, ctx: ToolContext, dex_id: str = "", **kwargs) -> ToolResult:
if not dex_id:
return ToolResult(success=False, error="'dex_id' is required")
try:
client = _get_client()
data = await client.delete_dex(dex_id)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
# ── Branding Tools (3) — JWT Auth ────────────────────────────────────────────
class OrderlyOneSocialCardTool(BaseTool):
"""Update DEX branding and social links."""
@property
def name(self) -> str:
return "orderly_one_social_card"
@property
def description(self) -> str:
return """Update the social card and branding for your DEX on Orderly One.
Configure social links, OG image, and other branding metadata for your DEX.
Parameters:
- title: Social card title (optional)
- description: Social card description (optional)
- og_image_url: Open Graph image URL (optional)
- twitter_url: Twitter/X profile URL (optional)
- discord_url: Discord invite URL (optional)
- telegram_url: Telegram group URL (optional)
- website_url: Website URL (optional)
Returns: updated social card configuration"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Social card title",
},
"description": {
"type": "string",
"description": "Social card description",
},
"og_image_url": {
"type": "string",
"description": "Open Graph image URL",
},
"twitter_url": {
"type": "string",
"description": "Twitter/X profile URL",
},
"discord_url": {
"type": "string",
"description": "Discord invite URL",
},
"telegram_url": {
"type": "string",
"description": "Telegram group URL",
},
"website_url": {
"type": "string",
"description": "Website URL",
},
},
}
async def execute(
self,
ctx: ToolContext,
title: str = "",
description: str = "",
og_image_url: str = "",
twitter_url: str = "",
discord_url: str = "",
telegram_url: str = "",
website_url: str = "",
**kwargs,
) -> ToolResult:
try:
client = _get_client()
updates = {}
if title:
updates["title"] = title
if description:
updates["description"] = description
if og_image_url:
updates["og_image_url"] = og_image_url
if twitter_url:
updates["twitter_url"] = twitter_url
if discord_url:
updates["discord_url"] = discord_url
if telegram_url:
updates["telegram_url"] = telegram_url
if website_url:
updates["website_url"] = website_url
if not updates:
return ToolResult(
success=False, error="At least one field to update is required"
)
data = await client.update_social_card(**updates)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneDomainTool(BaseTool):
"""Set or remove a custom domain for a DEX."""
@property
def name(self) -> str:
return "orderly_one_domain"
@property
def description(self) -> str:
return """Manage custom domain for your Orderly One DEX.
Set a custom domain (e.g. "trade.mydex.com") or remove the current custom domain
to revert to the default Orderly subdomain.
Parameters:
- dex_id: DEX ID (required)
- action: "set" or "remove" (required)
- domain: Custom domain to set (required when action is "set", e.g. "trade.mydex.com")
Returns: domain configuration status"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"dex_id": {
"type": "string",
"description": "DEX ID",
},
"action": {
"type": "string",
"enum": ["set", "remove"],
"description": "Set or remove custom domain",
},
"domain": {
"type": "string",
"description": "Custom domain (required for 'set' action)",
},
},
"required": ["dex_id", "action"],
}
async def execute(
self,
ctx: ToolContext,
dex_id: str = "",
action: str = "",
domain: str = "",
**kwargs,
) -> ToolResult:
if not dex_id or not action:
return ToolResult(
success=False, error="'dex_id' and 'action' are required"
)
try:
client = _get_client()
if action == "set":
if not domain:
return ToolResult(
success=False,
error="'domain' is required when action is 'set'",
)
data = await client.set_custom_domain(dex_id, domain)
elif action == "remove":
data = await client.remove_custom_domain(dex_id)
else:
return ToolResult(
success=False, error="'action' must be 'set' or 'remove'"
)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneVisibilityTool(BaseTool):
"""Toggle leaderboard visibility."""
@property
def name(self) -> str:
return "orderly_one_visibility"
@property
def description(self) -> str:
return """Toggle your DEX's visibility on the Orderly One leaderboard.
Parameters:
- dex_id: DEX ID (required)
- show: true to show on leaderboard, false to hide (required)
Returns: visibility update confirmation"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"dex_id": {
"type": "string",
"description": "DEX ID",
},
"show": {
"type": "boolean",
"description": "true = show on leaderboard, false = hide",
},
},
"required": ["dex_id", "show"],
}
async def execute(
self, ctx: ToolContext, dex_id: str = "", show: bool = True, **kwargs
) -> ToolResult:
if not dex_id:
return ToolResult(success=False, error="'dex_id' is required")
try:
client = _get_client()
data = await client.set_board_visibility(dex_id, show)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
# ── Operations Tools (3) — JWT Auth ─────────────────────────────────────────
class OrderlyOneDeployStatusTool(BaseTool):
"""Check deployment status and trigger upgrades."""
@property
def name(self) -> str:
return "orderly_one_deploy_status"
@property
def description(self) -> str:
return """Check DEX deployment status or trigger an upgrade on Orderly One.
Actions:
- "status": Check current deployment workflow status
- "workflow": Get details of a specific workflow run
- "upgrade_check": Check if an upgrade is available
- "upgrade": Trigger a DEX upgrade to the latest version
Parameters:
- dex_id: DEX ID (required)
- action: "status", "workflow", "upgrade_check", or "upgrade" (default: "status")
- run_id: Workflow run ID (required when action is "workflow")
Returns: deployment status, workflow details, or upgrade information"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"dex_id": {
"type": "string",
"description": "DEX ID",
},
"action": {
"type": "string",
"enum": ["status", "workflow", "upgrade_check", "upgrade"],
"description": "Action to perform (default: status)",
},
"run_id": {
"type": "string",
"description": "Workflow run ID (for 'workflow' action)",
},
},
"required": ["dex_id"],
}
async def execute(
self,
ctx: ToolContext,
dex_id: str = "",
action: str = "status",
run_id: str = "",
**kwargs,
) -> ToolResult:
if not dex_id:
return ToolResult(success=False, error="'dex_id' is required")
try:
client = _get_client()
if action == "status":
data = await client.get_workflow_status(dex_id)
elif action == "workflow":
if not run_id:
return ToolResult(
success=False,
error="'run_id' is required for 'workflow' action",
)
data = await client.get_workflow_run(dex_id, run_id)
elif action == "upgrade_check":
data = await client.get_upgrade_status(dex_id)
elif action == "upgrade":
data = await client.upgrade_dex(dex_id)
else:
return ToolResult(
success=False,
error="'action' must be 'status', 'workflow', 'upgrade_check', or 'upgrade'",
)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneThemeTool(BaseTool):
"""AI-powered theme generation and fine-tuning."""
@property
def name(self) -> str:
return "orderly_one_theme"
@property
def description(self) -> str:
return """Generate or fine-tune your DEX theme using Orderly One's AI theme engine.
Actions:
- "generate": Create a full theme from a text prompt (e.g. "dark cyberpunk with neon green accents")
- "fine_tune": Adjust a specific element's style
Parameters:
- action: "generate" or "fine_tune" (default: "generate")
- prompt: Text description for theme generation (required for "generate")
- element: UI element to fine-tune (required for "fine_tune", e.g. "header", "button", "sidebar")
- style: Style description for the element (required for "fine_tune", e.g. "rounded corners, gradient background")
Returns: generated theme configuration or fine-tuned element styles"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["generate", "fine_tune"],
"description": "Generate full theme or fine-tune an element (default: generate)",
},
"prompt": {
"type": "string",
"description": "Text prompt for theme generation (e.g. 'dark mode with blue accents')",
},
"element": {
"type": "string",
"description": "UI element to fine-tune (e.g. 'header', 'button')",
},
"style": {
"type": "string",
"description": "Style description for the element",
},
},
}
async def execute(
self,
ctx: ToolContext,
action: str = "generate",
prompt: str = "",
element: str = "",
style: str = "",
**kwargs,
) -> ToolResult:
try:
client = _get_client()
if action == "generate":
if not prompt:
return ToolResult(
success=False,
error="'prompt' is required for theme generation",
)
data = await client.modify_theme(prompt)
elif action == "fine_tune":
if not element or not style:
return ToolResult(
success=False,
error="'element' and 'style' are required for fine-tuning",
)
data = await client.fine_tune_theme(element, style)
else:
return ToolResult(
success=False,
error="'action' must be 'generate' or 'fine_tune'",
)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))
class OrderlyOneGraduationTool(BaseTool):
"""Graduate DEX to production."""
@property
def name(self) -> str:
return "orderly_one_graduation"
@property
def description(self) -> str:
return """Manage DEX graduation to production on Orderly One.
Graduation moves your DEX from testnet/sandbox to production with its own broker ID
and full Orderly Network integration.
Actions:
- "status": Check graduation eligibility and progress
- "fees": Get graduation fee options and payment methods
- "verify": Verify a graduation payment transaction
- "finalize": Complete graduation with admin wallet assignment
Parameters:
- action: "status", "fees", "verify", or "finalize" (default: "status")
- tx_hash: Transaction hash to verify (required for "verify")
- chain_id: Chain ID of the payment transaction (required for "verify")
- admin_wallet: Admin wallet address (required for "finalize")
Returns: graduation status, fee options, verification result, or finalization confirmation"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["status", "fees", "verify", "finalize"],
"description": "Graduation action (default: status)",
},
"tx_hash": {
"type": "string",
"description": "Payment transaction hash (for 'verify')",
},
"chain_id": {
"type": "integer",
"description": "Chain ID of payment tx (for 'verify')",
},
"admin_wallet": {
"type": "string",
"description": "Admin wallet address (for 'finalize')",
},
},
}
async def execute(
self,
ctx: ToolContext,
action: str = "status",
tx_hash: str = "",
chain_id: int = 0,
admin_wallet: str = "",
**kwargs,
) -> ToolResult:
try:
client = _get_client()
if action == "status":
data = await client.get_graduation_status()
elif action == "fees":
data = await client.get_graduation_fees()
elif action == "verify":
if not tx_hash or not chain_id:
return ToolResult(
success=False,
error="'tx_hash' and 'chain_id' are required for 'verify'",
)
data = await client.verify_graduation_tx(tx_hash, chain_id)
elif action == "finalize":
if not admin_wallet:
return ToolResult(
success=False,
error="'admin_wallet' is required for 'finalize'",
)
data = await client.finalize_graduation(admin_wallet)
else:
return ToolResult(
success=False,
error="'action' must be 'status', 'fees', 'verify', or 'finalize'",
)
return ToolResult(success=True, output=data)
except Exception as e:
return ToolResult(success=False, error=str(e))