feat: wallet connect + direct trading via gTrade (Closes #14)#24
Conversation
2651610 to
0e2ac6f
Compare
|
I've updated the original issue (#14) to include all assets supported by the Synth API (Crypto, Gold, and Equities). The live position tracker is a great addition! To get this to a mergeable state, the trading logic needs one final refinement: the UI should never allow a submission of a transaction that gTrade wouldn't accept. This means build-in guards to prevent things like leverage mismatches or orders that are too small/too large for the protocol. If the protocol won't accept the trade, the UI shouldn't even allow the 'Execute' button to be clicked. |
8873ac5 to
31364bd
Compare
|
Fixed. The Changes
All verified against live data from |
367acf1 to
0d1f5bb
Compare
|
Please make sure you can place and monitor trades. Also, please upload an updated demo video that showcases the tool working end-to-end, opening and closing a trade |
0d1f5bb to
a9b877e
Compare
Add MetaMask wallet connection and gTrade (Gains Network) trading integration to the Tide Chart dashboard on Arbitrum One. New features: - Wallet connect/disconnect with any EIP-1193 provider (MetaMask, Coinbase, Rabby) - Automatic chain switching to Arbitrum One - USDC balance display and spend approval - Trade button per equity row in rankings table (click to pre-fill trade form) - Native trade form: pair selection, long/short, leverage (2-150x), collateral - Take Profit and Stop Loss percentage inputs - Configurable max slippage (0.1%-5%, default 1%) - Live trade preview with position size calculation - Direct on-chain trade execution via gTrade Diamond contract - Open positions viewer via gTrade backend API - Clickable Arbiscan tx links on trade success - Graceful fallback to gTrade web app on contract errors - Account/chain change listeners for reactive UI updates - Server-side trade parameter validation New files: - gtrade.py: pair mapping, chain config, validation, API proxy with caching - static/trading.js: wallet connection, trade execution, UI state management Modified files: - main.py: wallet/trading CSS, HTML, ethers.js CDN, 4 new Flask routes - tests/test_tool.py: 18 new gTrade-specific tests - README.md: updated with trading documentation (deliverable) New API routes: - GET /api/gtrade/config - POST /api/gtrade/validate-trade - GET /api/gtrade/resolve-pair - GET /api/gtrade/open-trades Tests: 52 passing (18 new gTrade-specific tests)
a9b877e to
4bf20dc
Compare
…to-refresh - Fetch live price from Chainlink on-chain feeds (BTC, ETH, SOL, etc.) instead of stale cached prices, preventing MarketOpenCanceled errors - Pass current market price as openPrice in trade struct (1e10 precision) to fix BelowMin() revert on market orders - Use gasLimit override to bypass estimateGas/MetaMask simulation (oracle callbacks always revert in static call context) - Close trade with Chainlink expectedPrice in 1e10 precision - Auto-poll Open Positions after open/close tx (every 3s for 15s) - Increase default max slippage from 1% to 1.5% - Add current_price to resolve-pair API endpoint
|
https://www.loom.com/share/70c042b8f9284731a8dae358be551241?t=79 |
|
I tested this PR locally and found a blocking issue where closing Synthetic positions (e.g. Stocks, Commodities) always reverts on the gTrade Diamond contract. The Bug: The Fix: |
- Fix closeTradeMarket reverting: dynamic Chainlink feed resolution instead of hardcoded BTC/ETH map, with Synth API currentAssets fallback for stocks/commodities that lack on-chain feeds - Add live unrealized P&L display for open positions using Chainlink + Synth API prices with leveraged P&L calculation - Add trade history section with localStorage-based recording on successful close (gTrade history API unavailable) - Deduplicate Chainlink feed logic: shared CHAINLINK_FEEDS constant and fetchChainlinkPrice/resolveFeedForPairIndex helpers - Fix open position row layout (trade-row-info wrapper) - Add CSS for P&L display, history badge, and row styling All 54 tests pass.
all the comments are fixed! |
- Parse USDC Transfer event from close tx receipt to get actual amount returned by gTrade, compute real P&L as (returned - collateral) instead of raw leveraged price-change (which ignores all fees) - If no Transfer event found (full loss), P&L = -collateral - Label open position P&L as 'Est.' since it excludes fees (opening, closing, borrowing, spread, price impact) 54/54 tests pass.
- Snapshot USDC balanceOf before sending closeTradeMarket tx - Read USDC balanceOf after tx confirmation - Compute actual P&L as (balanceAfter - balanceBefore) - collateral - This accounts for ALL gTrade fees (open/close/spread/borrowing/impact) - Replaces unreliable Transfer event log parsing which failed when gTrade routes USDC through vault contracts 54/54 tests pass.
…t UI update gTrade uses a two-step close: closeTradeMarket() initiates a price request, then an oracle callback settles the trade and transfers USDC in a SEPARATE transaction. Previous approaches failed because they looked for balance changes / Transfer events in the initiation tx. Now: - Snapshot USDC balance before sending close tx - After tx confirms, poll balanceOf every 2s for up to 30s - When balance changes (oracle callback executed), compute real P&L as (balanceAfter - balanceBefore) - collateral - If oracle is slow, save P&L as 'pending' - Show settlement toast with actual P&L amount Also: - Add relative timestamps to trade history (e.g. '2m ago', '1h ago') - Immediately remove closed position from DOM (no refresh needed) - Handle 'pending' P&L display gracefully 54/54 tests pass.
|
@e35ventura it works well now |




Summary
Add wallet connection and direct trading via gTrade (Gains Network) to the Tide Chart dashboard, closing the loop from Synth forecast intelligence to on-chain DeFi execution — all in one workflow, without leaving the site.
Users can now:
What's New
Backend (
gtrade.py— new file, 230 lines)GROUP_LIMITS): min/max leverage, min position size ($1,500), max collateral — enforced server-sideFrontend (
static/trading.js— new file, 596 lines)ethers.BrowserProvider(ethers.js v6)wallet_switchEthereumChain/wallet_addEthereumChain)eth_accounts(no popup)balanceOfcallselectTradeAsset()— per-row Trade buttons scroll to form and pre-select the asset (works without wallet connected)validateTradeClient) — Execute button is disabled with a descriptive reason whenever the trade would be rejected:openTradeon Diamond contract → tx confirmation with clickable Arbiscan linkaccountsChangedandchainChangedevents auto-update UI, balance, open positions, and trade button stateDashboard (
main.py— +211 lines)trading.jsvia Flask static servingGET /api/gtrade/config— contract addresses, pair mapping, leverage/collateral limitsPOST /api/gtrade/validate-trade— server-side parameter validation with trade summaryGET /api/gtrade/resolve-pair?asset=SPY— resolves ticker to gTrade pair index via backend APIGET /api/gtrade/open-trades?address=0x...— proxies user's open positions from gTrade backendTests (
tests/test_tool.py— +277 lines, 20 new tests)test_gtrade_tradeable_assets— verifies 9 tradeable assets (equities + crypto + gold)test_gtrade_is_tradeable— known + unknown assetstest_gtrade_validate_valid— valid params passtest_gtrade_validate_invalid_asset— non-tradeable asset rejectedtest_gtrade_validate_invalid_direction— invalid direction rejectedtest_gtrade_validate_leverage_bounds— min/max leverage enforcementtest_gtrade_validate_collateral_bounds— min/max collateral enforcementtest_gtrade_build_trade_summary— summary fields and computed position sizetest_gtrade_chain_config— chain ID, hex, name, RPCtest_gtrade_contract_config— contracts, pairs, limitstest_flask_gtrade_config_route— GET /api/gtrade/config returns correct shapetest_flask_gtrade_validate_trade_valid— valid trade returns summary with position_size_usdtest_flask_gtrade_validate_trade_invalid— invalid trade returns 400test_flask_gtrade_validate_trade_below_min_position— position size below $1,500 rejectedtest_flask_gtrade_resolve_pair_invalid— unknown asset returns 400test_flask_gtrade_resolve_pair_valid— valid asset returns pair_index fieldtest_dashboard_html_contains_wallet_ui— HTML has wallet button, trade form, ethers.js, toast container, position size display, open positionstest_flask_gtrade_open_trades_invalid_address— invalid/missing address returns 400test_fetch_open_trades_empty_address— empty address returns empty listDocumentation (
README.md— updated)Related Issues
Closes #14
Type of Change
Testing
Checklist
Files Changed
tools/tide-chart/gtrade.pytools/tide-chart/static/trading.jstools/tide-chart/main.pytools/tide-chart/tests/test_tool.pytools/tide-chart/README.mdtools/tide-chart/.flake8Architecture
Demo Video
https://www.loom.com/share/818c190f102842688aa6dd3234acd72e?t=95