@thirdfy/agent-cli 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +59 -19
  3. package/package.json +2 -2
  4. package/scripts/validate-cli-contract-schemas.mjs +6 -0
  5. package/src/cli/errors.mjs +58 -8
  6. package/src/cli/help.mjs +1 -1
  7. package/src/cli/manifest.mjs +62 -6
  8. package/src/cli/options/bootstrap.mjs +15 -3
  9. package/src/cli/options/chains.mjs +5 -0
  10. package/src/cli/options/credits.mjs +9 -0
  11. package/src/cli/options/data.mjs +13 -1
  12. package/src/cli/options/index.mjs +10 -4
  13. package/src/cli/options/walletControl.mjs +8 -0
  14. package/src/commands/bootstrap.mjs +44 -5
  15. package/src/commands/chat.mjs +3 -0
  16. package/src/commands/credits.mjs +109 -16
  17. package/src/commands/delegation.mjs +3 -1
  18. package/src/commands/discovery.mjs +156 -13
  19. package/src/commands/doctor.mjs +5 -2
  20. package/src/commands/execute.mjs +96 -3
  21. package/src/commands/prompt.mjs +5 -3
  22. package/src/commands/wallet.mjs +238 -3
  23. package/src/commands/walletControl.mjs +66 -0
  24. package/src/contracts/cli/schemas/actions.response.schema.json +45 -0
  25. package/src/contracts/cli/schemas/chains-non-evm.response.schema.json +76 -0
  26. package/src/contracts/cli/schemas/chains.response.schema.json +151 -0
  27. package/src/contracts/cli/schemas/error.response.schema.json +61 -0
  28. package/src/contracts/cli/schemas/preview.response.schema.json +179 -0
  29. package/src/contracts/cli/schemas/readiness.response.schema.json +94 -0
  30. package/src/contracts/cli/schemas/wallet-profile.response.schema.json +127 -0
  31. package/src/core/args.mjs +10 -2
  32. package/src/core/chainRegistry.mjs +223 -1
  33. package/src/core/context.mjs +57 -14
  34. package/src/core/errorEnvelope.mjs +209 -0
  35. package/src/core/fundingTokenIn.mjs +24 -1
  36. package/src/core/http.mjs +6 -1
  37. package/src/core/readOnlyActions.mjs +10 -0
  38. package/src/core/walletExecuteChainId.mjs +25 -0
  39. package/src/lib/creditsUsdSummary.mjs +48 -4
  40. package/src/runtime/actions/actionList.mjs +87 -0
  41. package/src/runtime/actions/selection.mjs +17 -22
  42. package/src/runtime/execution/actionPreflight.mjs +50 -14
  43. package/src/runtime/execution/payloads.mjs +36 -28
  44. package/src/runtime/execution/runners.mjs +75 -21
  45. package/src/runtime/execution/svmLane.mjs +106 -0
  46. package/src/runtime/execution/walletControl.mjs +104 -0
  47. package/src/runtime/handlers.mjs +18 -2
  48. package/src/runtime/index.mjs +1 -1
  49. package/src/runtime/main.mjs +21 -5
  50. package/src/runtime/providerHints/apps.mjs +36 -0
  51. package/src/runtime/providerHints/catalogHint.mjs +55 -0
  52. package/src/runtime/providerHints/cex.mjs +130 -0
  53. package/src/runtime/providerHints/data.mjs +144 -0
  54. package/src/runtime/providerHints/dispatch.mjs +177 -0
  55. package/src/runtime/providerHints/dogeos.mjs +38 -0
  56. package/src/runtime/providerHints/earn.mjs +201 -0
  57. package/src/runtime/providerHints/perps.mjs +346 -0
  58. package/src/runtime/providerHints/prediction.mjs +128 -0
  59. package/src/runtime/providerHints/solana.mjs +85 -0
  60. package/src/runtime/providerHints/trading.mjs +78 -0
  61. package/src/runtime/providerHints/walletControl.mjs +39 -0
  62. package/src/runtime/risk/notional.mjs +59 -0
  63. package/src/runtime/risk/orderPreview.mjs +154 -0
  64. package/src/runtime/risk/riskRefusal.mjs +74 -0
  65. package/src/runtime/validation/actionParamsGate.mjs +2 -0
  66. package/src/runtime/providerHints.mjs +0 -1017
@@ -0,0 +1,38 @@
1
+ export const DOGEOS_CHAIN_ID = 6281971;
2
+
3
+ /** The DogeOS hint, shared by every DogeOS provider id and alias. */
4
+ const DOGEOS_HINT = Object.freeze({
5
+ network: 'DogeOS Chikyu testnet only (chainId 6281971). Testnet tokens have no real value.',
6
+ gas: 'Not sponsored: the agent\'s wallet pays gas in native DOGE. Fund the agent\'s EVM execution wallet (`thirdfy-agent wallet list`, executionWallets; same address as on Base) with test DOGE, and test USDC if needed, from https://faucet.testnet.dogeos.com. A write without DOGE answers INSUFFICIENT_NATIVE_GAS with the faucet link.',
7
+ explorer: 'https://blockscout.testnet.dogeos.com',
8
+ startHere: 'dogeos_get_wallet_actionability (`thirdfy-agent run`, a read): the agent\'s DogeOS address, native DOGE for gas, token balances (WDOGE, USDC, USDT, BARK, WETH) and the next step. Use it for "my DogeOS address / balances" and before the first write.',
9
+ swapFlow: 'Barkswap swap: dogeos_barkswap_get_quote -> `thirdfy-agent preview` -> `thirdfy-agent run --action dogeos_barkswap_execute_swap --chain-id 6281971`; dogeos_prepare_trade (a read) plans it. Both take symbols (DOGE, WDOGE, USDC, USDT, BARK, WETH) or addresses; amountIn is in token units ("1"), not wei. tokenIn DOGE spends native DOGE in one swap (the router wraps it to WDOGE; no separate wrap, a little DOGE stays for gas); tokenOut DOGE swaps to WDOGE and unwraps it in a second transaction. Report every txHash the result lists.',
10
+ routing: 'With no direct pool, the quote and the swap take a two-hop route through the pool quote token in one swap: a migrated Laika token quoted in WETH buys as tokenIn DOGE, tokenOut the token address (DOGE -> WETH -> token) and sells back the same way with tokenOut DOGE. The quote\'s route shows the path; viaToken forces the middle token.',
11
+ wrapFlow: 'Plain wrap or unwrap: `thirdfy-agent run` dogeos_wrap_doge (native DOGE -> WDOGE) or dogeos_unwrap_wdoge (WDOGE -> DOGE), amount in DOGE units or "max". A write that would leave no DOGE for gas answers DOGEOS_GAS_RESERVE_INSUFFICIENT with maxSpendable and the faucet.',
12
+ amountUsd: 'Writes need --estimated-amount-usd. Testnet tokens have no market price: use the dogeos_barkswap_get_quote output in USDC (USDC counts as $1), or priceUsd from the Laika feeds.',
13
+ launchpadFlow: 'Laika tokens: dogeos_get_trending_tokens (or new/early-bird) -> dogeos_laika_token_state -> dogeos_laika_buy_token (dogeAmountWei: DOGE in wei) or dogeos_laika_sell_token (tokenAmountRaw: 18-decimal raw units; get it from dogeos_get_wallet_actionability or the token balance). A token with migrated: true no longer trades on Laika: buy and sell answer LAIKA_TOKEN_MIGRATED with nextAction dogeos_barkswap_execute_swap and the nextActionParams to send. Launch: name and symbol are all it needs; offer description, image URL and socials once as optional extras, and launch without them if the user skips (dogeos_prepare_token_launch, a read, returns the plan -> dogeos_laika_launch_token, which pays the on-chain creation fee in DOGE). ICO claims: dogeos_laika_claim. dogeos_laika_execute_raw takes prebuilt calldata: prefer the typed actions.',
14
+ discoveryActions: [
15
+ 'dogeos_get_trending_tokens',
16
+ 'dogeos_get_new_tokens',
17
+ 'dogeos_get_early_bird_tokens',
18
+ 'dogeos_get_only_moon_tokens',
19
+ 'dogeos_get_big_wins_tokens',
20
+ 'dogeos_get_related_tokens',
21
+ 'dogeos_get_ecosystem_overview',
22
+ 'dogeos_get_chain_insights',
23
+ ],
24
+ laneCompatibility: 'runMode agent_wallet on chainId 6281971, from the agent\'s EVM execution wallet.',
25
+ });
26
+
27
+ /**
28
+ * Static provider hints. DogeOS (Chikyu testnet 6281971): Barkswap swaps, the Laika launchpad and ecosystem reads. Same facts as thirdfy-mcp `src/tools/providers/dogeosProviderHints.ts`. The API has no provider manifest for DogeOS, so this hint is the only guidance: a testnet, gas paid in DOGE (not sponsored), the faucet, and which action starts each flow.
29
+ * Each entry builds the hint for one provider id; `dispatch.mjs` picks the entry.
30
+ */
31
+ export const DOGEOS_PROVIDER_HINTS = Object.freeze({
32
+ dogeos: ({ provider }) => ({ provider, ...DOGEOS_HINT }),
33
+ 'dogeos-ecosystem': ({ provider }) => ({ provider, ...DOGEOS_HINT }),
34
+ 'dogeos-barkswap': ({ provider }) => ({ provider, ...DOGEOS_HINT }),
35
+ 'dogeos-laika': ({ provider }) => ({ provider, ...DOGEOS_HINT }),
36
+ barkswap: ({ provider }) => ({ provider, ...DOGEOS_HINT }),
37
+ laika: ({ provider }) => ({ provider, ...DOGEOS_HINT }),
38
+ });
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Static provider hints. Earn and lending: the `earn` aggregator and the protocols behind it.
3
+ * Each entry builds the hint for one provider id; `dispatch.mjs` picks the entry.
4
+ */
5
+ export const EARN_PROVIDER_HINTS = Object.freeze({
6
+ earn: ({ provider }) => ({
7
+ provider,
8
+ category: 'earn',
9
+ canonicalReadAction: 'get_earning_opportunities',
10
+ canonicalWriteAction: 'deposit_earn_position',
11
+ readActions: [
12
+ 'get_earning_opportunities',
13
+ 'get_earn_opportunities',
14
+ 'get_earn_provider',
15
+ 'get_earn_position',
16
+ 'get_morpho_vaults',
17
+ 'get_aave_markets',
18
+ 'get_aave_portfolio',
19
+ 'get_aegis_pools',
20
+ 'get_aegis_pool_state',
21
+ 'get_aegis_vault_state',
22
+ 'get_curve_pools',
23
+ 'get-vaults-fyi-vaults',
24
+ 'get_yield_xyz_opportunities',
25
+ ],
26
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position', 'claim_earn_rewards'],
27
+ laneCompatibility: 'Generic earn writes use deposit_earn_position / withdraw_earn_position on normal Thirdfy policy/delegation rails; Yield.xyz incentive claims use claim_earn_rewards (no amount; optional passthrough from get_earn_position.claimableRewards). Routing selects Morpho vault calldata or the validated Curve Base 4pool adapter on Base (8453) per opportunity. With private: true (deposit_earn_position / withdraw_earn_position) the position is entered or exited from the shielded (Bermuda) USDC balance on allowlisted vaults where a Bermuda pool exists (Base Sepolia MetaMorpho today); a private withdraw without amount exits everything; otherwise it is refused, never run publicly.',
28
+ }),
29
+ capyfi: ({ provider }) => ({
30
+ provider,
31
+ category: 'earn',
32
+ canonicalReadAction: 'get_capyfi_markets',
33
+ canonicalWriteAction: 'deposit_earn_position',
34
+ readActions: [
35
+ 'get_capyfi_markets',
36
+ 'get_earning_opportunities',
37
+ 'get_earn_opportunities',
38
+ 'get_earn_position',
39
+ ],
40
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
41
+ supportedChains: [1, 480],
42
+ laneCompatibility: 'CapyFi uses Compound-v2 mint/redeem; native ETH markets use payable mint().',
43
+ example: 'thirdfy-agent run --action deposit_earn_position --params \'{"providerId":"capyfi","opportunityId":"capyfi-1-usdc","amount":"100","chainId":1,"tokenAddress":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}\'',
44
+ }),
45
+ morpho: ({ provider }) => ({
46
+ provider,
47
+ category: 'earn',
48
+ canonicalReadAction: 'get_morpho_vaults',
49
+ canonicalWriteAction: 'deposit_earn_position',
50
+ readActions: ['get_morpho_vaults', 'get_earn_provider', 'get_earn_position'],
51
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
52
+ supportedChains: [8453, 4663],
53
+ laneCompatibility: 'Base MetaMorpho V1 vaults are writable (prefer depositPlan from discovery). Robinhood Vault V2 on 4663 is discoverable read-only until maxDeposit > 0. Deposits require ERC-20 approval before deposit_earn_position.',
54
+ example: 'thirdfy-agent run --action get_earn_opportunities --params \'{"providerId":"morpho","chainId":8453,"asset":"USDC"}\' && thirdfy-agent run --action deposit_earn_position --params \'{"providerId":"morpho","chainId":8453,"vaultAddress":"0x...","tokenAddress":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","amount":"0.1","tokenDecimals":6}\'',
55
+ }),
56
+ aave: ({ provider }) => ({
57
+ provider,
58
+ category: 'earn',
59
+ canonicalReadAction: 'get_aave_markets',
60
+ canonicalWriteAction: 'deposit_earn_position',
61
+ readActions: [
62
+ 'get_aave_markets',
63
+ 'get_aave_portfolio',
64
+ 'get_earning_opportunities',
65
+ 'get_earn_opportunities',
66
+ 'get_earn_position',
67
+ ],
68
+ orderManagementActions: [
69
+ 'deposit_earn_position',
70
+ 'withdraw_earn_position',
71
+ 'aave_borrow',
72
+ 'aave_repay',
73
+ 'aave_set_collateral',
74
+ ],
75
+ laneCompatibility: 'Aave V3 supply and withdraw use deposit_earn_position / withdraw_earn_position with providerId aave. Borrow, repay, and collateral toggles use aave_* lending actions with health-factor guards.',
76
+ example: 'thirdfy-agent actions --provider aave --json && thirdfy-agent run --action get_aave_markets --params \'{"chainId":8453}\'',
77
+ }),
78
+ aegis: ({ provider }) => ({
79
+ provider,
80
+ category: 'earn',
81
+ canonicalReadAction: 'get_aegis_pools',
82
+ canonicalWriteAction: 'deposit_aegis_lender',
83
+ readActions: [
84
+ 'get_earning_opportunities',
85
+ 'get_earn_opportunities',
86
+ 'get_aegis_pools',
87
+ 'get_aegis_pool_state',
88
+ 'get_aegis_vault_state',
89
+ 'get_earn_provider',
90
+ ],
91
+ orderManagementActions: [
92
+ 'deposit_aegis_lender',
93
+ 'redeem_aegis_lender',
94
+ 'open_aegis_vault_and_borrow',
95
+ 'repay_aegis_vault',
96
+ 'stabilize_aegis_vault',
97
+ ],
98
+ supportedChains: [8453, 130],
99
+ laneCompatibility: 'Aegis reads are live on Base allowlisted pools and Unichain DFM defaults. Engine writes use AegisRouterV1 batches with router-only approvals and eth_call simulation; writes stay fail-closed until partner addresses, PoolKeys, Engine ABI/opcodes, and audit sign-off. Solo Hermes should use agent_wallet (`thirdfy-agent run --run-mode agent_wallet`), not execute-intent.',
100
+ example: 'thirdfy-agent actions --provider aegis --chain-id 8453 --json && thirdfy-agent run --action get_aegis_pool_state --run-mode agent_wallet --params \'{"pool":"tfy-usdc","chainId":8453}\'',
101
+ }),
102
+ curve: ({ provider }) => ({
103
+ provider,
104
+ category: 'earn',
105
+ canonicalReadAction: 'get_curve_pools',
106
+ canonicalWriteAction: 'deposit_earn_position',
107
+ readActions: [
108
+ 'get_curve_pools',
109
+ 'get_earning_opportunities',
110
+ 'get_earn_opportunities',
111
+ 'get_earn_provider',
112
+ 'get_earn_position',
113
+ ],
114
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
115
+ supportedChains: [8453],
116
+ laneCompatibility: 'Curve EVM writes are limited to the validated Base mainnet 4pool adapter; other pools remain discovery-only until per-pool calldata is validated.',
117
+ }),
118
+ uniswap: ({ provider }) => ({
119
+ provider,
120
+ category: 'earn',
121
+ canonicalReadAction: 'get_uniswap_pools',
122
+ canonicalWriteAction: 'mint_uniswap_position',
123
+ readActions: [
124
+ 'get_uniswap_pools',
125
+ 'get_uniswap_pool_state',
126
+ 'get_uniswap_positions',
127
+ 'get_uniswap_position',
128
+ 'get_uniswap_fees',
129
+ 'get_earning_opportunities',
130
+ 'get_earn_opportunities',
131
+ ],
132
+ orderManagementActions: [
133
+ 'mint_uniswap_position',
134
+ 'increase_uniswap_liquidity',
135
+ 'decrease_uniswap_liquidity',
136
+ 'collect_uniswap_fees',
137
+ 'close_uniswap_position',
138
+ 'burn_uniswap_position',
139
+ ],
140
+ supportedChains: [8453, 42161, 1, 4663],
141
+ laneCompatibility: 'Uniswap LP discovery is read-first on Base v3 and vanilla v4 pools. Named mint/increase/decrease/collect/close actions replace deposit_earn_position; writes ship after Gate A discover passes.',
142
+ example: 'thirdfy-agent actions --provider uniswap --json && thirdfy-agent run --action get_uniswap_pools --params \'{"chainId":8453}\'',
143
+ }),
144
+ ratehopper: ({ provider }) => ({
145
+ provider,
146
+ category: 'earn',
147
+ canonicalReadAction: 'get_ratehopper_agents',
148
+ canonicalWriteAction: 'setup_ratehopper_cash_lp',
149
+ readActions: [
150
+ 'get_ratehopper_agents',
151
+ 'get_ratehopper_portfolio',
152
+ 'get_ratehopper_logs',
153
+ 'get_ratehopper_performance',
154
+ 'get_ratehopper_setup_status',
155
+ ],
156
+ orderManagementActions: [
157
+ 'deploy_ratehopper_safe',
158
+ 'enable_ratehopper_operator',
159
+ 'setup_ratehopper_cash_lp',
160
+ 'close_ratehopper_agent',
161
+ 'transfer_ratehopper_to_owner',
162
+ ],
163
+ supportedChains: [8453],
164
+ laneCompatibility: 'Ratehopper Managed USDC LP uses a user-owned Safe on Base. Reads use Thirdfy-hosted Partner REST access. Close and owner sweep stay blocked until the REST close-path spike is confirmed.',
165
+ example: 'thirdfy-agent actions --provider ratehopper --json && thirdfy-agent run --action get_ratehopper_agents --params \'{"chainId":8453}\'',
166
+ }),
167
+ 'vaults-fyi': ({ provider }) => ({
168
+ provider,
169
+ category: 'earn',
170
+ canonicalReadAction: 'get-vaults-fyi-vaults',
171
+ canonicalWriteAction: 'deposit_earn_position',
172
+ readActions: [
173
+ 'get-vaults-fyi-vaults',
174
+ 'get_earning_opportunities',
175
+ 'get_earn_opportunities',
176
+ 'get_earn_provider',
177
+ 'get_earn_position',
178
+ ],
179
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
180
+ laneCompatibility: 'Vaults.fyi writes are transaction-prep first; Thirdfy validates partner payloads, chain/user context, and target allowlists before signing or returning prepared calls.',
181
+ example: 'thirdfy-agent actions --provider vaults-fyi && thirdfy-agent preflight --action deposit_earn_position --params \'{"providerId":"vaults-fyi","opportunityId":"...","vaultAddress":"0x...","tokenAddress":"0x...","amount":"10","chainId":8453}\'',
182
+ supportedChains: [1, 10, 137, 8453, 42161],
183
+ }),
184
+ 'yield-xyz': ({ provider }) => ({
185
+ provider,
186
+ category: 'earn',
187
+ canonicalReadAction: 'get_yield_xyz_opportunities',
188
+ canonicalWriteAction: 'deposit_earn_position',
189
+ readActions: [
190
+ 'get_yield_xyz_opportunities',
191
+ 'get_earning_opportunities',
192
+ 'get_earn_opportunities',
193
+ 'get_earn_provider',
194
+ 'get_earn_position',
195
+ ],
196
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position', 'claim_earn_rewards'],
197
+ laneCompatibility: 'Yield.xyz writes are transaction-prep first. Discover with get_yield_xyz_opportunities and pass the canonical opportunityId. Thirdfy prepareDeposit calls GET /v1/yields/{yieldId} before enter/exit, then validates unsigned transactions with @yieldxyz/shield. claim_earn_rewards claims pending CLAIM_REWARDS incentives (no amount; optional passthrough from get_earn_position.claimableRewards).',
198
+ example: 'thirdfy-agent run --action get_yield_xyz_opportunities --params \'{"chainId":8453,"asset":"USDC"}\' && thirdfy-agent preflight --action deposit_earn_position --params \'{"providerId":"yield-xyz","opportunityId":"<canonical-yieldId>","tokenAddress":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","amount":"10","chainId":8453}\'',
199
+ supportedChains: [1, 10, 100, 130, 137, 42220, 8453, 42161, 4663],
200
+ }),
201
+ });
@@ -0,0 +1,346 @@
1
+ /**
2
+ * Veranta (formerly Avantis) naming for the `avantis` / `avantis-vault` hints, static or from the
3
+ * capabilities manifest. Empty for every other provider.
4
+ */
5
+ export function verantaNamingFields(provider) {
6
+ if (provider !== 'avantis' && provider !== 'avantis-vault') return {};
7
+ const alias = provider === 'avantis' ? 'veranta' : 'veranta-vault';
8
+ return {
9
+ displayName: 'Veranta',
10
+ formerName: 'Avantis',
11
+ providerAliases: [alias],
12
+ actionNaming: `Veranta (formerly Avantis). Veranta action names (*_veranta_*) are canonical; Avantis names (*_avantis_*) still resolve. Provider id stays ${provider}; --provider ${alias} is an alias.`,
13
+ };
14
+ }
15
+
16
+ /**
17
+ * Perps trade recipes: which action and params answer the requests people make ("short BTC 50x $20 with
18
+ * 3% TP and SL", "close my position", "what is my PnL", "move my TP", "add margin", "withdraw to Base").
19
+ * Limits are never written here: each recipe names the read that returns them. Same rules as
20
+ * thirdfy-mcp `src/tools/providers/perpsTradeRecipes.ts`.
21
+ */
22
+ export const HYPERLIQUID_TRADE_RECIPES = Object.freeze({
23
+ limits: 'search_hyperliquid_markets {query: coin} returns mid, szDecimals and maxLeverage per coin. A leverage above maxLeverage is refused: say so and offer maxLeverage. An order under the venue\'s minimum value is refused HL_ORDER_BELOW_MIN_VALUE, which names the minimum. `thirdfy-agent preview` checks both (blockedStage venue_rules) before the order is sent.',
24
+ open: 'One write, leverage, TP and SL included: place_hyperliquid_perps_order {coin, isBuy (false = short), size, limitPx, orderType: market|limit, leverage, takeProfitPx, stopLossPx}. leverage is an integer, at most maxLeverage (cross by default; isCross: false for isolated margin); omit it to keep the account\'s leverage. size is in coins: margin USD x leverage / mid, rounded down to szDecimals. For market, limitPx is the mid (Thirdfy bounds the fill to mid +-1%). --estimated-amount-usd = size x mid. Preview it with `thirdfy-agent preview` and place it once with `run`: never send update_hyperliquid_leverage or place_hyperliquid_tp_sl for the same order.',
25
+ takeProfitStopLoss: 'takeProfitPx and stopLossPx ride on the order: reduce-only triggers sized like the entry that wait for it to fill. A short\'s TP is below entry and its SL above (a crossed leg is refused HL_TP_SL_CROSSED). `thirdfy-agent preview` returns the estimated liquidationPrice and warns HL_STOP_PAST_LIQUIDATION when the stop is past it: tell the user, and offer a closer stop or a lower leverage. HL_TP_SL_LEG_REJECTED means the entry is live without that leg: do not resend the order; read get_hyperliquid_open_orders and attach the missing leg with place_hyperliquid_tp_sl {coin, tpsl: tp|sl, triggerPx, size: the position size, isBuy: the opposite of the position}. place_hyperliquid_tp_sl also adds a TP or SL to a position opened without one.',
26
+ positions: 'get_hyperliquid_user_state: assetPositions[].position (coin, szi: negative = short, entryPx, unrealizedPnl, liquidationPx, leverage {type: cross|isolated}, marginUsed) and marginSummary (accountValue, withdrawable). Open orders and TP/SL triggers: get_hyperliquid_open_orders.',
27
+ close: 'There is no close action: place_hyperliquid_perps_order {coin, isBuy: opposite of the position, size: abs(szi), limitPx: mid, orderType: market, reduceOnly: true} with no leverage, TP or SL. A partial close sends a smaller size.',
28
+ modifyTakeProfitStopLoss: 'cancel_hyperliquid_perps_order {coin, orderId: oid from get_hyperliquid_open_orders}, then place_hyperliquid_tp_sl with the new triggerPx.',
29
+ margin: 'Cross margin (the default) is the account balance: depositing more USDC adds margin to every cross position (deposit_hyperliquid_cctp {sourceChainId: 8453, amountUsdc}, quote_hyperliquid_cctp_deposit first for the fee). An isolated position (opened with isCross: false) takes update_hyperliquid_isolated_margin {coin, direction: add|remove, amountUsdc}: it changes no size; adding moves the liquidation price away. A cross position is refused HL_POSITION_NOT_ISOLATED.',
30
+ withdraw: 'withdraw_hyperliquid_cctp_to_base {amountUsdc} (omit for all withdrawable margin) lands native USDC in the agent\'s Base wallet; get_hyperliquid_cctp_withdraw_status confirms it. Open positions block it: close them first, or pass confirmFullExit: true only when the user asked to close everything.',
31
+ setup: 'Thirdfy runs the one-time Hyperliquid setup (API wallet, approvals) by itself with the first order: do not list keys or approvals to the user. Only funding is the user\'s step.',
32
+ });
33
+
34
+ export const VERANTA_TRADE_RECIPES = Object.freeze({
35
+ limits: 'get_veranta_pair {pair: "BTC/USD"} returns leverages.maxLeverage and pairMinLevPosUSDC (minimum position: collateral x leverage). `thirdfy-agent preview` refuses an open outside them (blockedStage venue_rules) with the reason.',
36
+ open: 'One write, TP and SL included: place_veranta_perps_order {pair: "BTC/USD", side: long|short, collateralUsdc, leverage, orderType: market, takeProfitPrice, stopLossPrice, confirmWrites: true} on chainId 8453. collateralUsdc is the margin ("$20 at 50x" is collateralUsdc 20, leverage 50). --estimated-amount-usd = collateralUsdc x leverage. Limit: orderType limit plus limitPrice.',
37
+ takeProfitStopLoss: 'Prices in USD from the mark (get_veranta_price): a short\'s TP below entry, SL above. Veranta caps a stop at an 80% loss of collateral, so at L x the stop can be at most 80/L % from entry (1.6% at 50x): a wider stop is refused. Tell the user and offer the widest allowed stop or a lower leverage.',
38
+ positions: 'get_veranta_positions: each position\'s pairIndex, tradeIndex, isLong, collateralUsdc and leverage (entry price, TP and SL in raw). Mark for PnL: get_veranta_price. Open limit orders: get_veranta_open_orders.',
39
+ close: 'close_veranta_position {pairIndex, tradeIndex, confirmWrites: true} from get_veranta_positions; collateralToCloseUsdc for a partial close. The collateral returns to the agent\'s Base wallet.',
40
+ modifyTakeProfitStopLoss: 'update_veranta_tp_sl {pairIndex, tradeIndex, takeProfitPrice, stopLossPrice, confirmWrites: true}; cancel_veranta_tp_sl removes them.',
41
+ margin: 'Collateral is per position. update_veranta_margin {pairIndex, tradeIndex, direction: add|remove, amountUsdc, confirmWrites: true} from get_veranta_positions adds Base USDC from the agent wallet to the position, or withdraws it back, with no change of size: adding lowers the leverage and moves the liquidation price away. Withdrawing from an Upside (PnL) position is refused. increase_veranta_coin_position adds collateral and size together. Funding is native USDC in the agent\'s Base wallet.',
42
+ withdraw: 'Nothing to withdraw from the venue: closing a position returns its USDC to the agent\'s Base wallet.',
43
+ setup: 'Thirdfy runs the one-time Veranta setup (delegate, USDC approval) by itself with the first order: do not list delegates or approvals to the user.',
44
+ });
45
+
46
+ /**
47
+ * Static provider hints. Leveraged perps venues: Hyperliquid, Lighter and Veranta (provider id `avantis`), and the Veranta vault.
48
+ * Each entry builds the hint for one provider id; `dispatch.mjs` picks the entry.
49
+ */
50
+ export const PERPS_PROVIDER_HINTS = Object.freeze({
51
+ hyperliquid: ({ provider, manifestHint, setupHints }) => ({
52
+ provider,
53
+ category: 'leveraged_perps',
54
+ canonicalWriteAction: 'place_hyperliquid_perps_order',
55
+ readActions: [
56
+ 'get_hyperliquid_perps_meta',
57
+ 'get_hyperliquid_all_mids',
58
+ 'search_hyperliquid_markets',
59
+ 'get_hyperliquid_l2_book',
60
+ 'get_hyperliquid_candles',
61
+ 'get_hyperliquid_user_state',
62
+ 'get_hyperliquid_open_orders',
63
+ 'get_hyperliquid_funding_status',
64
+ 'get_hyperliquid_onboarding_plan',
65
+ 'get_hyperliquid_referral_status',
66
+ 'get_hyperliquid_builder_fee_status',
67
+ 'quote_hyperliquid_cctp_deposit',
68
+ ],
69
+ orderManagementActions: [
70
+ 'place_hyperliquid_perps_order',
71
+ 'place_hyperliquid_tp_sl',
72
+ 'cancel_hyperliquid_perps_order',
73
+ 'update_hyperliquid_leverage',
74
+ 'update_hyperliquid_isolated_margin',
75
+ 'get_hyperliquid_open_orders',
76
+ ],
77
+ setupActions: [
78
+ 'get_hyperliquid_funding_status',
79
+ 'get_hyperliquid_setup_status',
80
+ 'get_hyperliquid_onboarding_plan',
81
+ 'prepare_hyperliquid_onboarding',
82
+ 'complete_hyperliquid_onboarding',
83
+ 'quote_hyperliquid_cctp_deposit',
84
+ 'deposit_hyperliquid_cctp',
85
+ 'deposit_hyperliquid_bridge',
86
+ 'transfer_hyperliquid_spot_to_perps',
87
+ 'get_bridge_quote',
88
+ 'execute_bridge',
89
+ 'approve_hyperliquid_agent',
90
+ 'get_hyperliquid_builder_fee_status',
91
+ 'approve_hyperliquid_builder_fee',
92
+ 'set_hyperliquid_referrer',
93
+ 'deposit_hyperliquid_staking',
94
+ 'claim_hyperliquid_testnet_faucet',
95
+ ],
96
+ statusActions: [
97
+ 'get_hyperliquid_funding_status',
98
+ 'get_hyperliquid_setup_status',
99
+ 'get_hyperliquid_builder_fee_status',
100
+ 'get_hyperliquid_referral_status',
101
+ ],
102
+ recoveryActions: [
103
+ 'get_hyperliquid_user_state',
104
+ 'withdraw_hyperliquid_cctp_to_base',
105
+ 'withdraw_hyperliquid_to_arbitrum',
106
+ ],
107
+ decommissionExample: 'get_hyperliquid_user_state -> close each position (reduceOnly order) -> withdraw_hyperliquid_cctp_to_base (USDC lands in the agent\'s Base wallet) -> withdraw-to-user on execution wallet',
108
+ credentialType: 'hyperliquid_api_wallet',
109
+ credentialUx: 'agent_wallet lane (signed-in apps and the agent\'s managed wallet): Thirdfy creates and stores the Hyperliquid API wallet with the first order; never ask the user for a private key or an approval. Delegated lanes (thirdfy, hybrid) need a signer-backed hyperliquid_api_wallet credential stored first.',
110
+ supportedFundingSourceChains: [
111
+ {
112
+ chainId: 8453,
113
+ name: 'Base',
114
+ },
115
+ {
116
+ chainId: 42161,
117
+ name: 'Arbitrum One',
118
+ },
119
+ {
120
+ chainId: 137,
121
+ name: 'Polygon',
122
+ },
123
+ {
124
+ chainId: 1,
125
+ name: 'Ethereum',
126
+ },
127
+ ],
128
+ setupBlockers: [
129
+ 'HYPERLIQUID_SOURCE_FUNDS_REQUIRED',
130
+ 'HYPERLIQUID_API_WALLET_APPROVAL_REQUIRED',
131
+ 'HYPERLIQUID_BUILDER_APPROVAL_REQUIRED',
132
+ 'HYPERLIQUID_POLICY_REQUIRED',
133
+ 'HYPERLIQUID_CREDITS_REQUIRED',
134
+ 'HYPERLIQUID_API_WALLET_SIGNER_REQUIRED',
135
+ ],
136
+ setupWarnings: ['HYPERLIQUID_BUILDER_WALLET_UNFUNDED', 'HYPERLIQUID_API_WALLET_NOT_PROVIDED'],
137
+ funding: 'Fund the agent\'s execution wallet with native USDC on Base, Arbitrum, Ethereum or Polygon; Thirdfy bridges and deposits it and sponsors the gas (no ETH needed). Then follow nextAction and nextActionParams from get_hyperliquid_funding_status. Do not invent a funding chain.',
138
+ laneCompatibility: 'Use self/BYOW only for setup signatures or source-chain funding transactions. Perps order placement is an offchain venue write and should use thirdfy, hybrid, or agent_wallet. The default solo agent_wallet path uses the managed execution wallet as the Hyperliquid master address. If margin already sits on a distinct Hyperliquid main wallet, pass that as userAddress/mainWalletAddress and pass the approved execution/API wallet as apiWalletAddress; place_hyperliquid_perps_order uses userAddress for main-wallet readiness checks while the API wallet signs.',
139
+ setupExample: '0) get_hyperliquid_funding_status 1) complete_hyperliquid_onboarding for runtime-owned setup, or get_hyperliquid_onboarding_plan/prepare_hyperliquid_onboarding for operator previews 2) follow nextAction with nextActionParams 3) get_hyperliquid_setup_status before place_hyperliquid_perps_order',
140
+ monetization: 'Builder monetization is active only when the API operator configured a builder address and the builder treasury has Hyperliquid margin. When active, the main wallet signs approve_hyperliquid_builder_fee once and orders attach builder fees. When the treasury is unfunded, get_hyperliquid_setup_status can return ready=true with warning HYPERLIQUID_BUILDER_WALLET_UNFUNDED, get_hyperliquid_builder_fee_status returns monetizationEnabled=false with reason BUILDER_WALLET_UNFUNDED, and place_hyperliquid_perps_order does not require builder approval.',
141
+ example: 'thirdfy-agent actions --provider hyperliquid && thirdfy-agent preflight --action place_hyperliquid_perps_order --params \'{"coin":"ETH","isBuy":true,"size":0.01,"limitPx":3500,"orderType":"market"}\'',
142
+ tradeRecipes: HYPERLIQUID_TRADE_RECIPES,
143
+ ...(manifestHint || {}),
144
+ ...setupHints,
145
+ provider,
146
+ source: manifestHint ? 'cli_capabilities_manifest' : 'static_provider_hint',
147
+ }),
148
+ lighter: ({ provider }) => ({
149
+ provider,
150
+ category: 'leveraged_perps',
151
+ canonicalWriteAction: 'place_lighter_perps_order',
152
+ readActions: [
153
+ 'get_lighter_markets',
154
+ 'search_lighter_markets',
155
+ 'get_lighter_order_book',
156
+ 'get_lighter_candles',
157
+ 'get_lighter_funding_rates',
158
+ 'get_lighter_account',
159
+ 'get_lighter_positions',
160
+ 'get_lighter_open_orders',
161
+ 'get_lighter_pnl',
162
+ 'get_lighter_funding_status',
163
+ 'get_lighter_setup_status',
164
+ 'get_lighter_onboarding_plan',
165
+ 'get_lighter_integrator_status',
166
+ 'get_lighter_partner_stats',
167
+ ],
168
+ orderManagementActions: [
169
+ 'place_lighter_perps_order',
170
+ 'cancel_lighter_perps_order',
171
+ 'modify_lighter_perps_order',
172
+ 'update_lighter_leverage',
173
+ 'update_lighter_margin',
174
+ 'get_lighter_open_orders',
175
+ ],
176
+ setupActions: [
177
+ 'get_lighter_funding_status',
178
+ 'get_lighter_setup_status',
179
+ 'get_lighter_onboarding_plan',
180
+ 'prepare_lighter_onboarding',
181
+ 'complete_lighter_onboarding',
182
+ 'create_lighter_deposit_intent',
183
+ 'setup_lighter_api_key',
184
+ 'create_lighter_api_key',
185
+ 'register_lighter_api_key',
186
+ 'approve_lighter_integrator',
187
+ 'get_bridge_quote',
188
+ 'execute_bridge',
189
+ ],
190
+ statusActions: ['get_lighter_funding_status', 'get_lighter_setup_status', 'get_lighter_integrator_status'],
191
+ recoveryActions: ['get_lighter_account', 'get_lighter_withdrawal_status', 'prepare_lighter_secure_withdrawal'],
192
+ decommissionExample: 'get_lighter_account -> prepare_lighter_secure_withdrawal -> withdraw-to-user on execution wallet',
193
+ credentialType: 'lighter_api_key',
194
+ credentialUx: 'Delegated Lighter writes require encrypted lighter_api_key credentials with privateKey, apiKeyIndex (4-254), and accountIndex.',
195
+ recommendedFundingChainId: 8453,
196
+ supportedFundingSourceChains: [
197
+ {
198
+ chainId: 8453,
199
+ name: 'Base',
200
+ path: 'native USDC -> CCTP intent -> Lighter margin (recommended)',
201
+ },
202
+ {
203
+ chainId: 42161,
204
+ name: 'Arbitrum One',
205
+ path: 'Li.Fi -> Base USDC -> CCTP intent -> Lighter margin',
206
+ },
207
+ {
208
+ chainId: 43114,
209
+ name: 'Avalanche',
210
+ path: 'Li.Fi -> Base USDC -> CCTP intent -> Lighter margin',
211
+ },
212
+ {
213
+ chainId: 1,
214
+ name: 'Ethereum',
215
+ path: 'Priority changePubKey registration only (chainId 1)',
216
+ },
217
+ ],
218
+ setupBlockers: [
219
+ 'LIGHTER_SOURCE_FUNDS_REQUIRED',
220
+ 'LIGHTER_DEPOSIT_REQUIRED',
221
+ 'LIGHTER_ACCOUNT_NOT_FOUND',
222
+ 'LIGHTER_API_KEY_REGISTRATION_REQUIRED',
223
+ 'LIGHTER_INTEGRATOR_APPROVAL_REQUIRED',
224
+ 'LIGHTER_POLICY_REQUIRED',
225
+ 'LIGHTER_CREDITS_REQUIRED',
226
+ 'LIGHTER_SIGNER_NOT_CONFIGURED',
227
+ ],
228
+ setupWarnings: ['LIGHTER_API_KEY_NOT_PROVIDED', 'LIGHTER_INTEGRATOR_ACCOUNT_UNFUNDED'],
229
+ sourceBridgeProvider: 'lifi',
230
+ funding: 'Run complete_lighter_onboarding on Base for Li.Fi, CCTP intent, and USDC transfer. When margin is credited, the API auto-switches to Ethereum API key registration on the next complete_lighter_onboarding call. Minimum CCTP deposit is 5 USDC.',
231
+ laneCompatibility: 'Use agent_wallet and repeat complete_lighter_onboarding on chainId 8453 until setup status is ready. Perps writes use thirdfy, hybrid, or agent_wallet with lighter_api_key credentials.',
232
+ setupExample: '0) complete_lighter_onboarding (chainId 8453, agent_wallet) 1) repeat until get_lighter_setup_status.ready 2) place_lighter_perps_order',
233
+ example: 'thirdfy-agent actions --provider lighter && thirdfy-agent preflight --action place_lighter_perps_order --params \'{"accountIndex":1,"apiKeyIndex":4,"marketId":0,"baseAmount":100,"price":310000,"isAsk":false,"orderType":"limit"}\'',
234
+ }),
235
+ avantis: ({ provider }) => ({
236
+ provider,
237
+ ...verantaNamingFields(provider),
238
+ category: 'leveraged_perps',
239
+ canonicalWriteAction: 'place_veranta_perps_order',
240
+ readActions: [
241
+ 'get_veranta_markets',
242
+ 'get_veranta_pair',
243
+ 'get_veranta_price',
244
+ 'get_veranta_spread',
245
+ 'get_veranta_positions',
246
+ 'get_veranta_open_orders',
247
+ 'get_veranta_allowance',
248
+ 'get_veranta_delegation_status',
249
+ 'get_veranta_funding_status',
250
+ 'get_veranta_setup_status',
251
+ 'get_veranta_onboarding_plan',
252
+ 'get_veranta_builder_fee_status',
253
+ 'get_veranta_referral_status',
254
+ 'get_veranta_referral_stats',
255
+ ],
256
+ orderManagementActions: [
257
+ 'place_veranta_perps_order',
258
+ 'cancel_veranta_perps_order',
259
+ 'close_veranta_position',
260
+ 'update_veranta_tp_sl',
261
+ 'cancel_veranta_tp_sl',
262
+ 'update_veranta_margin',
263
+ 'place_veranta_twap_order',
264
+ 'close_veranta_twap_order',
265
+ 'cancel_veranta_twap_order',
266
+ 'place_veranta_coin_perps_order',
267
+ 'increase_veranta_coin_position',
268
+ 'close_veranta_coin_position',
269
+ 'place_veranta_mm_order',
270
+ 'cancel_veranta_mm_order',
271
+ 'get_veranta_open_orders',
272
+ 'get_veranta_positions',
273
+ ],
274
+ setupActions: [
275
+ 'get_veranta_funding_status',
276
+ 'get_veranta_setup_status',
277
+ 'get_veranta_onboarding_plan',
278
+ 'prepare_veranta_onboarding',
279
+ 'complete_veranta_onboarding',
280
+ 'approve_veranta_builder_fee',
281
+ 'revoke_veranta_builder_fee',
282
+ 'set_veranta_referral_code',
283
+ 'register_veranta_referral_code',
284
+ 'claim_veranta_referral_rebate',
285
+ ],
286
+ statusActions: [
287
+ 'get_veranta_funding_status',
288
+ 'get_veranta_setup_status',
289
+ 'get_veranta_builder_fee_status',
290
+ 'get_veranta_delegation_status',
291
+ ],
292
+ recoveryActions: ['get_veranta_positions', 'close_veranta_position'],
293
+ decommissionExample: 'get_veranta_positions -> close_veranta_position -> withdraw-to-user on execution wallet (Base USDC)',
294
+ credentialType: 'avantis_delegate',
295
+ credentialUx: 'Thirdfy mints and stores the encrypted Veranta delegate. CLI callers use Thirdfy auth only. Do not paste a private key.',
296
+ recommendedFundingChainId: 8453,
297
+ supportedFundingSourceChains: [
298
+ {
299
+ chainId: 8453,
300
+ name: 'Base',
301
+ path: 'native USDC in managed execution wallet (recommended)',
302
+ },
303
+ ],
304
+ setupBlockers: [
305
+ 'AVANTIS_USDC_BALANCE_REQUIRED',
306
+ 'AVANTIS_USDC_ALLOWANCE_REQUIRED',
307
+ 'AVANTIS_DELEGATION_REQUIRED',
308
+ 'AVANTIS_DELEGATE_CREDENTIAL_REQUIRED',
309
+ ],
310
+ setupWarnings: ['AVANTIS_BUILDER_TEMPLATE_UNWIRED'],
311
+ supportedChains: [8453],
312
+ funding: 'Fund the managed execution wallet on Base (8453) with native USDC. Minimum collateral follows the live catalog notional floor.',
313
+ laneCompatibility: 'Use agent_wallet for solo managed-wallet onboarding and perps writes after avantis_delegate credential is stored. Use thirdfy or hybrid for delegated capital. Relayer is default. Builder-fee collection stays unwired until Veranta supplies a fee-enabled template.',
314
+ setupExample: '0) get_veranta_funding_status 1) complete_veranta_onboarding (agent_wallet on Base 8453) 2) get_veranta_setup_status before place_veranta_perps_order. Do not call approve_veranta_builder_fee until setup status shows a wired template.',
315
+ example: 'thirdfy-agent actions --provider veranta && thirdfy-agent preflight --action place_veranta_perps_order --params \'{"pairIndex":0,"side":"long","collateralUsdc":10,"leverage":10,"orderType":"market"}\'',
316
+ formerlyKnownAs: 'Avantis',
317
+ tradeRecipes: VERANTA_TRADE_RECIPES,
318
+ }),
319
+ 'avantis-vault': ({ provider }) => ({
320
+ provider,
321
+ ...verantaNamingFields(provider),
322
+ category: 'earn',
323
+ canonicalReadAction: 'get_veranta_vault_info',
324
+ canonicalWriteAction: 'deposit_veranta_vault',
325
+ readActions: ['get_veranta_vault_info', 'get_veranta_vault_position'],
326
+ orderManagementActions: [
327
+ 'deposit_veranta_vault',
328
+ 'request_veranta_vault_withdrawal',
329
+ 'redeem_veranta_vault',
330
+ 'claim_veranta_vault',
331
+ ],
332
+ recommendedFundingChainId: 8453,
333
+ supportedChains: [8453],
334
+ funding: 'Fund the managed execution wallet on Base with native USDC before vault deposit.',
335
+ laneCompatibility: 'Veranta LP vault on Base. Use agent_wallet, thirdfy, or hybrid. Relayer is default.',
336
+ example: 'thirdfy-agent actions --provider veranta-vault && thirdfy-agent run --action get_veranta_vault_info --provider veranta-vault --json',
337
+ formerlyKnownAs: 'Avantis LP vault',
338
+ supportedFundingSourceChains: [
339
+ {
340
+ chainId: 8453,
341
+ name: 'Base',
342
+ path: 'native USDC in managed execution wallet',
343
+ },
344
+ ],
345
+ }),
346
+ });