Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c3bd6f1
fix: add explicit operation IDs to gateway proxy routes
fengtality Mar 4, 2026
b9db532
Add SwapExecutor support
fengtality Mar 11, 2026
f9f203d
fix: remove misleading restart message for token add/delete
fengtality Mar 12, 2026
e04c2a1
fix: skip Gateway placeholder wallet addresses when fetching balances
fengtality Mar 23, 2026
7dd6a39
feat: add deploy-v2-script endpoint and set-default wallet support
fengtality Mar 23, 2026
84d69d9
refactor: move wallet management endpoints to /accounts/gateway/wallet/*
fengtality Mar 23, 2026
33216e5
chore: remove LP-FIX debug prints from main.py
fengtality Mar 23, 2026
4cbc678
refactor: rename /gateway/add-wallet to /gateway/wallet/add
fengtality Mar 23, 2026
c8fd223
refactor: rename DELETE /gateway/{chain}/{address} to /gateway/wallet…
fengtality Mar 23, 2026
a15a26d
refactor: reorder wallet endpoints - set-default after add
fengtality Mar 23, 2026
a8774c8
fix: remove unused network field from GatewayWalletCredential
fengtality Mar 23, 2026
3eb263c
Merge branch 'main' into fix/gateway-proxy-operation-ids
fengtality Mar 23, 2026
24ee725
revert: move wallet endpoints back to original locations
fengtality Mar 27, 2026
99aeea7
revert: keep original function names in gateway router
fengtality Mar 27, 2026
ca57a16
Merge fix/gateway-proxy-operation-ids into feature/swap-executor
fengtality Mar 28, 2026
02ef8ea
Add /lphistory endpoint for LP position history
fengtality Mar 28, 2026
28b15ca
Add swap_executor type and improve executor handling
fengtality Mar 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions bots/credentials/master_account/conf_client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ anonymized_metrics_mode:

# A source for rate oracle, currently ascend_ex, binance, coin_gecko, coin_cap, kucoin, gate_io
rate_oracle_source:
name: binance
name: gate_io

# A universal token which to display tokens values in, e.g. USD,EUR,BTC
global_token:
Expand All @@ -133,7 +133,6 @@ tables_format: psql

paper_trade:
paper_trade_exchanges:
- binance
- kucoin
- ascend_ex
- gate_io
Expand Down
7 changes: 2 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,10 @@ async def lifespan(app: FastAPI):
try:
from hummingbot.strategy_v2.executors.lp_executor.data_types import LPExecutorConfig
from hummingbot.strategy_v2.executors.lp_executor.lp_executor import LPExecutor
print(f"[LP-FIX] imports OK. Registry before: {list(ExecutorService.EXECUTOR_REGISTRY.keys())}", flush=True)
ExecutorService.EXECUTOR_REGISTRY["lp_executor"] = (LPExecutor, LPExecutorConfig)
print(f"[LP-FIX] Registry after: {list(ExecutorService.EXECUTOR_REGISTRY.keys())}", flush=True)
logging.debug("lp_executor registered in ExecutorService")
except Exception as e:
import traceback
print(f"[LP-FIX] FAILED: {e}", flush=True)
traceback.print_exc()
logging.warning(f"Failed to register lp_executor: {e}")

# =========================================================================
# 5. Other Services
Expand Down
4 changes: 4 additions & 0 deletions models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
StopAndArchiveResponse,
StopBotAction,
V2ControllerDeployment,
V2ScriptDeployment,
)

# Connector models
Expand Down Expand Up @@ -84,6 +85,7 @@
GatewayWalletCredential,
GatewayWalletInfo,
SendTransactionRequest,
SetDefaultWalletRequest,
ShowPrivateKeyRequest,
)

Expand Down Expand Up @@ -213,6 +215,7 @@
"StopAndArchiveRequest",
"StopAndArchiveResponse",
"V2ControllerDeployment",
"V2ScriptDeployment",
# Trading models
"TradeRequest",
"TradeResponse",
Expand Down Expand Up @@ -282,6 +285,7 @@
"CreateWalletRequest",
"ShowPrivateKeyRequest",
"SendTransactionRequest",
"SetDefaultWalletRequest",
"GatewayWalletCredential",
"GatewayWalletInfo",
"GatewayBalanceRequest",
Expand Down
10 changes: 10 additions & 0 deletions models/bot_orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ class StopAndArchiveResponse(BaseModel):


# Bot deployment models
class V2ScriptDeployment(BaseModel):
"""Configuration for deploying a bot with a script"""
instance_name: str = Field(description="Unique name for the bot instance")
credentials_profile: str = Field(description="Name of the credentials profile to use")
image: str = Field(default="hummingbot/hummingbot:latest", description="Docker image for the Hummingbot instance")
script: Optional[str] = Field(default=None, description="Script name to run (without .py extension)")
script_config: Optional[str] = Field(default=None, description="Script configuration file name (without .yml extension)")
headless: bool = Field(default=False, description="Run in headless mode (no UI)")


class V2ControllerDeployment(BaseModel):
"""Configuration for deploying a bot with controllers"""
instance_name: str = Field(description="Unique name for the bot instance")
Expand Down
25 changes: 21 additions & 4 deletions models/executors.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ class PositionsSummaryResponse(BaseModel):
"twap_executor",
"xemm_executor",
"order_executor",
"lp_executor"
"lp_executor",
"swap_executor"
]


Expand Down Expand Up @@ -246,14 +247,14 @@ class CreateExecutorRequest(BaseModel):
},
{
"summary": "LP Executor",
"description": "Create an LP position on a CLMM DEX (Meteora, Raydium)",
"description": "Create an LP position on a CLMM DEX",
"value": {
"account_name": "master_account",
"executor_config": {
"type": "lp_executor",
"connector_name": "meteora/clmm",
"trading_pair": "SOL-USDC",
"connector_name": "meteora",
"pool_address": "HTvjzsfX3yU6BUodCjZ5vZkUrAxMDTrBs3CJaq43ashR",
"network": "solana-mainnet-beta",
"lower_price": "80",
"upper_price": "100",
"base_amount": "0",
Expand All @@ -265,6 +266,22 @@ class CreateExecutorRequest(BaseModel):
"keep_position": False
}
}
},
{
"summary": "Swap Executor",
"description": "Execute a single swap on Gateway AMM connectors (Jupiter, Raydium, etc.)",
"value": {
"account_name": "master_account",
"executor_config": {
"type": "swap_executor",
"network": "solana-mainnet-beta",
"trading_pair": "SOL-USDC",
"side": 2,
"amount": "0.1",
"slippage_pct": "0.5",
"swap_providers": ["jupiter/router", "meteora/clmm", "orca/clmm"]
}
}
}
]
}
Expand Down
10 changes: 8 additions & 2 deletions models/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ class SendTransactionRequest(BaseModel):


class GatewayWalletCredential(BaseModel):
"""Credentials for connecting a Gateway wallet"""
"""Credentials for adding an existing wallet to Gateway"""
chain: str = Field(description="Blockchain chain (e.g., 'solana', 'ethereum')")
private_key: str = Field(description="Wallet private key")
network: Optional[str] = Field(default=None, description="Network to use (defaults to chain's default)")
set_default: bool = Field(default=True, description="Set as default wallet for this chain")


class GatewayWalletInfo(BaseModel):
Expand All @@ -63,6 +63,12 @@ class GatewayWalletInfo(BaseModel):
network: str = Field(description="Network the wallet is configured for")


class SetDefaultWalletRequest(BaseModel):
"""Request to set the default wallet for a chain"""
chain: str = Field(description="Blockchain chain (e.g., 'solana', 'ethereum')")
address: str = Field(description="Wallet address to set as default")


# ============================================
# Pool and Token Management Models
# ============================================
Expand Down
90 changes: 70 additions & 20 deletions routers/accounts.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import Dict, List, Optional
from datetime import datetime
from typing import Dict, List

from fastapi import APIRouter, HTTPException, Depends, Query
from fastapi import APIRouter, Depends, HTTPException
from starlette import status

from services.accounts_service import AccountsService
from deps import get_accounts_service
from models import PaginatedResponse, GatewayWalletCredential, GatewayWalletInfo
from models import GatewayWalletCredential, SetDefaultWalletRequest
from services.accounts_service import AccountsService

router = APIRouter(tags=["Accounts"], prefix="/accounts")

Expand All @@ -15,7 +14,7 @@
async def list_accounts(accounts_service: AccountsService = Depends(get_accounts_service)):
"""
Get a list of all account names in the system.

Returns:
List of account names
"""
Expand Down Expand Up @@ -51,13 +50,13 @@ async def list_account_credentials(account_name: str,
async def add_account(account_name: str, accounts_service: AccountsService = Depends(get_accounts_service)):
"""
Create a new account with default configuration files.

Args:
account_name: Name of the new account to create

Returns:
Success message when account is created

Raises:
HTTPException: 400 if account already exists
"""
Expand All @@ -72,13 +71,13 @@ async def add_account(account_name: str, accounts_service: AccountsService = Dep
async def delete_account(account_name: str, accounts_service: AccountsService = Depends(get_accounts_service)):
"""
Delete an account and all its associated credentials.

Args:
account_name: Name of the account to delete

Returns:
Success message when account is deleted

Raises:
HTTPException: 400 if trying to delete master account, 404 if account not found
"""
Expand All @@ -95,14 +94,14 @@ async def delete_account(account_name: str, accounts_service: AccountsService =
async def delete_credential(account_name: str, connector_name: str, accounts_service: AccountsService = Depends(get_accounts_service)):
"""
Delete a specific connector credential for an account.

Args:
account_name: Name of the account
connector_name: Name of the connector to delete credentials for

Returns:
Success message when credential is deleted

Raises:
HTTPException: 404 if credential not found
"""
Expand Down Expand Up @@ -168,10 +167,11 @@ async def add_gateway_wallet(
accounts_service: AccountsService = Depends(get_accounts_service)
):
"""
Add a wallet to Gateway. Gateway handles encryption and storage internally.
Add an existing wallet to Gateway using its private key.
Gateway handles encryption and storage internally.

Args:
wallet_credential: Wallet credentials (chain and private_key)
wallet_credential: Wallet credentials (chain, private_key, and optional set_default)

Returns:
Wallet information from Gateway including address
Expand All @@ -182,7 +182,8 @@ async def add_gateway_wallet(
try:
result = await accounts_service.add_gateway_wallet(
chain=wallet_credential.chain,
private_key=wallet_credential.private_key
private_key=wallet_credential.private_key,
set_default=wallet_credential.set_default
)
return result
except HTTPException:
Expand All @@ -191,6 +192,57 @@ async def add_gateway_wallet(
raise HTTPException(status_code=500, detail=str(e))


@router.post("/gateway/wallet/set-default")
async def set_default_gateway_wallet(
request: SetDefaultWalletRequest,
accounts_service: AccountsService = Depends(get_accounts_service)
) -> Dict:
"""
Set the default wallet for a chain in Gateway.

When multiple wallets are configured for a chain, this endpoint allows
switching which wallet is used as the default for operations.

Args:
request: Contains chain and wallet address to set as default

Returns:
Dict with success status and updated wallet info.

Example: POST /accounts/gateway/wallet/set-default
{
"chain": "solana",
"address": "82SggYRE2Vo4jN4a2pk3aQ4SET4ctafZJGbowmCqyHx5"
}
"""
try:
if not await accounts_service.gateway_client.ping():
raise HTTPException(status_code=503, detail="Gateway service is not available")

result = await accounts_service.gateway_client.set_default_wallet(
chain=request.chain,
address=request.address
)

if result is None:
raise HTTPException(status_code=502, detail="Failed to set default wallet: Gateway returned no response")

if "error" in result:
raise HTTPException(status_code=400, detail=f"Failed to set default wallet: {result.get('error')}")

return {
"success": True,
"message": f"Set {request.address} as default wallet for {request.chain}",
"chain": request.chain,
"address": request.address
}

except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error setting default wallet: {str(e)}")


@router.delete("/gateway/{chain}/{address}")
async def remove_gateway_wallet(
chain: str,
Expand All @@ -217,5 +269,3 @@ async def remove_gateway_wallet(
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))


Loading