@reefclaw/connect 0.1.34 → 0.1.36
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.
|
@@ -96,22 +96,40 @@ export async function hlProvisionAgentWalletTool(args, deps) {
|
|
|
96
96
|
const derived = await deriveAddressFromPrivateKey(existingKey);
|
|
97
97
|
if (derived.ok) {
|
|
98
98
|
const masterMatches = existingMaster != null && existingMaster.toLowerCase() === walletAddress.toLowerCase();
|
|
99
|
-
// ★
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
|
|
99
|
+
// ★ Re-ACTIVATE the venue on resume (E2E audit 2026-08-11 #6) and honour
|
|
100
|
+
// a CHANGED network in the same write.
|
|
101
|
+
//
|
|
102
|
+
// Venue: the resume path used to write NOTHING unless the network flag
|
|
103
|
+
// moved — so a box whose active venue was still binance (HL provisioned
|
|
104
|
+
// earlier and switched back, or a live-Binance box that just clicked
|
|
105
|
+
// through the confirm-switch dialog above) kept `venue:'binance'` on
|
|
106
|
+
// disk. hl_agent_wallet_status only reports configured when
|
|
107
|
+
// `exchange.venue==='hyperliquid'`, so the guided flow dead-ended
|
|
108
|
+
// polling configured:false forever, and the confirm dialog "switched"
|
|
109
|
+
// nothing. By this point the venue-switch confirm gate has already run,
|
|
110
|
+
// so the activation write is authorized. buildVenueExchangeConfig with
|
|
111
|
+
// empty fields activates the venue while keeping BOTH venues'
|
|
112
|
+
// credentials (the merge contract).
|
|
113
|
+
//
|
|
114
|
+
// Network: the same keypair is valid on both Hyperliquid networks, so
|
|
115
|
+
// mainnet<->testnet must not require regenerating — but the stored flag
|
|
116
|
+
// has to follow, or the box boots against the network the operator did
|
|
117
|
+
// NOT pick (observed live 2026-08-03: approval signed for Testnet while
|
|
118
|
+
// the operator believed mainnet).
|
|
119
|
+
const needsVenueActivation = fromVenue !== 'hyperliquid';
|
|
120
|
+
if (masterMatches && (needsVenueActivation || existingTestnet !== testnet)) {
|
|
108
121
|
try {
|
|
109
122
|
updatePluginConfig({ exchange: buildVenueExchangeConfig(existingExchange, 'hyperliquid', {}, testnet) }, deps.configPath);
|
|
123
|
+
if (needsVenueActivation) {
|
|
124
|
+
logger.info(TAG, 'venue re-activated: hyperliquid (existing agent wallet resumed)');
|
|
125
|
+
}
|
|
126
|
+
if (existingTestnet !== testnet) {
|
|
127
|
+
logger.info(TAG, `network switched to ${testnet ? 'TESTNET' : 'MAINNET'} (same agent wallet)`);
|
|
128
|
+
}
|
|
110
129
|
existingTestnet = testnet;
|
|
111
|
-
logger.info(TAG, `network switched to ${testnet ? 'TESTNET' : 'MAINNET'} (same agent wallet)`);
|
|
112
130
|
}
|
|
113
131
|
catch (err) {
|
|
114
|
-
logger.warn(TAG, `could not persist network change: ${err instanceof Error ? err.message : String(err)}`);
|
|
132
|
+
logger.warn(TAG, `could not persist venue/network change: ${err instanceof Error ? err.message : String(err)}`);
|
|
115
133
|
}
|
|
116
134
|
}
|
|
117
135
|
return {
|
|
@@ -34,12 +34,31 @@ import { parseVenue } from '../venues/registry.js';
|
|
|
34
34
|
import { unsealCredentials, SealedEnvelopeError } from '../security/sealed-credentials.js';
|
|
35
35
|
import { logger } from '../logger.js';
|
|
36
36
|
const TAG = 'set-exchange-credentials';
|
|
37
|
+
/** Non-secret CONTROL flags honored from the PLAINTEXT SIBLINGS of a sealed
|
|
38
|
+
* envelope (E2E audit 2026-08-11 #5). The envelope's anti-smuggle property —
|
|
39
|
+
* "plaintext siblings are ignored" — exists so a mixed payload can't override
|
|
40
|
+
* sealed CREDENTIAL values. But the dashboard sends `confirm_venue_switch`
|
|
41
|
+
* as a sibling NEXT TO `sealed` (it is not a secret and the sealer encrypts
|
|
42
|
+
* only the per-venue credential payload), so dropping every sibling made the
|
|
43
|
+
* confirm retry look unconfirmed forever: any live venue-switcher on a box
|
|
44
|
+
* with a transport key hit an infinite confirm loop. The flags below are
|
|
45
|
+
* safe to honor from plaintext because they cannot change WHAT gets stored
|
|
46
|
+
* (the sealed payload alone decides that) — they only acknowledge a warn
|
|
47
|
+
* step for the request the operator themselves sealed. A value INSIDE the
|
|
48
|
+
* envelope still wins (sealed-beats-plaintext is preserved). */
|
|
49
|
+
const SEALED_SIBLING_CONTROL_FLAGS = ['confirm_venue_switch'];
|
|
37
50
|
/** Open a sealed envelope into plain args, or return a renderable error. */
|
|
38
51
|
export function resolveSealedArgs(args, configDir) {
|
|
39
52
|
if (args?.sealed == null)
|
|
40
53
|
return { args, sealed: false };
|
|
41
54
|
try {
|
|
42
55
|
const plain = unsealCredentials(args.sealed, configDir);
|
|
56
|
+
for (const flag of SEALED_SIBLING_CONTROL_FLAGS) {
|
|
57
|
+
const sibling = args[flag];
|
|
58
|
+
if (plain[flag] === undefined && sibling !== undefined) {
|
|
59
|
+
plain[flag] = sibling;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
43
62
|
return { args: plain, sealed: true };
|
|
44
63
|
}
|
|
45
64
|
catch (err) {
|