feat(relayer): add relayer service for user vault execution
This commit is contained in:
@@ -47,7 +47,7 @@ class TradingService:
|
|||||||
order_id = str(uuid.uuid4())
|
order_id = str(uuid.uuid4())
|
||||||
fee = amount * Decimal("0.006") # 0.6% protocol fee
|
fee = amount * Decimal("0.006") # 0.6% protocol fee
|
||||||
|
|
||||||
# 1. 记账并扣款/冻结
|
# 1. 记账并扣款/冻结 (若提供 vault_address 则关联金库)
|
||||||
await self.ledger_service.record_trade(
|
await self.ledger_service.record_trade(
|
||||||
address=user_address,
|
address=user_address,
|
||||||
market_address=market_address,
|
market_address=market_address,
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import logging
|
||||||
|
from decimal import Decimal
|
||||||
|
from typing import Optional, Dict, Any
|
||||||
|
from web3 import AsyncWeb3, AsyncHTTPProvider
|
||||||
|
from eth_account import Account
|
||||||
|
from app.config import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class RelayerService:
|
||||||
|
"""
|
||||||
|
【WTFX Relayer 链上代付撮合服务】
|
||||||
|
代表持有 Session Key 授权的用户,将其交易免 Gas 费提交至链上执行
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.w3 = AsyncWeb3(AsyncHTTPProvider(settings.ROBINHOOD_TESTNET_RPC))
|
||||||
|
# 管理员/Relayer 私钥
|
||||||
|
self.relayer_private_key = "0x02aef1247dbddab8e8d6b0962f086f47874626e94988541ca21c9c2ea2475e62"
|
||||||
|
self.relayer_account = Account.from_key(self.relayer_private_key)
|
||||||
|
|
||||||
|
async def execute_vault_transaction(
|
||||||
|
self,
|
||||||
|
vault_address: str,
|
||||||
|
target_market: str,
|
||||||
|
call_data: str,
|
||||||
|
value: int = 0
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
通过 Relayer 调用用户 Vault 的 execute() 函数
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
vault_checksum = self.w3.to_checksum_address(vault_address)
|
||||||
|
target_checksum = self.w3.to_checksum_address(target_market)
|
||||||
|
|
||||||
|
# 构建 execute(address target, uint256 value, bytes calldata data) ABI 调用
|
||||||
|
execute_abi = [{
|
||||||
|
"inputs": [
|
||||||
|
{"name": "target", "type": "address"},
|
||||||
|
{"name": "value", "type": "uint256"},
|
||||||
|
{"name": "data", "type": "bytes"}
|
||||||
|
],
|
||||||
|
"name": "execute",
|
||||||
|
"outputs": [{"name": "", "type": "bytes"}],
|
||||||
|
"stateMutability": "payable",
|
||||||
|
"type": "function"
|
||||||
|
}]
|
||||||
|
|
||||||
|
vault_contract = self.w3.eth.contract(address=vault_checksum, abi=execute_abi)
|
||||||
|
nonce = await self.w3.eth.get_transaction_count(self.relayer_account.address)
|
||||||
|
gas_price = await self.w3.eth.gas_price
|
||||||
|
|
||||||
|
data_bytes = bytes.fromhex(call_data[2:]) if call_data.startswith("0x") else bytes.fromhex(call_data)
|
||||||
|
|
||||||
|
tx = await vault_contract.functions.execute(
|
||||||
|
target_checksum,
|
||||||
|
value,
|
||||||
|
data_bytes
|
||||||
|
).build_transaction({
|
||||||
|
"from": self.relayer_account.address,
|
||||||
|
"nonce": nonce,
|
||||||
|
"gasPrice": gas_price,
|
||||||
|
"chainId": 46630
|
||||||
|
})
|
||||||
|
|
||||||
|
signed_tx = self.relayer_account.sign_transaction(tx)
|
||||||
|
tx_hash = await self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)
|
||||||
|
logger.info(f"Relayer tx submitted: {tx_hash.hex()} for Vault {vault_address}")
|
||||||
|
return tx_hash.hex()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to execute relayer tx: {e}")
|
||||||
|
raise e
|
||||||
|
|
||||||
|
relayer_service = RelayerService()
|
||||||
@@ -52,10 +52,12 @@ class MarketDTO(BaseModel):
|
|||||||
|
|
||||||
class CreateOrderRequest(BaseModel):
|
class CreateOrderRequest(BaseModel):
|
||||||
market_address: str
|
market_address: str
|
||||||
|
vault_address: Optional[str] = None
|
||||||
outcome_index: int = Field(..., ge=0, le=7)
|
outcome_index: int = Field(..., ge=0, le=7)
|
||||||
side: str = Field(..., pattern="^(BUY|SELL)$")
|
side: str = Field(..., pattern="^(BUY|SELL)$")
|
||||||
amount: Decimal = Field(..., gt=0)
|
amount: Decimal = Field(..., gt=0)
|
||||||
price: Optional[Decimal] = None
|
price: Optional[Decimal] = None
|
||||||
|
session_signature: Optional[str] = None
|
||||||
|
|
||||||
class OrderDTO(BaseModel):
|
class OrderDTO(BaseModel):
|
||||||
order_id: str
|
order_id: str
|
||||||
|
|||||||
Reference in New Issue
Block a user