@reefclaw/openclaw-plugin 0.1.20 → 0.1.21
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.
- package/bridge/bridge.d.ts +10 -0
- package/bridge/bridge.js +142 -22
- package/bridge/gateway/tool-discovery.d.ts +1 -1
- package/bridge/gateway/tool-discovery.js +11 -0
- package/bridge/provider.d.ts +73 -6
- package/bridge/providers/gateway.d.ts +12 -3
- package/bridge/providers/gateway.js +18 -5
- package/bridge/providers/onboarding-commands.d.ts +33 -7
- package/bridge/providers/onboarding-commands.js +109 -13
- package/bridge/types.d.ts +1 -1
- package/bridge/types.js +5 -0
- package/ccxt/binance-private.js +6 -0
- package/config/tool-gate.js +4 -0
- package/index.js +77 -12
- package/ingest/readiness-reporter.js +25 -1
- package/openclaw.plugin.json +3 -1
- package/package.json +1 -1
- package/security/sealed-credentials.d.ts +38 -0
- package/security/sealed-credentials.js +180 -0
- package/tools/clear-exchange-credentials.js +16 -3
- package/tools/hl-agent-wallet-status.d.ts +29 -0
- package/tools/hl-agent-wallet-status.js +100 -0
- package/tools/hl-provision-agent-wallet.d.ts +35 -0
- package/tools/hl-provision-agent-wallet.js +144 -0
- package/tools/set-exchange-credentials.d.ts +32 -3
- package/tools/set-exchange-credentials.js +144 -32
- package/tools/set-trading-mode.d.ts +7 -0
- package/tools/set-trading-mode.js +15 -0
- package/tools/test-exchange-credentials.d.ts +30 -3
- package/tools/test-exchange-credentials.js +173 -35
- package/types.d.ts +10 -11
- package/venues/hyperliquid/hl-agent-wallet.d.ts +29 -0
- package/venues/hyperliquid/hl-agent-wallet.js +118 -0
- package/venues/hyperliquid/hl-preflight.d.ts +28 -0
- package/venues/hyperliquid/hl-preflight.js +116 -0
package/bridge/bridge.d.ts
CHANGED
|
@@ -92,6 +92,12 @@ export declare class Bridge {
|
|
|
92
92
|
* frame. Ladder validation runs here for fast dashboard feedback and
|
|
93
93
|
* again in the plugin (defense in depth). */
|
|
94
94
|
private handleSetTradingMode;
|
|
95
|
+
/** Parse + validate the per-venue credential fields shared by the set/test
|
|
96
|
+
* handlers. Secrets (Binance secret / HL agent key) pass through once and
|
|
97
|
+
* are never cached or logged — the returned fingerprint is the Binance
|
|
98
|
+
* apiKey prefix or the PUBLIC HL master address, never secret material.
|
|
99
|
+
* Returns null after writing a 400 response when validation fails. */
|
|
100
|
+
private parseExchangeCredentialParams;
|
|
95
101
|
/** Handle a set_exchange_credentials request. The secret value passes
|
|
96
102
|
* through once and is never cached or logged; only a redacted fingerprint
|
|
97
103
|
* appears in the audit trail. */
|
|
@@ -100,6 +106,10 @@ export declare class Bridge {
|
|
|
100
106
|
* verification, nothing persisted. Same input validation + secret
|
|
101
107
|
* redaction rules as set_exchange_credentials. */
|
|
102
108
|
private handleTestExchangeCredentials;
|
|
109
|
+
/** Handle an hl_provision_agent_wallet request — the guided HL onboarding's
|
|
110
|
+
* key-minting step. Nothing secret transits in either direction: request =
|
|
111
|
+
* public master address, response = public agent address. */
|
|
112
|
+
private handleProvisionHlAgentWallet;
|
|
103
113
|
/** Handle a clear_exchange_credentials request. No input — the method
|
|
104
114
|
* itself is the "yes I want this" signal; the webapp is expected to
|
|
105
115
|
* gate this behind a confirmation dialog before calling. */
|
package/bridge/bridge.js
CHANGED
|
@@ -498,6 +498,27 @@ export class Bridge {
|
|
|
498
498
|
this.connector.sendResponse(id, true, result);
|
|
499
499
|
return;
|
|
500
500
|
}
|
|
501
|
+
if (method === 'hl_provision_agent_wallet') {
|
|
502
|
+
const result = await this.handleProvisionHlAgentWallet(id, params);
|
|
503
|
+
if (result !== 'responded') {
|
|
504
|
+
this.connector.sendResponse(id, true, result);
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (method === 'hl_agent_wallet_status') {
|
|
509
|
+
const provider = this.provider;
|
|
510
|
+
if (!provider.getHlAgentWalletStatus) {
|
|
511
|
+
this.connector.sendResponse(id, true, {
|
|
512
|
+
ok: false,
|
|
513
|
+
message: 'Provider does not support hl_agent_wallet_status (likely mock provider)',
|
|
514
|
+
configured: false,
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const result = await provider.getHlAgentWalletStatus();
|
|
519
|
+
this.connector.sendResponse(id, true, result);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
501
522
|
if (method === 'get_bracket_config') {
|
|
502
523
|
if (!this.provider.getBracketConfig) {
|
|
503
524
|
this.connector.sendResponse(id, false, undefined, {
|
|
@@ -671,21 +692,72 @@ export class Bridge {
|
|
|
671
692
|
}
|
|
672
693
|
return outcome;
|
|
673
694
|
}
|
|
674
|
-
/**
|
|
675
|
-
*
|
|
676
|
-
*
|
|
677
|
-
|
|
695
|
+
/** Parse + validate the per-venue credential fields shared by the set/test
|
|
696
|
+
* handlers. Secrets (Binance secret / HL agent key) pass through once and
|
|
697
|
+
* are never cached or logged — the returned fingerprint is the Binance
|
|
698
|
+
* apiKey prefix or the PUBLIC HL master address, never secret material.
|
|
699
|
+
* Returns null after writing a 400 response when validation fails. */
|
|
700
|
+
parseExchangeCredentialParams(id, params) {
|
|
701
|
+
// Sealed envelope: the browser encrypted the credential payload to the
|
|
702
|
+
// BOX's transport key — the bridge cannot read it and must not try.
|
|
703
|
+
// Forward opaquely; the plugin decrypts and runs the full validation.
|
|
704
|
+
if (params?.sealed != null) {
|
|
705
|
+
const sealed = params.sealed;
|
|
706
|
+
if (typeof sealed !== 'object' || Array.isArray(sealed)) {
|
|
707
|
+
this.connector.sendResponse(id, false, undefined, {
|
|
708
|
+
code: 400,
|
|
709
|
+
message: 'sealed must be an envelope object',
|
|
710
|
+
});
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
const kid = sealed.kid;
|
|
714
|
+
return {
|
|
715
|
+
req: { sealed: sealed },
|
|
716
|
+
fp: `sealed:${typeof kid === 'string' ? kid.slice(0, 16) : 'unknown'}`,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
const testnet = params?.testnet === true;
|
|
720
|
+
if (params?.venue === 'hyperliquid') {
|
|
721
|
+
const walletAddress = typeof params?.walletAddress === 'string' ? params.walletAddress.trim() : '';
|
|
722
|
+
const agentPrivateKey = typeof params?.agentPrivateKey === 'string' ? params.agentPrivateKey.trim() : '';
|
|
723
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(walletAddress)) {
|
|
724
|
+
this.connector.sendResponse(id, false, undefined, {
|
|
725
|
+
code: 400,
|
|
726
|
+
message: 'walletAddress must be your MASTER account address: 0x followed by 40 hex characters',
|
|
727
|
+
});
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
730
|
+
if (!/^(0x)?[0-9a-fA-F]{64}$/.test(agentPrivateKey)) {
|
|
731
|
+
this.connector.sendResponse(id, false, undefined, {
|
|
732
|
+
code: 400,
|
|
733
|
+
message: 'agentPrivateKey must be an agent (API) wallet private key: 64 hex characters (0x prefix optional)',
|
|
734
|
+
});
|
|
735
|
+
return null;
|
|
736
|
+
}
|
|
737
|
+
return {
|
|
738
|
+
req: { venue: 'hyperliquid', walletAddress, agentPrivateKey, testnet },
|
|
739
|
+
fp: fingerprint(walletAddress),
|
|
740
|
+
};
|
|
741
|
+
}
|
|
678
742
|
const apiKey = typeof params?.apiKey === 'string' ? params.apiKey : '';
|
|
679
743
|
const secret = typeof params?.secret === 'string' ? params.secret : '';
|
|
680
|
-
const testnet = params?.testnet === true;
|
|
681
744
|
if (apiKey.length < 8 || secret.length < 8) {
|
|
682
745
|
this.connector.sendResponse(id, false, undefined, {
|
|
683
746
|
code: 400,
|
|
684
747
|
message: 'apiKey and secret must be at least 8 characters each',
|
|
685
748
|
});
|
|
686
|
-
return
|
|
749
|
+
return null;
|
|
687
750
|
}
|
|
688
|
-
|
|
751
|
+
return { req: { venue: 'binance', apiKey, secret, testnet }, fp: fingerprint(apiKey) };
|
|
752
|
+
}
|
|
753
|
+
/** Handle a set_exchange_credentials request. The secret value passes
|
|
754
|
+
* through once and is never cached or logged; only a redacted fingerprint
|
|
755
|
+
* appears in the audit trail. */
|
|
756
|
+
async handleSetExchangeCredentials(id, params) {
|
|
757
|
+
const parsed = this.parseExchangeCredentialParams(id, params);
|
|
758
|
+
if (!parsed)
|
|
759
|
+
return 'responded';
|
|
760
|
+
const { req, fp } = parsed;
|
|
689
761
|
const provider = this.provider;
|
|
690
762
|
if (!provider.setExchangeCredentials) {
|
|
691
763
|
return {
|
|
@@ -697,13 +769,20 @@ export class Bridge {
|
|
|
697
769
|
readiness: 'UNKNOWN',
|
|
698
770
|
};
|
|
699
771
|
}
|
|
700
|
-
audit('set_exchange_credentials.start', {
|
|
701
|
-
|
|
772
|
+
audit('set_exchange_credentials.start', {
|
|
773
|
+
id,
|
|
774
|
+
venue: 'sealed' in req ? 'sealed' : req.venue,
|
|
775
|
+
fingerprint: fp,
|
|
776
|
+
testnet: 'testnet' in req ? req.testnet === true : undefined,
|
|
777
|
+
});
|
|
778
|
+
const outcome = await provider.setExchangeCredentials(req);
|
|
702
779
|
audit('set_exchange_credentials.complete', {
|
|
703
780
|
id,
|
|
704
781
|
ok: outcome.ok,
|
|
782
|
+
venue: outcome.venue,
|
|
705
783
|
fingerprint: outcome.fingerprint,
|
|
706
784
|
reconnected: outcome.reconnected,
|
|
785
|
+
restartRequired: outcome.restartRequired === true,
|
|
707
786
|
mode: outcome.mode,
|
|
708
787
|
});
|
|
709
788
|
return outcome;
|
|
@@ -712,17 +791,10 @@ export class Bridge {
|
|
|
712
791
|
* verification, nothing persisted. Same input validation + secret
|
|
713
792
|
* redaction rules as set_exchange_credentials. */
|
|
714
793
|
async handleTestExchangeCredentials(id, params) {
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
const testnet = params?.testnet === true;
|
|
718
|
-
if (apiKey.length < 8 || secret.length < 8) {
|
|
719
|
-
this.connector.sendResponse(id, false, undefined, {
|
|
720
|
-
code: 400,
|
|
721
|
-
message: 'apiKey and secret must be at least 8 characters each',
|
|
722
|
-
});
|
|
794
|
+
const parsed = this.parseExchangeCredentialParams(id, params);
|
|
795
|
+
if (!parsed)
|
|
723
796
|
return 'responded';
|
|
724
|
-
}
|
|
725
|
-
const fp = fingerprint(apiKey);
|
|
797
|
+
const { req, fp } = parsed;
|
|
726
798
|
const provider = this.provider;
|
|
727
799
|
if (!provider.testExchangeCredentials) {
|
|
728
800
|
return {
|
|
@@ -732,19 +804,67 @@ export class Bridge {
|
|
|
732
804
|
canReadBalance: false,
|
|
733
805
|
canReadPositions: false,
|
|
734
806
|
balanceUSDT: null,
|
|
735
|
-
testnet,
|
|
807
|
+
testnet: 'testnet' in req ? req.testnet === true : false,
|
|
736
808
|
errors: ['provider-unsupported'],
|
|
737
809
|
};
|
|
738
810
|
}
|
|
739
|
-
audit('test_exchange_credentials.start', {
|
|
740
|
-
|
|
811
|
+
audit('test_exchange_credentials.start', {
|
|
812
|
+
id,
|
|
813
|
+
venue: 'sealed' in req ? 'sealed' : req.venue,
|
|
814
|
+
fingerprint: fp,
|
|
815
|
+
testnet: 'testnet' in req ? req.testnet === true : undefined,
|
|
816
|
+
});
|
|
817
|
+
const outcome = await provider.testExchangeCredentials(req);
|
|
741
818
|
audit('test_exchange_credentials.complete', {
|
|
742
819
|
id,
|
|
743
820
|
ok: outcome.ok,
|
|
821
|
+
venue: outcome.venue,
|
|
744
822
|
fingerprint: outcome.fingerprint,
|
|
745
823
|
canReadBalance: outcome.canReadBalance,
|
|
746
824
|
canReadPositions: outcome.canReadPositions,
|
|
747
825
|
balanceUSDT: outcome.balanceUSDT,
|
|
826
|
+
agentApproved: outcome.agentApproved,
|
|
827
|
+
});
|
|
828
|
+
return outcome;
|
|
829
|
+
}
|
|
830
|
+
/** Handle an hl_provision_agent_wallet request — the guided HL onboarding's
|
|
831
|
+
* key-minting step. Nothing secret transits in either direction: request =
|
|
832
|
+
* public master address, response = public agent address. */
|
|
833
|
+
async handleProvisionHlAgentWallet(id, params) {
|
|
834
|
+
const walletAddress = typeof params?.walletAddress === 'string' ? params.walletAddress.trim() : '';
|
|
835
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(walletAddress)) {
|
|
836
|
+
this.connector.sendResponse(id, false, undefined, {
|
|
837
|
+
code: 400,
|
|
838
|
+
message: 'walletAddress must be your MASTER account address: 0x followed by 40 hex characters',
|
|
839
|
+
});
|
|
840
|
+
return 'responded';
|
|
841
|
+
}
|
|
842
|
+
const provider = this.provider;
|
|
843
|
+
if (!provider.provisionHlAgentWallet) {
|
|
844
|
+
return {
|
|
845
|
+
ok: false,
|
|
846
|
+
message: 'Provider does not support hl_provision_agent_wallet (likely mock provider)',
|
|
847
|
+
venue: 'hyperliquid',
|
|
848
|
+
mode: this.lastKnownTradingMode ?? 'PAPER',
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
audit('hl_provision_agent_wallet.start', {
|
|
852
|
+
id,
|
|
853
|
+
master: fingerprint(walletAddress),
|
|
854
|
+
testnet: params?.testnet === true,
|
|
855
|
+
regenerate: params?.regenerate === true,
|
|
856
|
+
});
|
|
857
|
+
const outcome = await provider.provisionHlAgentWallet({
|
|
858
|
+
walletAddress,
|
|
859
|
+
testnet: params?.testnet === true,
|
|
860
|
+
regenerate: params?.regenerate === true,
|
|
861
|
+
});
|
|
862
|
+
audit('hl_provision_agent_wallet.complete', {
|
|
863
|
+
id,
|
|
864
|
+
ok: outcome.ok,
|
|
865
|
+
agentAddress: outcome.agentAddress, // public — the point of the flow
|
|
866
|
+
existing: outcome.existing === true,
|
|
867
|
+
restartRequired: outcome.restartRequired === true,
|
|
748
868
|
});
|
|
749
869
|
return outcome;
|
|
750
870
|
}
|
|
@@ -3,7 +3,7 @@ import { GatewayHttpClient, GatewayHttpError } from './gateway-http-client.js';
|
|
|
3
3
|
* Logical tool names used by ReefClaw internally.
|
|
4
4
|
* Each maps to one or more candidate actual tool names on the gateway.
|
|
5
5
|
*/
|
|
6
|
-
export type LogicalTool = 'fetch_ticker' | 'fetch_balance' | 'fetch_ohlcv' | 'fetch_positions' | 'fetch_open_orders' | 'cancel_all_orders' | 'cancel_order' | 'close_position' | 'create_order' | 'get_market_structure' | 'get_crypto_metrics' | 'get_market_intel' | 'set_trading_mode' | 'set_exchange_credentials' | 'test_exchange_credentials' | 'clear_exchange_credentials' | 'get_bracket_config' | 'set_bracket_requirement';
|
|
6
|
+
export type LogicalTool = 'fetch_ticker' | 'fetch_balance' | 'fetch_ohlcv' | 'fetch_positions' | 'fetch_open_orders' | 'cancel_all_orders' | 'cancel_order' | 'close_position' | 'create_order' | 'get_market_structure' | 'get_crypto_metrics' | 'get_market_intel' | 'set_trading_mode' | 'set_exchange_credentials' | 'test_exchange_credentials' | 'clear_exchange_credentials' | 'hl_provision_agent_wallet' | 'hl_agent_wallet_status' | 'get_bracket_config' | 'set_bracket_requirement';
|
|
7
7
|
/**
|
|
8
8
|
* Build the test args used when probing each logical tool.
|
|
9
9
|
*
|
|
@@ -20,6 +20,8 @@ const OPTIONAL_TOOLS = [
|
|
|
20
20
|
'set_exchange_credentials',
|
|
21
21
|
'test_exchange_credentials',
|
|
22
22
|
'clear_exchange_credentials',
|
|
23
|
+
'hl_provision_agent_wallet',
|
|
24
|
+
'hl_agent_wallet_status',
|
|
23
25
|
'get_bracket_config',
|
|
24
26
|
'set_bracket_requirement',
|
|
25
27
|
];
|
|
@@ -44,6 +46,8 @@ const CANDIDATES = {
|
|
|
44
46
|
set_exchange_credentials: ['set_exchange_credentials'],
|
|
45
47
|
test_exchange_credentials: ['test_exchange_credentials'],
|
|
46
48
|
clear_exchange_credentials: ['clear_exchange_credentials'],
|
|
49
|
+
hl_provision_agent_wallet: ['hl_provision_agent_wallet'],
|
|
50
|
+
hl_agent_wallet_status: ['hl_agent_wallet_status'],
|
|
47
51
|
get_bracket_config: ['get_bracket_config'],
|
|
48
52
|
set_bracket_requirement: ['set_bracket_requirement'],
|
|
49
53
|
};
|
|
@@ -108,6 +112,13 @@ export function buildProbeArgs(symbol = DEFAULT_PROBE_SYMBOL) {
|
|
|
108
112
|
// clear_exchange_credentials: tool requires confirm:true. Probing without
|
|
109
113
|
// it triggers the safety gate early-return — tool exists, nothing wiped.
|
|
110
114
|
clear_exchange_credentials: {},
|
|
115
|
+
// Provision: empty walletAddress fails the 0x-hex validator before any
|
|
116
|
+
// key is minted or written. Status: `probe:true` is the tool's dedicated
|
|
117
|
+
// discovery path — it returns before touching config or the network (a
|
|
118
|
+
// real status call runs HL /info reads that could outlive the 8s probe
|
|
119
|
+
// timeout and mark the tool missing forever).
|
|
120
|
+
hl_provision_agent_wallet: { walletAddress: '' },
|
|
121
|
+
hl_agent_wallet_status: { probe: true },
|
|
111
122
|
// Bracket-config probes: no-arg read; set with an invalid flag triggers early-return.
|
|
112
123
|
get_bracket_config: {},
|
|
113
124
|
set_bracket_requirement: { flag: '__probe__', value: false },
|
package/bridge/provider.d.ts
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
import type { EmergencyAction, ReconciliationSnapshot, TickerData, CandleData, OrderUpdatePayload, AgentStateData, RiskUpdatePayload, ChatMessage, MarketStructureData, CryptoMetricsData, VolumeAnalysisData, TradeJournalEntry, RegimeData, SignalData, MissionData, AnalyticsData, ShadowComparisonData, TradingModeData, DecisionTraceData } from './types.js';
|
|
2
2
|
import type { TradingMode } from '@reefclaw/shared';
|
|
3
|
+
/** Per-venue credential shapes for the operator set/test RPCs. Binance is an
|
|
4
|
+
* HMAC key pair; Hyperliquid is a MASTER account address (public — queries)
|
|
5
|
+
* plus an approved AGENT wallet private key (signs only, cannot withdraw).
|
|
6
|
+
* The `sealed` variant carries an end-to-end encrypted envelope the browser
|
|
7
|
+
* sealed to the box's transport key — the bridge forwards it OPAQUELY (it
|
|
8
|
+
* cannot and must not read it); all validation happens plugin-side after
|
|
9
|
+
* decryption. A discriminated union so a caller can never mix the shapes. */
|
|
10
|
+
export type ExchangeCredentialsRequest = {
|
|
11
|
+
venue: 'binance';
|
|
12
|
+
apiKey: string;
|
|
13
|
+
secret: string;
|
|
14
|
+
testnet?: boolean;
|
|
15
|
+
} | {
|
|
16
|
+
venue: 'hyperliquid';
|
|
17
|
+
walletAddress: string;
|
|
18
|
+
agentPrivateKey: string;
|
|
19
|
+
testnet?: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
sealed: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
/** Result of hl_provision_agent_wallet — the box-generated agent wallet. */
|
|
24
|
+
export interface HlProvisionOutcome {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
message: string;
|
|
27
|
+
venue: 'hyperliquid';
|
|
28
|
+
agentAddress?: string;
|
|
29
|
+
masterAddress?: string;
|
|
30
|
+
testnet?: boolean;
|
|
31
|
+
existing?: boolean;
|
|
32
|
+
masterMatches?: boolean;
|
|
33
|
+
restartRequired?: boolean;
|
|
34
|
+
mode: string;
|
|
35
|
+
}
|
|
36
|
+
/** Result of hl_agent_wallet_status — approval polling for the guided flow. */
|
|
37
|
+
export interface HlAgentWalletStatusOutcome {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
message: string;
|
|
40
|
+
configured: boolean;
|
|
41
|
+
masterAddress?: string;
|
|
42
|
+
agentAddress?: string;
|
|
43
|
+
testnet?: boolean;
|
|
44
|
+
approved?: boolean | null;
|
|
45
|
+
validUntil?: number | null;
|
|
46
|
+
balanceUSDC?: number | null;
|
|
47
|
+
warnings?: string[];
|
|
48
|
+
restartRequired?: boolean;
|
|
49
|
+
}
|
|
3
50
|
/** Fill error data emitted when a limit fill fails */
|
|
4
51
|
export interface FillErrorData {
|
|
5
52
|
orderId: string;
|
|
@@ -95,19 +142,24 @@ export interface OpenClawProvider {
|
|
|
95
142
|
readiness: string;
|
|
96
143
|
reason?: string;
|
|
97
144
|
}>;
|
|
98
|
-
/** Operator-only: set
|
|
99
|
-
* to the plugin-local config file and never retained
|
|
100
|
-
|
|
145
|
+
/** Operator-only: set exchange credentials, per venue. The raw secret /
|
|
146
|
+
* agent key is written to the plugin-local config file and never retained
|
|
147
|
+
* by the skill. */
|
|
148
|
+
setExchangeCredentials?(req: ExchangeCredentialsRequest): Promise<{
|
|
101
149
|
ok: boolean;
|
|
102
150
|
message: string;
|
|
103
151
|
fingerprint: string;
|
|
104
152
|
reconnected: boolean;
|
|
105
153
|
mode: TradingMode;
|
|
106
154
|
readiness: string;
|
|
155
|
+
venue?: string;
|
|
156
|
+
/** True when the stored venue differs from the booted venue — the
|
|
157
|
+
* operator must restart the agent before the change takes effect. */
|
|
158
|
+
restartRequired?: boolean;
|
|
107
159
|
}>;
|
|
108
|
-
/** Operator-only: verify
|
|
109
|
-
*
|
|
110
|
-
testExchangeCredentials?(
|
|
160
|
+
/** Operator-only: verify exchange credentials with transient read-only
|
|
161
|
+
* calls, per venue. Nothing is persisted. */
|
|
162
|
+
testExchangeCredentials?(req: ExchangeCredentialsRequest): Promise<{
|
|
111
163
|
ok: boolean;
|
|
112
164
|
message: string;
|
|
113
165
|
fingerprint: string;
|
|
@@ -116,7 +168,22 @@ export interface OpenClawProvider {
|
|
|
116
168
|
balanceUSDT: number | null;
|
|
117
169
|
testnet: boolean;
|
|
118
170
|
errors: string[];
|
|
171
|
+
venue?: string;
|
|
172
|
+
agentAddress?: string;
|
|
173
|
+
agentApproved?: boolean | null;
|
|
174
|
+
agentValidUntil?: number | null;
|
|
175
|
+
warnings?: string[];
|
|
119
176
|
}>;
|
|
177
|
+
/** Operator-only: generate a Hyperliquid agent wallet ON the trader's box
|
|
178
|
+
* (the private key never leaves it) and return the public address. */
|
|
179
|
+
provisionHlAgentWallet?(args: {
|
|
180
|
+
walletAddress: string;
|
|
181
|
+
testnet?: boolean;
|
|
182
|
+
regenerate?: boolean;
|
|
183
|
+
}): Promise<HlProvisionOutcome>;
|
|
184
|
+
/** Operator-only: approval/balance status of the box's provisioned HL agent
|
|
185
|
+
* wallet (polled by the dashboard's guided flow after the wallet signature). */
|
|
186
|
+
getHlAgentWalletStatus?(): Promise<HlAgentWalletStatusOutcome>;
|
|
120
187
|
/** Operator-only: remove stored credentials from the plugin config and
|
|
121
188
|
* de-escalate to PAPER mode if currently running in a live mode. */
|
|
122
189
|
clearExchangeCredentials?(): Promise<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OpenClawProvider, ProviderEvents, ProviderEventName } from '../provider.js';
|
|
1
|
+
import type { OpenClawProvider, ProviderEvents, ProviderEventName, ExchangeCredentialsRequest, HlProvisionOutcome, HlAgentWalletStatusOutcome } from '../provider.js';
|
|
2
2
|
import type { EmergencyAction, ReconciliationSnapshot, TradingMode } from '../types.js';
|
|
3
3
|
import type { GatewayConfig } from '../gateway/gateway-config.js';
|
|
4
4
|
import { type GetBracketConfigOutcome, type SetBracketRequirementOutcome, type BracketRequirementFlag, type SetTradingModeOutcome, type SetExchangeCredentialsOutcome, type TestExchangeCredentialsOutcome, type ClearExchangeCredentialsOutcome } from './onboarding-commands.js';
|
|
@@ -218,9 +218,18 @@ export declare class GatewayProvider implements OpenClawProvider {
|
|
|
218
218
|
error?: string;
|
|
219
219
|
}>;
|
|
220
220
|
setTradingMode(mode: TradingMode, acknowledged?: boolean): Promise<SetTradingModeOutcome>;
|
|
221
|
-
setExchangeCredentials(
|
|
222
|
-
testExchangeCredentials(
|
|
221
|
+
setExchangeCredentials(req: ExchangeCredentialsRequest): Promise<SetExchangeCredentialsOutcome>;
|
|
222
|
+
testExchangeCredentials(req: ExchangeCredentialsRequest): Promise<TestExchangeCredentialsOutcome>;
|
|
223
223
|
clearExchangeCredentials(): Promise<ClearExchangeCredentialsOutcome>;
|
|
224
|
+
/** Operator-only. Mint an HL agent wallet on the box; returns the public
|
|
225
|
+
* address only (guided onboarding). */
|
|
226
|
+
provisionHlAgentWallet(args: {
|
|
227
|
+
walletAddress: string;
|
|
228
|
+
testnet?: boolean;
|
|
229
|
+
regenerate?: boolean;
|
|
230
|
+
}): Promise<HlProvisionOutcome>;
|
|
231
|
+
/** Operator-only. Approval/balance status of the provisioned HL wallet. */
|
|
232
|
+
getHlAgentWalletStatus(): Promise<HlAgentWalletStatusOutcome>;
|
|
224
233
|
/** Operator-only. Read the current bracket-orders config from the plugin. */
|
|
225
234
|
getBracketConfig(): Promise<GetBracketConfigOutcome>;
|
|
226
235
|
/** Operator-only. Flip requireStopLoss or requireTakeProfit. */
|
|
@@ -17,7 +17,7 @@ import { ensureHeartbeatCron, isHeartbeatLikeName } from '../gateway/heartbeat-c
|
|
|
17
17
|
import { parseIdentityName } from '../utils/identity-name.js';
|
|
18
18
|
import { computeEquity as _computeEquity, computePositionNotional as _computePositionNotional, computeRiskMetrics as _computeRiskMetrics, DEFAULT_RISK_LIMITS, DRAWDOWN_ZONE_THRESHOLDS, TENANT_LIMIT_BOUNDS, boundedNum, validateDrawdownLadder, } from './risk-calculator.js';
|
|
19
19
|
import { executeKill as _executeKill, executeFlatten as _executeFlatten, executePause as _executePause, executeResume as _executeResume, } from './emergency-commands.js';
|
|
20
|
-
import { executeSetTradingMode, executeGetBracketConfig, executeSetBracketRequirement, executeSetExchangeCredentials, executeTestExchangeCredentials, executeClearExchangeCredentials, } from './onboarding-commands.js';
|
|
20
|
+
import { executeSetTradingMode, executeGetBracketConfig, executeSetBracketRequirement, executeSetExchangeCredentials, executeTestExchangeCredentials, executeClearExchangeCredentials, executeProvisionHlAgentWallet, executeHlAgentWalletStatus, } from './onboarding-commands.js';
|
|
21
21
|
const TAG = 'gateway';
|
|
22
22
|
// ---- Day-start NAV persistence ----
|
|
23
23
|
// Persists sessionStartNav (the UTC-day P&L anchor) per date so Day P&L
|
|
@@ -684,14 +684,14 @@ export class GatewayProvider {
|
|
|
684
684
|
// four state-mutating operator tools without it (audit F12).
|
|
685
685
|
{ http: this.http, toolMap: this.toolMap, operatorToken: this.config.connectionToken }, mode, acknowledged);
|
|
686
686
|
}
|
|
687
|
-
async setExchangeCredentials(
|
|
688
|
-
return executeSetExchangeCredentials({ http: this.http, toolMap: this.toolMap, operatorToken: this.config.connectionToken },
|
|
687
|
+
async setExchangeCredentials(req) {
|
|
688
|
+
return executeSetExchangeCredentials({ http: this.http, toolMap: this.toolMap, operatorToken: this.config.connectionToken }, req);
|
|
689
689
|
}
|
|
690
|
-
async testExchangeCredentials(
|
|
690
|
+
async testExchangeCredentials(req) {
|
|
691
691
|
return executeTestExchangeCredentials(
|
|
692
692
|
// operatorToken required since the SkillSpector hardening: the plugin
|
|
693
693
|
// refuses the credential-validation call without dashboard provenance.
|
|
694
|
-
{ http: this.http, toolMap: this.toolMap, operatorToken: this.config.connectionToken },
|
|
694
|
+
{ http: this.http, toolMap: this.toolMap, operatorToken: this.config.connectionToken }, req);
|
|
695
695
|
}
|
|
696
696
|
async clearExchangeCredentials() {
|
|
697
697
|
return executeClearExchangeCredentials({
|
|
@@ -700,6 +700,19 @@ export class GatewayProvider {
|
|
|
700
700
|
operatorToken: this.config.connectionToken,
|
|
701
701
|
});
|
|
702
702
|
}
|
|
703
|
+
/** Operator-only. Mint an HL agent wallet on the box; returns the public
|
|
704
|
+
* address only (guided onboarding). */
|
|
705
|
+
async provisionHlAgentWallet(args) {
|
|
706
|
+
return executeProvisionHlAgentWallet({ http: this.http, toolMap: this.toolMap, operatorToken: this.config.connectionToken }, args);
|
|
707
|
+
}
|
|
708
|
+
/** Operator-only. Approval/balance status of the provisioned HL wallet. */
|
|
709
|
+
async getHlAgentWalletStatus() {
|
|
710
|
+
return executeHlAgentWalletStatus({
|
|
711
|
+
http: this.http,
|
|
712
|
+
toolMap: this.toolMap,
|
|
713
|
+
operatorToken: this.config.connectionToken,
|
|
714
|
+
});
|
|
715
|
+
}
|
|
703
716
|
/** Operator-only. Read the current bracket-orders config from the plugin. */
|
|
704
717
|
async getBracketConfig() {
|
|
705
718
|
return executeGetBracketConfig({ http: this.http, toolMap: this.toolMap });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GatewayHttpClient } from '../gateway/gateway-http-client.js';
|
|
2
2
|
import type { ToolMap } from '../gateway/tool-discovery.js';
|
|
3
|
+
import type { ExchangeCredentialsRequest, HlProvisionOutcome, HlAgentWalletStatusOutcome } from '../provider.js';
|
|
3
4
|
import type { TradingMode } from '@reefclaw/shared';
|
|
4
5
|
export interface SetTradingModeOutcome {
|
|
5
6
|
ok: boolean;
|
|
@@ -16,6 +17,11 @@ export interface SetExchangeCredentialsOutcome {
|
|
|
16
17
|
reconnected: boolean;
|
|
17
18
|
mode: TradingMode;
|
|
18
19
|
readiness: string;
|
|
20
|
+
/** Venue the credentials were stored for (plugin ≥ HL product surface). */
|
|
21
|
+
venue?: string;
|
|
22
|
+
/** True when the stored venue differs from the booted venue — the operator
|
|
23
|
+
* must restart the agent before the change takes effect. */
|
|
24
|
+
restartRequired?: boolean;
|
|
19
25
|
}
|
|
20
26
|
export interface TestExchangeCredentialsOutcome {
|
|
21
27
|
ok: boolean;
|
|
@@ -23,9 +29,18 @@ export interface TestExchangeCredentialsOutcome {
|
|
|
23
29
|
fingerprint: string;
|
|
24
30
|
canReadBalance: boolean;
|
|
25
31
|
canReadPositions: boolean;
|
|
32
|
+
/** Quote-currency balance (USDT on Binance, USDC on HL); name is historical. */
|
|
26
33
|
balanceUSDT: number | null;
|
|
27
34
|
testnet: boolean;
|
|
28
35
|
errors: string[];
|
|
36
|
+
venue?: string;
|
|
37
|
+
/** HL only: address the tested agent key controls (public). */
|
|
38
|
+
agentAddress?: string;
|
|
39
|
+
/** HL only: definitive approval verdict, or null when unverifiable. */
|
|
40
|
+
agentApproved?: boolean | null;
|
|
41
|
+
/** HL only: approval expiry (epoch ms) when the exchange reports one. */
|
|
42
|
+
agentValidUntil?: number | null;
|
|
43
|
+
warnings?: string[];
|
|
29
44
|
}
|
|
30
45
|
export interface ClearExchangeCredentialsOutcome {
|
|
31
46
|
ok: boolean;
|
|
@@ -71,10 +86,10 @@ export interface SetBracketRequirementOutcome {
|
|
|
71
86
|
/** Forward a set_trading_mode invocation to the plugin via HTTP. */
|
|
72
87
|
export declare function executeSetTradingMode(ctx: OnboardingContext, mode: TradingMode, acknowledged: boolean | undefined): Promise<SetTradingModeOutcome>;
|
|
73
88
|
/** Forward a test_exchange_credentials invocation to the plugin. The plugin
|
|
74
|
-
* does
|
|
75
|
-
*
|
|
76
|
-
* (same approach as the set path). */
|
|
77
|
-
export declare function executeTestExchangeCredentials(ctx: OnboardingContext,
|
|
89
|
+
* does throwaway read-only calls to verify the credentials without
|
|
90
|
+
* persisting them. Error messages are scrubbed of the raw secret / agent key
|
|
91
|
+
* before logging (same approach as the set path). */
|
|
92
|
+
export declare function executeTestExchangeCredentials(ctx: OnboardingContext, req: ExchangeCredentialsRequest): Promise<TestExchangeCredentialsOutcome>;
|
|
78
93
|
/** Forward a clear_exchange_credentials invocation to the plugin. Sends
|
|
79
94
|
* `confirm: true` unconditionally — the skill RPC only accepts the call
|
|
80
95
|
* at all when the bridge has decided it's legitimate, so the plugin-side
|
|
@@ -87,8 +102,19 @@ export declare function executeGetBracketConfig(ctx: OnboardingContext): Promise
|
|
|
87
102
|
/** Forward a set_bracket_requirement invocation to the plugin. The plugin
|
|
88
103
|
* side enforces flag + boolean validation; the skill layer just forwards. */
|
|
89
104
|
export declare function executeSetBracketRequirement(ctx: OnboardingContext, flag: BracketRequirementFlag, value: boolean): Promise<SetBracketRequirementOutcome>;
|
|
105
|
+
/** Forward an hl_provision_agent_wallet invocation to the plugin. No secrets
|
|
106
|
+
* transit this path in EITHER direction — the request carries a public
|
|
107
|
+
* master address; the response carries a public agent address (the private
|
|
108
|
+
* key is minted and stays on the box). */
|
|
109
|
+
export declare function executeProvisionHlAgentWallet(ctx: OnboardingContext, args: {
|
|
110
|
+
walletAddress: string;
|
|
111
|
+
testnet?: boolean;
|
|
112
|
+
regenerate?: boolean;
|
|
113
|
+
}): Promise<HlProvisionOutcome>;
|
|
114
|
+
/** Forward an hl_agent_wallet_status invocation to the plugin. Read-only. */
|
|
115
|
+
export declare function executeHlAgentWalletStatus(ctx: OnboardingContext): Promise<HlAgentWalletStatusOutcome>;
|
|
90
116
|
/** Forward a set_exchange_credentials invocation to the plugin via HTTP.
|
|
91
|
-
* The raw secret is sent once over TLS and never retained here —
|
|
92
|
-
* caching, no log lines with the raw value. Errors are scrubbed of the
|
|
117
|
+
* The raw secret / agent key is sent once over TLS and never retained here —
|
|
118
|
+
* no caching, no log lines with the raw value. Errors are scrubbed of the
|
|
93
119
|
* secret before logging in case it ever appears in an error chain. */
|
|
94
|
-
export declare function executeSetExchangeCredentials(ctx: OnboardingContext,
|
|
120
|
+
export declare function executeSetExchangeCredentials(ctx: OnboardingContext, req: ExchangeCredentialsRequest): Promise<SetExchangeCredentialsOutcome>;
|