solana-traderclaw 1.0.59 → 1.0.60

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.
@@ -38,7 +38,7 @@
38
38
  agentId: "main",
39
39
  sessionTarget: "isolated",
40
40
  delivery: { mode: "none" },
41
- message: "CRON_JOB: source_reputation_recalc\n\nStep 1: Call solana_alpha_sources to get per-source performance stats.\n\nStep 2: Call solana_alpha_history to get recent signal history.\n\nStep 3: Call solana_trades to get recent trade outcomes. Cross-reference each trade to its originating signal source.\n\nStep 4: For each source, calculate: win rate, average PnL, signal-to-trade conversion rate.\n\nStep 5: Assign tier rankings:\n- TIER-1 (LOCK): Win rate above 60% AND 5+ trades AND positive avg PnL\n- TIER-2 (CONDITIONAL): Win rate 30-60% OR fewer than 5 trades\n- TIER-3 (BLACKLIST): Win rate below 30% with 5+ trades\n\nStep 6: Write scorecard to memory using solana_memory_write with tag 'source_reputation'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
41
+ message: "CRON_JOB: source_reputation_recalc\n\nStep 1: Call solana_alpha_sources to get per-source performance stats (signal count, conversion rate, avg score).\n\nStep 2: Call solana_alpha_history to get recent signal history with scores and source identifiers.\n\nStep 3: Call solana_trades to get recent trade outcomes. Cross-reference each trade back to its originating signal source.\n\nStep 4: For each source, calculate: win rate (trades that hit TP vs SL), average PnL per trade, signal-to-trade conversion rate.\n\nStep 5: Assign tier rankings:\n- TIER-1 (LOCK): Win rate above 60% AND 5+ trades AND positive avg PnL\n- TIER-2 (CONDITIONAL): Win rate 30-60% OR fewer than 5 trades\n- TIER-3 (BLACKLIST): Win rate below 30% with 5+ trades\n\nStep 6: Write scorecard to memory using solana_memory_write with tag 'source_reputation'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
42
42
  enabled: true
43
43
  },
44
44
 
@@ -49,7 +49,7 @@
49
49
  agentId: "main",
50
50
  sessionTarget: "isolated",
51
51
  delivery: { mode: "none" },
52
- message: "CRON_JOB: portfolio_risk_audit\n\nStep 1: Call solana_capital_status for wallet balance and portfolio value.\n\nStep 2: Call solana_positions for all open positions.\n\nStep 3: For each position, call solana_token_snapshot for current price and volume.\n\nStep 4: Run concentration check — flag WARNING if any position > 30% of portfolio, CRITICAL if > 50%.\n\nStep 5: Run exposure check — flag WARNING if total exposure > 50% of wallet, CRITICAL if > 75%.\n\nStep 6: Run drawdown check — CRITICAL if drawdown exceeds 25% from peak.\n\nStep 7: Calculate portfolio heat. Flag WARNING > 50%, CRITICAL > 75%.\n\nStep 8: Run liquidity check — WARNING if position > 2% of pool depth.\n\nStep 9: Check solana_killswitch_status.\n\nStep 10: Write risk report via solana_memory_write with tag 'risk_audit'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
52
+ message: "CRON_JOB: portfolio_risk_audit\n\nStep 1: Call solana_capital_status to get wallet balance and portfolio value.\n\nStep 2: Call solana_positions to get all open positions with entry prices and sizes.\n\nStep 3: For each open position, call solana_token_snapshot to get current price, 24h volume, and market cap.\n\nStep 4: Run concentration check — flag WARNING if any single position exceeds 30 percent of total portfolio value, CRITICAL if above 50 percent.\n\nStep 5: Run exposure check — flag WARNING if total exposure exceeds 50 percent of wallet balance, CRITICAL if above 75 percent.\n\nStep 6: Run drawdown check — CRITICAL if portfolio drawdown exceeds 25 percent from peak capital.\n\nStep 7: Calculate portfolio heat (sum of all position risk scores). Flag WARNING above 50 percent, CRITICAL above 75 percent.\n\nStep 8: Run liquidity check — WARNING if any position exceeds 2 percent of its pool depth.\n\nStep 9: Check solana_killswitch_status.\n\nStep 10: Write risk report via solana_memory_write with tag 'risk_audit'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
53
53
  enabled: true
54
54
  },
55
55
 
@@ -60,7 +60,7 @@
60
60
  agentId: "main",
61
61
  sessionTarget: "isolated",
62
62
  delivery: { mode: "none" },
63
- message: "CRON_JOB: meta_rotation_analysis\n\nStep 1: Call solana_scan_launches to get recent launches (last 3-6 hours).\n\nStep 2: Categorize each token by narrative cluster: AI/Agents, Animal Memes, Political, Celebrity/IP, DeFi, Gaming, Culture/Humor, Other.\n\nStep 3: For each cluster, aggregate: token count, total volume, average market cap.\n\nStep 4: Call solana_memory_search for 'meta_rotation' to compare with prior scan.\n\nStep 5: Classify each narrative: GAINING, SATURATED, COOLING, DORMANT.\n\nStep 6: Write rotation report via solana_memory_write with tag 'meta_rotation'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
63
+ message: "CRON_JOB: meta_rotation_analysis\n\nStep 0: Call x_search_tweets with queries: 'solana memecoin', 'pump fun gem', 'sol alpha'. Note which token names and narratives appear most frequently in the last 3 hours. Use this social signal to validate or challenge the on-chain data in the following steps.\n\nStep 1: Call solana_scan_launches to get recent token launches (last 3-6 hours).\n\nStep 2: Categorize each token by narrative cluster: AI/Agents, Animal Memes, Political, Celebrity/IP, DeFi, Gaming, Culture/Humor, Other.\n\nStep 3: For each cluster, aggregate: token count, total volume, average market cap.\n\nStep 4: Call solana_memory_search for 'meta_rotation' to compare with prior scan.\n\nStep 5: Classify each narrative: GAINING, SATURATED, COOLING, DORMANT.\n\nStep 6: Write rotation report via solana_memory_write with tag 'meta_rotation'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
64
64
  enabled: true
65
65
  },
66
66
 
@@ -80,7 +80,7 @@
80
80
  agentId: "main",
81
81
  sessionTarget: "isolated",
82
82
  delivery: { mode: "none" },
83
- message: "CRON_JOB: subscription_cleanup\n\nStep 1: Call solana_positions to get open position CAs.\n\nStep 2: Call solana_bitquery_subscriptions to list active subscriptions.\n\nStep 3: Build matched vs orphaned lists.\n\nStep 4: Unsubscribe orphans via solana_bitquery_unsubscribe.\n\nStep 5: Reopen subscriptions nearing 24h expiry via solana_bitquery_subscription_reopen.\n\nStep 6: Write summary via solana_memory_write with tag 'subscription_cleanup'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
83
+ message: "CRON_JOB: subscription_cleanup\n\nStep 1: Call solana_positions to get all open positions and extract their contract addresses.\n\nStep 2: Call solana_bitquery_subscriptions to list all active Bitquery subscriptions. If this call returns an AUTH_SCOPE_MISSING error, log the error to memory and stop gracefully — do not retry or error out.\n\nStep 3: For each active subscription, check if the associated token CA still has an open position. Build two lists: 'matched' (has position) and 'orphaned' (no position).\n\nStep 4: Unsubscribe orphans via solana_bitquery_unsubscribe.\n\nStep 5: Reopen subscriptions nearing 24h expiry via solana_bitquery_subscription_reopen.\n\nStep 6: Write summary via solana_memory_write with tag 'subscription_cleanup'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
84
84
  enabled: true
85
85
  },
86
86
 
@@ -38,7 +38,7 @@
38
38
  agentId: "main",
39
39
  sessionTarget: "isolated",
40
40
  delivery: { mode: "none" },
41
- message: "CRON_JOB: source_reputation_recalc\n\nStep 1: Call solana_alpha_sources to get per-source performance stats.\n\nStep 2: Call solana_alpha_history to get recent signal history.\n\nStep 3: Call solana_trades to get recent trade outcomes. Cross-reference each trade to its originating signal source.\n\nStep 4: For each source, calculate: win rate, average PnL, signal-to-trade conversion rate.\n\nStep 5: Assign tier rankings:\n- TIER-1 (LOCK): Win rate above 60% AND 5+ trades AND positive avg PnL\n- TIER-2 (CONDITIONAL): Win rate 30-60% OR fewer than 5 trades\n- TIER-3 (BLACKLIST): Win rate below 30% with 5+ trades\n\nStep 6: Write scorecard to memory using solana_memory_write with tag 'source_reputation'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
41
+ message: "CRON_JOB: source_reputation_recalc\n\nStep 1: Call solana_alpha_sources to get per-source performance stats (signal count, conversion rate, avg score).\n\nStep 2: Call solana_alpha_history to get recent signal history with scores and source identifiers.\n\nStep 3: Call solana_trades to get recent trade outcomes. Cross-reference each trade back to its originating signal source.\n\nStep 4: For each source, calculate: win rate (trades that hit TP vs SL), average PnL per trade, signal-to-trade conversion rate.\n\nStep 5: Assign tier rankings:\n- TIER-1 (LOCK): Win rate above 60% AND 5+ trades AND positive avg PnL\n- TIER-2 (CONDITIONAL): Win rate 30-60% OR fewer than 5 trades\n- TIER-3 (BLACKLIST): Win rate below 30% with 5+ trades\n\nStep 6: Write scorecard to memory using solana_memory_write with tag 'source_reputation'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
42
42
  enabled: true
43
43
  },
44
44
 
@@ -49,7 +49,7 @@
49
49
  agentId: "main",
50
50
  sessionTarget: "isolated",
51
51
  delivery: { mode: "none" },
52
- message: "CRON_JOB: portfolio_risk_audit\n\nStep 1: Call solana_capital_status for wallet balance and portfolio value.\n\nStep 2: Call solana_positions for all open positions.\n\nStep 3: For each position, call solana_token_snapshot for current price and volume.\n\nStep 4: Run concentration check — flag WARNING if any position > 30% of portfolio, CRITICAL if > 50%.\n\nStep 5: Run exposure check — flag WARNING if total exposure > 50% of wallet, CRITICAL if > 75%.\n\nStep 6: Run drawdown check — CRITICAL if drawdown exceeds 25% from peak.\n\nStep 7: Calculate portfolio heat. Flag WARNING > 50%, CRITICAL > 75%.\n\nStep 8: Run liquidity check — WARNING if position > 2% of pool depth.\n\nStep 9: Check solana_killswitch_status.\n\nStep 10: Write risk report via solana_memory_write with tag 'risk_audit'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
52
+ message: "CRON_JOB: portfolio_risk_audit\n\nStep 1: Call solana_capital_status to get wallet balance and portfolio value.\n\nStep 2: Call solana_positions to get all open positions with entry prices and sizes.\n\nStep 3: For each open position, call solana_token_snapshot to get current price, 24h volume, and market cap.\n\nStep 4: Run concentration check — flag WARNING if any single position exceeds 30 percent of total portfolio value, CRITICAL if above 50 percent.\n\nStep 5: Run exposure check — flag WARNING if total exposure exceeds 50 percent of wallet balance, CRITICAL if above 75 percent.\n\nStep 6: Run drawdown check — CRITICAL if portfolio drawdown exceeds 25 percent from peak capital.\n\nStep 7: Calculate portfolio heat (sum of all position risk scores). Flag WARNING above 50 percent, CRITICAL above 75 percent.\n\nStep 8: Run liquidity check — WARNING if any position exceeds 2 percent of its pool depth.\n\nStep 9: Check solana_killswitch_status.\n\nStep 10: Write risk report via solana_memory_write with tag 'risk_audit'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
53
53
  enabled: true
54
54
  },
55
55
 
@@ -80,7 +80,7 @@
80
80
  agentId: "main",
81
81
  sessionTarget: "isolated",
82
82
  delivery: { mode: "none" },
83
- message: "CRON_JOB: subscription_cleanup\n\nStep 1: Call solana_positions to get open position CAs.\n\nStep 2: Call solana_bitquery_subscriptions to list active subscriptions.\n\nStep 3: Build matched vs orphaned lists.\n\nStep 4: Unsubscribe orphans via solana_bitquery_unsubscribe.\n\nStep 5: Reopen subscriptions nearing 24h expiry via solana_bitquery_subscription_reopen.\n\nStep 6: Write summary via solana_memory_write with tag 'subscription_cleanup'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
83
+ message: "CRON_JOB: subscription_cleanup\n\nStep 1: Call solana_positions to get all open positions and extract their contract addresses.\n\nStep 2: Call solana_bitquery_subscriptions to list all active Bitquery subscriptions. If this call returns an AUTH_SCOPE_MISSING error, log the error to memory and stop gracefully — do not retry or error out.\n\nStep 3: For each active subscription, check if the associated token CA still has an open position. Build two lists: 'matched' (has position) and 'orphaned' (no position).\n\nStep 4: Unsubscribe orphans via solana_bitquery_unsubscribe.\n\nStep 5: Reopen subscriptions nearing 24h expiry via solana_bitquery_subscription_reopen.\n\nStep 6: Write summary via solana_memory_write with tag 'subscription_cleanup'.\n\nFORMATTING RULES:\n- Every token reference MUST use SYMBOL (full_CA) format.\n- Do not execute trades. Do not ask questions.",
84
84
  enabled: true
85
85
  },
86
86
 
@@ -26,7 +26,7 @@ async function doRequest(opts, isRetry = false) {
26
26
  headers,
27
27
  signal: controller.signal
28
28
  };
29
- if ((opts.method === "POST" || opts.method === "PUT") && opts.body) {
29
+ if ((opts.method === "POST" || opts.method === "PUT" || opts.method === "PATCH") && opts.body) {
30
30
  fetchOpts.body = JSON.stringify(opts.body);
31
31
  }
32
32
  const res = await fetch(url, fetchOpts);
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  } from "./chunk-3YPZOXWE.js";
19
19
  import {
20
20
  orchestratorRequest
21
- } from "./chunk-T4YWGIIR.js";
21
+ } from "./chunk-VUIYNUGF.js";
22
22
  import {
23
23
  IntelligenceLab
24
24
  } from "./chunk-C24QA3MQ.js";
@@ -1026,6 +1026,18 @@ var solanaTraderPlugin = {
1026
1026
  onUnauthorized
1027
1027
  });
1028
1028
  };
1029
+ const patch = async (apiPath, body) => {
1030
+ const token = await sessionManager.getAccessToken();
1031
+ return orchestratorRequest({
1032
+ baseUrl: orchestratorUrl,
1033
+ method: "PATCH",
1034
+ path: apiPath,
1035
+ body,
1036
+ timeout: apiTimeout,
1037
+ accessToken: token,
1038
+ onUnauthorized
1039
+ });
1040
+ };
1029
1041
  const del = async (apiPath) => {
1030
1042
  const token = await sessionManager.getAccessToken();
1031
1043
  return orchestratorRequest({
@@ -1466,7 +1478,12 @@ var solanaTraderPlugin = {
1466
1478
  description: "Advisory only \u2014 server decides position mode internally. Sent for future compatibility."
1467
1479
  })
1468
1480
  ),
1469
- idempotencyKey: Type.Optional(Type.String({ description: "Unique key to prevent duplicate executions (e.g., UUID). Server uses walletId + key for replay cache." }))
1481
+ idempotencyKey: Type.Optional(Type.String({ description: "Unique key to prevent duplicate executions (e.g., UUID). Server uses walletId + key for replay cache." })),
1482
+ agentId: Type.Optional(
1483
+ Type.String({
1484
+ description: "Optional agent id for gateway-forwarded notices (e.g. main). If omitted, the plugin config `agentId` is sent when set so default-risk messages reach the right agent."
1485
+ })
1486
+ )
1470
1487
  }),
1471
1488
  execute: wrapExecute("solana_trade_execute", async (_id, params) => {
1472
1489
  const headers = {};
@@ -1481,6 +1498,8 @@ var solanaTraderPlugin = {
1481
1498
  slPct: params.slPct,
1482
1499
  managementMode: params.managementMode
1483
1500
  };
1501
+ const execAgentId = typeof params.agentId === "string" && params.agentId.trim().length > 0 ? params.agentId.trim() : config.agentId && String(config.agentId).trim().length > 0 ? String(config.agentId).trim() : void 0;
1502
+ if (execAgentId) body.agentId = execAgentId;
1484
1503
  const tsExecute = params.trailingStop;
1485
1504
  if (tsExecute?.levels && Array.isArray(tsExecute.levels) && tsExecute.levels.length > 0) {
1486
1505
  body.trailingStop = tsExecute;
@@ -1700,7 +1719,7 @@ var solanaTraderPlugin = {
1700
1719
  });
1701
1720
  api.registerTool({
1702
1721
  name: "solana_positions",
1703
- description: "List trading positions with mark-to-market. **PnL:** for Solana wallets, `realizedPnl` / `unrealizedPnl` are returned in SOL-native units. `unrealizedReturnPct` is ROI on cost basis (for sweep-dead-tokens logic).",
1722
+ description: "List trading positions with mark-to-market. **PnL:** for Solana wallets, `realizedPnl` / `unrealizedPnl` are returned in SOL-native units. `unrealizedReturnPct` is ROI on cost basis (for sweep-dead-tokens logic). **Exit plan (source of truth):** use each position's `tpLevelsDetailed`, `slLevels`, `trailingStopPct`, `trailingStopLevels`, and `deadlockState.exits` \u2014 never guess exits from mode tables or memory.",
1704
1723
  parameters: Type.Object({
1705
1724
  status: Type.Optional(Type.String({ description: "Filter by status: 'open', 'closed', or omit for all" }))
1706
1725
  }),
@@ -1710,6 +1729,122 @@ var solanaTraderPlugin = {
1710
1729
  return get(reqPath);
1711
1730
  })
1712
1731
  });
1732
+ api.registerTool({
1733
+ name: "risk_management_get_default",
1734
+ description: "Read per-wallet default exit parameters used when a buy is executed **without** any TP/SL/trailing fields. Returns either the user's saved defaults or the platform system default (`source`: user | system).",
1735
+ parameters: Type.Object({}),
1736
+ execute: wrapExecute(
1737
+ "risk_management_get_default",
1738
+ async () => get(`/api/wallet/risk-defaults?walletId=${walletId}`)
1739
+ )
1740
+ });
1741
+ api.registerTool({
1742
+ name: "trade_size_limit_get",
1743
+ description: "Read the per-wallet maximum **buy** size in SOL enforced by the API (stored in `wallet.limits.maxTradeSizeSol`; platform default 1.5 SOL when unset). Always use this before sizing buys; never guess the limit.",
1744
+ parameters: Type.Object({}),
1745
+ execute: wrapExecute(
1746
+ "trade_size_limit_get",
1747
+ async () => get(`/api/wallet/max-trade-size?walletId=${walletId}`)
1748
+ )
1749
+ });
1750
+ api.registerTool({
1751
+ name: "trade_size_limit_set",
1752
+ description: "Set the per-wallet maximum buy size in SOL (persisted on the wallet `limits` JSON). Subject to a platform ceiling.",
1753
+ parameters: Type.Object({
1754
+ maxTradeSizeSol: Type.Number({ exclusiveMinimum: 0 })
1755
+ }),
1756
+ execute: wrapExecute(
1757
+ "trade_size_limit_set",
1758
+ async (_id, params) => put("/api/wallet/max-trade-size", {
1759
+ walletId,
1760
+ maxTradeSizeSol: params.maxTradeSizeSol
1761
+ })
1762
+ )
1763
+ });
1764
+ api.registerTool({
1765
+ name: "risk_management_set_default",
1766
+ description: "Save per-wallet default exit parameters (`tpExits`, `slExits`, `trailingStop.levels`) applied on buys that omit risk fields. Same shape as trade execute exit payloads.",
1767
+ parameters: Type.Object({
1768
+ tpExits: Type.Array(
1769
+ Type.Object({
1770
+ percent: Type.Number(),
1771
+ amountPct: Type.Number()
1772
+ }),
1773
+ { minItems: 1 }
1774
+ ),
1775
+ slExits: Type.Array(
1776
+ Type.Object({
1777
+ percent: Type.Number(),
1778
+ amountPct: Type.Number()
1779
+ }),
1780
+ { minItems: 1 }
1781
+ ),
1782
+ trailingStop: Type.Object({
1783
+ levels: Type.Array(
1784
+ Type.Object({
1785
+ percentage: Type.Number(),
1786
+ amount: Type.Optional(Type.Number()),
1787
+ triggerAboveATH: Type.Optional(Type.Number())
1788
+ }),
1789
+ { minItems: 1, maxItems: 5 }
1790
+ )
1791
+ })
1792
+ }),
1793
+ execute: wrapExecute(
1794
+ "risk_management_set_default",
1795
+ async (_id, params) => put("/api/wallet/risk-defaults", {
1796
+ walletId,
1797
+ tpExits: params.tpExits,
1798
+ slExits: params.slExits,
1799
+ trailingStop: params.trailingStop
1800
+ })
1801
+ )
1802
+ });
1803
+ api.registerTool({
1804
+ name: "position_risk_management_update",
1805
+ description: "Update **percentages and amounts only** on an open position's live exit plan (CaptureSell + stored position metadata). Cannot add or remove levels \u2014 array lengths must match the existing subscription. Use after entry when refining TP/SL/trailing numerics.",
1806
+ parameters: Type.Object({
1807
+ tokenAddress: Type.String({ description: "SPL mint for the open position" }),
1808
+ tpExits: Type.Optional(
1809
+ Type.Array(
1810
+ Type.Object({
1811
+ percent: Type.Number(),
1812
+ amountPct: Type.Number()
1813
+ })
1814
+ )
1815
+ ),
1816
+ slExits: Type.Optional(
1817
+ Type.Array(
1818
+ Type.Object({
1819
+ percent: Type.Number(),
1820
+ amountPct: Type.Number()
1821
+ })
1822
+ )
1823
+ ),
1824
+ trailingStop: Type.Optional(
1825
+ Type.Object({
1826
+ levels: Type.Array(
1827
+ Type.Object({
1828
+ percentage: Type.Number(),
1829
+ amount: Type.Optional(Type.Number()),
1830
+ triggerAboveATH: Type.Optional(Type.Number())
1831
+ }),
1832
+ { minItems: 1, maxItems: 5 }
1833
+ )
1834
+ })
1835
+ )
1836
+ }),
1837
+ execute: wrapExecute("position_risk_management_update", async (_id, params) => {
1838
+ const body = {
1839
+ walletId,
1840
+ tokenAddress: params.tokenAddress
1841
+ };
1842
+ if (params.tpExits) body.tpExits = params.tpExits;
1843
+ if (params.slExits) body.slExits = params.slExits;
1844
+ if (params.trailingStop) body.trailingStop = params.trailingStop;
1845
+ return patch("/api/position/risk-management", body);
1846
+ })
1847
+ });
1713
1848
  api.registerTool({
1714
1849
  name: "solana_wallet_token_balance",
1715
1850
  description: "Read on-chain SPL token balance (UI amount) for your trading wallet and a token mint. Same balance path as server exit monitoring (`balanceOf`).",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  orchestratorRequest
3
- } from "../chunk-T4YWGIIR.js";
3
+ } from "../chunk-VUIYNUGF.js";
4
4
  export {
5
5
  orchestratorRequest
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solana-traderclaw",
3
- "version": "1.0.59",
3
+ "version": "1.0.60",
4
4
  "description": "TraderClaw V1-Upgraded — Solana trading for OpenClaw with intelligence lab, tool envelopes, prompt scrubbing, read-only X social intel, and split skill docs",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -105,6 +105,8 @@ You operate in exactly one mode at a time. Default: `HARDENED`.
105
105
 
106
106
  ## Mode Parameters
107
107
 
108
+ *The exit percentages in this table (e.g. suggested `slExits` / `tpExits` ranges) are **illustrative mode targets** for planning — they are **not** the live exit configuration of any open position.*
109
+
108
110
  | Parameter | HARDENED | DEGEN |
109
111
  |---|---|---|
110
112
  | Entry confidence threshold | High (strong confluence) | Moderate (lower bar) |
@@ -130,6 +132,17 @@ You operate in exactly one mode at a time. Default: `HARDENED`.
130
132
  - `trailingStop`: `{ levels: [{ percentage: <trailing drawdown %>, amount: <% of position to sell, default 100>, triggerAboveATH: <% above session ATH to arm, default 100 = 2× ATH> }] }` — 1–5 tiered trailing stops. Use `trailingStopPct` for simpler single-level trailing.
131
133
  - `slippageBps`: REQUIRED on both precheck and execute. Positive integer, basis points (e.g. 300 = 3%). Scale to liquidity, hard cap 800bps.
132
134
 
135
+ ## Source of truth for exit configuration (mandatory)
136
+
137
+ - **Live** take-profit, stop-loss, and trailing-stop parameters for each **open** position come **only** from the orchestrator API via `solana_positions` (and related tools). Use the fields returned on each position row, especially: `tpLevelsDetailed`, `slLevels`, `trailingStopPct`, `trailingStopLevels`, and `deadlockState.exits` (including `trailingStopLevels` when present).
138
+ - **Never** invent, recall from chat history, or copy numbers from the **Mode Parameters** table above as if they were your current exits.
139
+ - If you need the **default** plan applied when a buy omitted risk fields, use `risk_management_get_default` (user override vs platform default). To change **defaults** for future buys, use `risk_management_set_default`. To adjust **numeric** TP/SL/trailing values on an **existing** position without adding or removing levels, use `position_risk_management_update`.
140
+
141
+ ## Maximum buy size in SOL (mandatory)
142
+
143
+ - The API enforces a per-wallet cap on **buy** `sizeSol` via `wallet.limits.maxTradeSizeSol` stored in Supabase on the same `limits` JSON as other risk knobs (default **1.5 SOL** when the key is absent).
144
+ - **Never** invent or recall a max size from mode tables or memory. Before proposing or executing a buy, call `trade_size_limit_get`. When the user wants a different cap, use `trade_size_limit_set` (subject to a platform ceiling).
145
+
133
146
  ## Position Execution Model (Authoritative)
134
147
 
135
148
  This section defines the UNIQUE valid interpretation of all exit-related parameters.
@@ -13,7 +13,7 @@ Things like:
13
13
  - Rate limit observations
14
14
  - Anything environment-specific
15
15
 
16
- ## Tool Inventory (98 tools — 95 Solana + 3 X read-only)
16
+ ## Tool Inventory (101 tools — 98 Solana + 3 X read-only)
17
17
 
18
18
  Every tool has a mandatory trigger — when the trigger condition is met, you MUST call the tool. "Cron-only" tools are called during cron jobs, not the heartbeat fast loop.
19
19
 
@@ -27,7 +27,7 @@ Every tool has a mandatory trigger — when the trigger condition is met, you MU
27
27
  | `solana_gateway_credentials_set` | Register gateway URL and token | When gateway is not registered (startup) |
28
28
  | `solana_gateway_forward_probe` | Test forwarding path health | Startup sequence; when events stop arriving |
29
29
 
30
- ### Wallet & Capital (8)
30
+ ### Wallet & Capital (11)
31
31
  | Tool | Purpose | When to Call |
32
32
  |---|---|---|
33
33
  | `solana_wallets` | List all wallets | Startup; when user asks about wallets |
@@ -38,6 +38,11 @@ Every tool has a mandatory trigger — when the trigger condition is met, you MU
38
38
  | `solana_sweep_dead_tokens` | Batch-exit losing positions | `dead_money_sweep` cron; Step 0 when multiple dead positions found |
39
39
  | `solana_killswitch_status` | Check kill switch state | Step 0 every heartbeat |
40
40
  | `solana_killswitch` | Toggle kill switch (enabled + mode) | When consecutive loss limit hit; when user requests |
41
+ | `risk_management_get_default` | Read per-wallet default TP/SL/trailing used when buys omit risk | Before relying on implicit defaults; after user asks about protection |
42
+ | `risk_management_set_default` | Save per-wallet default exit plan for future buys | When user or policy wants custom defaults instead of platform system default |
43
+ | `trade_size_limit_get` | Read max **buy** size (SOL) from wallet `limits` (default 1.5) | Before every buy or when user asks about size limits |
44
+ | `trade_size_limit_set` | Set max **buy** size (SOL) on wallet `limits` | When user asks to change the per-order cap |
45
+ | `position_risk_management_update` | Adjust TP/SL/trailing **numbers** on an open position (same level count) | After entry when refining exits without removing levels |
41
46
 
42
47
  ### Scanning & Discovery (4)
43
48
  | Tool | Purpose | When to Call |