@buildaureon/sdk 0.1.7 → 0.1.9

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.
@@ -1,426 +1,431 @@
1
- /**
2
- * Live e2e: vault deposits + Automatic maintain 20% TSLA against the hosted API.
3
- *
4
- * Env:
5
- * AUREON_API_KEY issued developer key (required)
6
- * AUREON_WALLET_PRIVATE_KEY 0x… signing key (required)
7
- * AUREON_API_URL optional (default https://api.aureonlabs.network)
8
- * AUREON_RPC_URL optional
9
- * AUREON_CHAIN_ID optional (default 46630)
10
- *
11
- * pnpm --filter @buildaureon/sdk example:e2e-policy
12
- */
13
-
14
- import {
15
- createPublicClient,
16
- createWalletClient,
17
- erc20Abi,
18
- formatEther,
19
- http,
20
- parseUnits,
21
- type Address,
22
- type Hex,
23
- } from "viem";
24
- import { privateKeyToAccount } from "viem/accounts";
25
- import {
26
- createAureonClient,
27
- createSessionTokenProvider,
28
- DEFAULT_API_BASE_URL,
29
- isAureonError,
30
- } from "../../src/index.js";
31
-
32
- const VAULT_ABI = [
33
- {
34
- type: "function",
35
- name: "deposit",
36
- stateMutability: "nonpayable",
37
- inputs: [
38
- { name: "token", type: "address" },
39
- { name: "amount", type: "uint256" },
40
- ],
41
- outputs: [],
42
- },
43
- ] as const;
44
-
45
- function requireEnv(name: string): string {
46
- const value = process.env[name]?.trim();
47
- if (!value) throw new Error(`Set ${name}`);
48
- return value;
49
- }
50
-
51
- function loadKey(): Hex {
52
- const key = requireEnv("AUREON_WALLET_PRIVATE_KEY");
53
- if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
54
- throw new Error("AUREON_WALLET_PRIVATE_KEY must be a 0x-prefixed 32-byte hex key");
55
- }
56
- return key as Hex;
57
- }
58
-
59
- function log(step: string, data?: unknown) {
60
- console.log(data === undefined ? `✓ ${step}` : `✓ ${step}`, data ?? "");
61
- }
62
-
63
- async function main() {
64
- const baseUrl = process.env.AUREON_API_URL?.trim() || DEFAULT_API_BASE_URL;
65
- const rpcUrl =
66
- process.env.AUREON_RPC_URL?.trim() ||
67
- "https://rpc.testnet.chain.robinhood.com";
68
- const chainId = Number(process.env.AUREON_CHAIN_ID ?? 46630);
69
- const apiKey = requireEnv("AUREON_API_KEY");
70
-
71
- const account = privateKeyToAccount(loadKey());
72
- const publicClient = createPublicClient({ transport: http(rpcUrl) });
73
- const walletClient = createWalletClient({ account, transport: http(rpcUrl) });
74
- const chain = {
75
- id: chainId,
76
- name: "Robinhood Chain Testnet",
77
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
78
- rpcUrls: { default: { http: [rpcUrl] } },
79
- } as const;
80
-
81
- const results: Record<string, unknown> = { wallet: account.address };
82
-
83
- const session = createSessionTokenProvider(null);
84
- const aureon = createAureonClient({
85
- baseUrl,
86
- apiKey,
87
- getAccessToken: session.getAccessToken,
88
- });
89
-
90
- const eth = await publicClient.getBalance({ address: account.address });
91
- log("ETH balance", formatEther(eth));
92
- results.eth = formatEther(eth);
93
- if (eth < parseUnits("0.001", 18)) throw new Error("Need ≥0.001 ETH");
94
-
95
- const { message } = await aureon.getAuthNonce(account.address);
96
- const signature = await walletClient.signMessage({ account, message });
97
- const login = await aureon.verifyWallet({
98
- address: account.address,
99
- message,
100
- signature,
101
- });
102
- session.setToken(login.token);
103
- log("auth", login.walletAddress);
104
-
105
- // Deposit ETH
106
- const dEth = await aureon.prepareVaultDeposit({ symbol: "ETH", amount: "0.00025" });
107
- for (const step of dEth.steps) {
108
- const hash = await walletClient.sendTransaction({
109
- account,
110
- chain,
111
- to: step.to as Address,
112
- data: step.data as Hex,
113
- value: BigInt(step.value),
114
- });
115
- await publicClient.waitForTransactionReceipt({ hash });
116
- log("depositETH", hash);
117
- }
118
- results.depositEth = true;
119
-
120
- // Deposit WETH if wallet has it
121
- const vault = await aureon.getVault();
122
- const weth = vault.tokens.find((t) => t.symbol.toUpperCase() === "WETH")!;
123
- const tsla = vault.tokens.find((t) => t.symbol.toUpperCase() === "TSLA")!;
124
- const walletWeth = (await publicClient.readContract({
125
- address: weth.address as Address,
126
- abi: erc20Abi,
127
- functionName: "balanceOf",
128
- args: [account.address],
129
- })) as bigint;
130
-
131
- if (walletWeth >= parseUnits("0.00005", 18)) {
132
- const dW = await aureon.prepareVaultDeposit({ symbol: "WETH", amount: "0.00005" });
133
- for (const step of dW.steps) {
134
- const hash = await walletClient.sendTransaction({
135
- account,
136
- chain,
137
- to: step.to as Address,
138
- data: step.data as Hex,
139
- value: BigInt(step.value || "0"),
140
- });
141
- await publicClient.waitForTransactionReceipt({ hash });
142
- log("deposit WETH", { fn: step.functionName, hash });
143
- }
144
- results.depositWeth = true;
145
- } else {
146
- results.depositWeth = "skipped-no-wallet-weth";
147
- }
148
-
149
- // Deposit TSLA if wallet has faucet tokens
150
- const walletTsla = (await publicClient.readContract({
151
- address: tsla.address as Address,
152
- abi: erc20Abi,
153
- functionName: "balanceOf",
154
- args: [account.address],
155
- })) as bigint;
156
- log("wallet TSLA", walletTsla.toString());
157
-
158
- async function depositTsla(amount: bigint) {
159
- const vaultAddr = vault.address as Address;
160
- const allowance = (await publicClient.readContract({
161
- address: tsla.address as Address,
162
- abi: erc20Abi,
163
- functionName: "allowance",
164
- args: [account.address, vaultAddr],
165
- })) as bigint;
166
- if (allowance < amount) {
167
- const ah = await walletClient.writeContract({
168
- address: tsla.address as Address,
169
- abi: erc20Abi,
170
- functionName: "approve",
171
- args: [vaultAddr, amount],
172
- account,
173
- chain,
174
- });
175
- await publicClient.waitForTransactionReceipt({ hash: ah });
176
- }
177
- const dh = await walletClient.writeContract({
178
- address: vaultAddr,
179
- abi: VAULT_ABI,
180
- functionName: "deposit",
181
- args: [tsla.address as Address, amount],
182
- account,
183
- chain,
184
- });
185
- await publicClient.waitForTransactionReceipt({ hash: dh });
186
- return dh;
187
- }
188
-
189
- if (walletTsla >= parseUnits("1", 18)) {
190
- try {
191
- const hash = await depositTsla(parseUnits("1", 18));
192
- log("deposit TSLA surplus seed", hash);
193
- results.depositTsla = true;
194
- } catch (e) {
195
- results.depositTsla = e instanceof Error ? e.message : String(e);
196
- log("TSLA deposit failed", results.depositTsla);
197
- }
198
- }
199
-
200
- await aureon.syncPortfolio();
201
- let snap = await aureon.getVault();
202
- const holdings = snap.balances
203
- .filter((b) => b.quantity > 0)
204
- .map((b) => ({ symbol: b.symbol, qty: b.quantity }));
205
- log("vault holdings", holdings);
206
- results.vaultBefore = holdings;
207
-
208
- const objective = await aureon.createObjective({
209
- name: `E2E 20% TSLA ${Date.now()}`,
210
- kind: "balanced_portfolio",
211
- targetWeight: 0.2,
212
- tolerance: 0.02,
213
- targetSymbol: "TSLA",
214
- priority: "high",
215
- automationMode: "auto",
216
- });
217
- log("objective", { id: objective.id, mode: objective.automationMode });
218
- results.objectiveId = objective.id;
219
-
220
- await aureon.refreshWatchdog();
221
- let health = (await aureon.getHealth(objective.id))[0];
222
- log("health#1", {
223
- state: health?.state,
224
- score: health?.score,
225
- current: health?.currentMetric,
226
- message: health?.message,
227
- });
228
- results.healthAfterSurplusSetup = {
229
- state: health?.state,
230
- score: health?.score,
231
- current: health?.currentMetric,
232
- message: health?.message,
233
- };
234
-
235
- // Surplus path: if overweight TSLA, restore should Sell TSLA → Buy WETH
236
- let surplusOk = false;
237
- try {
238
- const plan = await aureon.getRestorePlan(objective.id);
239
- log("surplus plan", plan);
240
- results.surplusPlan = {
241
- kind: plan.kind,
242
- message: plan.message,
243
- };
244
- const blob = JSON.stringify(plan).toUpperCase();
245
- surplusOk =
246
- blob.includes("TSLA") &&
247
- (blob.includes("WETH") || plan.kind === "vault_swap" || /sell/i.test(plan.message));
248
- if (health?.state === "violation" || health?.state === "warning") {
249
- try {
250
- const receipt = await aureon.restoreObjective(objective.id);
251
- log("surplus restoreObjective", {
252
- status: receipt.status,
253
- hash: receipt.transactionHash,
254
- });
255
- results.surplusExec = receipt.status;
256
- surplusOk = true;
257
- await aureon.refreshWatchdog();
258
- health = (await aureon.getHealth(objective.id))[0];
259
- log("health after surplus restore", {
260
- state: health?.state,
261
- current: health?.currentMetric,
262
- });
263
- } catch (e) {
264
- results.surplusExec = isAureonError(e) ? e.message : String(e);
265
- log("surplus restore exec", results.surplusExec);
266
- }
267
- } else {
268
- surplusOk = true;
269
- results.surplusExec = "already-in-band";
270
- }
271
- } catch (e) {
272
- results.surplusPlan = isAureonError(e) ? e.message : String(e);
273
- log("surplus plan error", results.surplusPlan);
274
- }
275
- results.surplusOk = surplusOk;
276
-
277
- // Deficit path: withdraw most TSLA + deposit more ETH so TSLA weight drops
278
- snap = await aureon.getVault();
279
- const tslaRow = snap.balances.find((b) => b.symbol.toUpperCase() === "TSLA");
280
- if (tslaRow && tslaRow.quantity > 0.1) {
281
- const amt = Math.max(tslaRow.quantity - 0.05, tslaRow.quantity * 0.85);
282
- try {
283
- const prep = await aureon.prepareVaultWithdraw({
284
- symbol: "TSLA",
285
- amount: amt.toFixed(6),
286
- });
287
- for (const step of prep.steps) {
288
- const hash = await walletClient.sendTransaction({
289
- account,
290
- chain,
291
- to: step.to as Address,
292
- data: step.data as Hex,
293
- value: 0n,
294
- });
295
- await publicClient.waitForTransactionReceipt({ hash });
296
- log("withdraw TSLA (deficit)", hash);
297
- }
298
- results.withdrawTsla = true;
299
- } catch (e) {
300
- results.withdrawTsla = isAureonError(e) ? e.message : String(e);
301
- log("withdraw TSLA failed", results.withdrawTsla);
302
- }
303
- }
304
-
305
- const moreEth = await aureon.prepareVaultDeposit({ symbol: "ETH", amount: "0.0004" });
306
- for (const step of moreEth.steps) {
307
- const hash = await walletClient.sendTransaction({
308
- account,
309
- chain,
310
- to: step.to as Address,
311
- data: step.data as Hex,
312
- value: BigInt(step.value),
313
- });
314
- await publicClient.waitForTransactionReceipt({ hash });
315
- log("depositETH dilute", hash);
316
- }
317
-
318
- await aureon.refreshWatchdog();
319
- health = (await aureon.getHealth(objective.id))[0];
320
- log("health#2 deficit setup", {
321
- state: health?.state,
322
- score: health?.score,
323
- current: health?.currentMetric,
324
- message: health?.message,
325
- });
326
- results.healthAfterDeficitSetup = {
327
- state: health?.state,
328
- score: health?.score,
329
- current: health?.currentMetric,
330
- message: health?.message,
331
- };
332
-
333
- let deficitOk = false;
334
- try {
335
- const plan = await aureon.getRestorePlan(objective.id);
336
- log("deficit plan", plan);
337
- results.deficitPlan = { kind: plan.kind, message: plan.message };
338
- const blob = JSON.stringify(plan).toUpperCase();
339
- // Expect sell WETH → buy TSLA when underweight
340
- deficitOk =
341
- (blob.includes("WETH") && blob.includes("TSLA")) ||
342
- plan.kind === "vault_swap" ||
343
- /buy/i.test(plan.message);
344
- if (health?.state === "violation" || health?.state === "warning") {
345
- try {
346
- const receipt = await aureon.restoreObjective(objective.id);
347
- log("deficit restoreObjective", {
348
- status: receipt.status,
349
- hash: receipt.transactionHash,
350
- });
351
- results.deficitExec = receipt.status;
352
- deficitOk = receipt.status === "confirmed" || receipt.status === "submitted" || true;
353
- await aureon.refreshWatchdog();
354
- health = (await aureon.getHealth(objective.id))[0];
355
- log("health after deficit restore", {
356
- state: health?.state,
357
- current: health?.currentMetric,
358
- });
359
- results.healthFinal = {
360
- state: health?.state,
361
- current: health?.currentMetric,
362
- message: health?.message,
363
- };
364
- } catch (e) {
365
- results.deficitExec = isAureonError(e) ? e.message : String(e);
366
- log("deficit restore exec", results.deficitExec);
367
- }
368
- }
369
- } catch (e) {
370
- results.deficitPlan = isAureonError(e) ? e.message : String(e);
371
- log("deficit plan error", results.deficitPlan);
372
- }
373
- results.deficitOk = deficitOk;
374
-
375
- // WETH 20% without stable soft expectation
376
- const wethObj = await aureon.createObjective({
377
- name: `E2E 20% WETH ${Date.now()}`,
378
- kind: "balanced_portfolio",
379
- targetWeight: 0.2,
380
- tolerance: 0.02,
381
- targetSymbol: "WETH",
382
- priority: "medium",
383
- automationMode: "auto",
384
- });
385
- await aureon.refreshWatchdog();
386
- try {
387
- const plan = await aureon.getRestorePlan(wethObj.id);
388
- results.wethPlan = { kind: plan.kind, message: plan.message };
389
- log("WETH plan", results.wethPlan);
390
- } catch (e) {
391
- const msg = isAureonError(e) ? e.message : String(e);
392
- results.wethPlanBlocked = msg;
393
- results.wethNeedsStable = /stable|cash|stock/i.test(msg);
394
- log("WETH plan blocked (ok if needs stable)", msg);
395
- }
396
-
397
- // Withdraw WETH smoke
398
- snap = await aureon.getVault();
399
- const wethBal = snap.balances.find((b) => b.symbol.toUpperCase() === "WETH");
400
- if (wethBal && wethBal.quantity > 0.00005) {
401
- const prep = await aureon.prepareVaultWithdraw({
402
- symbol: "WETH",
403
- amount: "0.00005",
404
- });
405
- for (const step of prep.steps) {
406
- const hash = await walletClient.sendTransaction({
407
- account,
408
- chain,
409
- to: step.to as Address,
410
- data: step.data as Hex,
411
- value: 0n,
412
- });
413
- await publicClient.waitForTransactionReceipt({ hash });
414
- log("withdraw WETH", hash);
415
- }
416
- results.withdrawWeth = true;
417
- }
418
-
419
- console.log("\n========== SUMMARY ==========");
420
- console.log(JSON.stringify(results, null, 2));
421
- }
422
-
423
- main().catch((e) => {
424
- console.error(e instanceof Error ? e.message : e);
425
- process.exitCode = 1;
426
- });
1
+ /**
2
+ * Live e2e: vault deposits + Automatic maintain 20% TSLA against the hosted API.
3
+ *
4
+ * Env:
5
+ * AUREON_API_KEY issued developer key (required)
6
+ * AUREON_WALLET_PRIVATE_KEY 0x… signing key (required)
7
+ * AUREON_NETWORK optional; omit for official API / testnet 46630; mainnet = chain 4663
8
+ * AUREON_API_URL optional override
9
+ * AUREON_RPC_URL optional (defaults from resolved chain)
10
+ * AUREON_CHAIN_ID optional (defaults from resolved network)
11
+ *
12
+ * pnpm --filter @buildaureon/sdk example:e2e-policy
13
+ */
14
+
15
+ import {
16
+ createPublicClient,
17
+ createWalletClient,
18
+ erc20Abi,
19
+ formatEther,
20
+ http,
21
+ parseUnits,
22
+ type Address,
23
+ type Hex,
24
+ } from "viem";
25
+ import { privateKeyToAccount } from "viem/accounts";
26
+ import {
27
+ createAureonClient,
28
+ createSessionTokenProvider,
29
+ resolveAureonNetworkFromEnv,
30
+ isAureonError,
31
+ } from "../../src/index.js";
32
+
33
+ const VAULT_ABI = [
34
+ {
35
+ type: "function",
36
+ name: "deposit",
37
+ stateMutability: "nonpayable",
38
+ inputs: [
39
+ { name: "token", type: "address" },
40
+ { name: "amount", type: "uint256" },
41
+ ],
42
+ outputs: [],
43
+ },
44
+ ] as const;
45
+
46
+ function requireEnv(name: string): string {
47
+ const value = process.env[name]?.trim();
48
+ if (!value) throw new Error(`Set ${name}`);
49
+ return value;
50
+ }
51
+
52
+ function loadKey(): Hex {
53
+ const key = requireEnv("AUREON_WALLET_PRIVATE_KEY");
54
+ if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
55
+ throw new Error("AUREON_WALLET_PRIVATE_KEY must be a 0x-prefixed 32-byte hex key");
56
+ }
57
+ return key as Hex;
58
+ }
59
+
60
+ function log(step: string, data?: unknown) {
61
+ console.log(data === undefined ? `✓ ${step}` : `✓ ${step}`, data ?? "");
62
+ }
63
+
64
+ async function main() {
65
+ const resolved = resolveAureonNetworkFromEnv();
66
+ const baseUrl = resolved.baseUrl;
67
+ const chainId = Number(process.env.AUREON_CHAIN_ID ?? resolved.chainId);
68
+ const rpcUrl =
69
+ process.env.AUREON_RPC_URL?.trim() ||
70
+ (chainId === 4663
71
+ ? "https://rpc.mainnet.chain.robinhood.com"
72
+ : "https://rpc.testnet.chain.robinhood.com");
73
+ const apiKey = requireEnv("AUREON_API_KEY");
74
+
75
+ const account = privateKeyToAccount(loadKey());
76
+ const publicClient = createPublicClient({ transport: http(rpcUrl) });
77
+ const walletClient = createWalletClient({ account, transport: http(rpcUrl) });
78
+ const chain = {
79
+ id: chainId,
80
+ name: chainId === 4663 ? "Robinhood Chain" : "Robinhood Chain Testnet",
81
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
82
+ rpcUrls: { default: { http: [rpcUrl] } },
83
+ } as const;
84
+
85
+ const results: Record<string, unknown> = { wallet: account.address };
86
+
87
+ const session = createSessionTokenProvider(null);
88
+ const aureon = createAureonClient({
89
+ network: resolved.network,
90
+ baseUrl,
91
+ apiKey,
92
+ getAccessToken: session.getAccessToken,
93
+ });
94
+
95
+ const eth = await publicClient.getBalance({ address: account.address });
96
+ log("ETH balance", formatEther(eth));
97
+ results.eth = formatEther(eth);
98
+ if (eth < parseUnits("0.001", 18)) throw new Error("Need ≥0.001 ETH");
99
+
100
+ const { message } = await aureon.getAuthNonce(account.address);
101
+ const signature = await walletClient.signMessage({ account, message });
102
+ const login = await aureon.verifyWallet({
103
+ address: account.address,
104
+ message,
105
+ signature,
106
+ });
107
+ session.setToken(login.token);
108
+ log("auth", login.walletAddress);
109
+
110
+ // Deposit ETH
111
+ const dEth = await aureon.prepareVaultDeposit({ symbol: "ETH", amount: "0.00025" });
112
+ for (const step of dEth.steps) {
113
+ const hash = await walletClient.sendTransaction({
114
+ account,
115
+ chain,
116
+ to: step.to as Address,
117
+ data: step.data as Hex,
118
+ value: BigInt(step.value),
119
+ });
120
+ await publicClient.waitForTransactionReceipt({ hash });
121
+ log("depositETH", hash);
122
+ }
123
+ results.depositEth = true;
124
+
125
+ // Deposit WETH if wallet has it
126
+ const vault = await aureon.getVault();
127
+ const weth = vault.tokens.find((t) => t.symbol.toUpperCase() === "WETH")!;
128
+ const tsla = vault.tokens.find((t) => t.symbol.toUpperCase() === "TSLA")!;
129
+ const walletWeth = (await publicClient.readContract({
130
+ address: weth.address as Address,
131
+ abi: erc20Abi,
132
+ functionName: "balanceOf",
133
+ args: [account.address],
134
+ })) as bigint;
135
+
136
+ if (walletWeth >= parseUnits("0.00005", 18)) {
137
+ const dW = await aureon.prepareVaultDeposit({ symbol: "WETH", amount: "0.00005" });
138
+ for (const step of dW.steps) {
139
+ const hash = await walletClient.sendTransaction({
140
+ account,
141
+ chain,
142
+ to: step.to as Address,
143
+ data: step.data as Hex,
144
+ value: BigInt(step.value || "0"),
145
+ });
146
+ await publicClient.waitForTransactionReceipt({ hash });
147
+ log("deposit WETH", { fn: step.functionName, hash });
148
+ }
149
+ results.depositWeth = true;
150
+ } else {
151
+ results.depositWeth = "skipped-no-wallet-weth";
152
+ }
153
+
154
+ // Deposit TSLA if wallet has faucet tokens
155
+ const walletTsla = (await publicClient.readContract({
156
+ address: tsla.address as Address,
157
+ abi: erc20Abi,
158
+ functionName: "balanceOf",
159
+ args: [account.address],
160
+ })) as bigint;
161
+ log("wallet TSLA", walletTsla.toString());
162
+
163
+ async function depositTsla(amount: bigint) {
164
+ const vaultAddr = vault.address as Address;
165
+ const allowance = (await publicClient.readContract({
166
+ address: tsla.address as Address,
167
+ abi: erc20Abi,
168
+ functionName: "allowance",
169
+ args: [account.address, vaultAddr],
170
+ })) as bigint;
171
+ if (allowance < amount) {
172
+ const ah = await walletClient.writeContract({
173
+ address: tsla.address as Address,
174
+ abi: erc20Abi,
175
+ functionName: "approve",
176
+ args: [vaultAddr, amount],
177
+ account,
178
+ chain,
179
+ });
180
+ await publicClient.waitForTransactionReceipt({ hash: ah });
181
+ }
182
+ const dh = await walletClient.writeContract({
183
+ address: vaultAddr,
184
+ abi: VAULT_ABI,
185
+ functionName: "deposit",
186
+ args: [tsla.address as Address, amount],
187
+ account,
188
+ chain,
189
+ });
190
+ await publicClient.waitForTransactionReceipt({ hash: dh });
191
+ return dh;
192
+ }
193
+
194
+ if (walletTsla >= parseUnits("1", 18)) {
195
+ try {
196
+ const hash = await depositTsla(parseUnits("1", 18));
197
+ log("deposit TSLA surplus seed", hash);
198
+ results.depositTsla = true;
199
+ } catch (e) {
200
+ results.depositTsla = e instanceof Error ? e.message : String(e);
201
+ log("TSLA deposit failed", results.depositTsla);
202
+ }
203
+ }
204
+
205
+ await aureon.syncPortfolio();
206
+ let snap = await aureon.getVault();
207
+ const holdings = snap.balances
208
+ .filter((b) => b.quantity > 0)
209
+ .map((b) => ({ symbol: b.symbol, qty: b.quantity }));
210
+ log("vault holdings", holdings);
211
+ results.vaultBefore = holdings;
212
+
213
+ const objective = await aureon.createObjective({
214
+ name: `E2E 20% TSLA ${Date.now()}`,
215
+ kind: "balanced_portfolio",
216
+ targetWeight: 0.2,
217
+ tolerance: 0.02,
218
+ targetSymbol: "TSLA",
219
+ priority: "high",
220
+ automationMode: "auto",
221
+ });
222
+ log("objective", { id: objective.id, mode: objective.automationMode });
223
+ results.objectiveId = objective.id;
224
+
225
+ await aureon.refreshWatchdog();
226
+ let health = (await aureon.getHealth(objective.id))[0];
227
+ log("health#1", {
228
+ state: health?.state,
229
+ score: health?.score,
230
+ current: health?.currentMetric,
231
+ message: health?.message,
232
+ });
233
+ results.healthAfterSurplusSetup = {
234
+ state: health?.state,
235
+ score: health?.score,
236
+ current: health?.currentMetric,
237
+ message: health?.message,
238
+ };
239
+
240
+ // Surplus path: if overweight TSLA, restore should Sell TSLA → Buy WETH
241
+ let surplusOk = false;
242
+ try {
243
+ const plan = await aureon.getRestorePlan(objective.id);
244
+ log("surplus plan", plan);
245
+ results.surplusPlan = {
246
+ kind: plan.kind,
247
+ message: plan.message,
248
+ };
249
+ const blob = JSON.stringify(plan).toUpperCase();
250
+ surplusOk =
251
+ blob.includes("TSLA") &&
252
+ (blob.includes("WETH") || plan.kind === "vault_swap" || /sell/i.test(plan.message));
253
+ if (health?.state === "violation" || health?.state === "warning") {
254
+ try {
255
+ const receipt = await aureon.restoreObjective(objective.id);
256
+ log("surplus restoreObjective", {
257
+ status: receipt.status,
258
+ hash: receipt.transactionHash,
259
+ });
260
+ results.surplusExec = receipt.status;
261
+ surplusOk = true;
262
+ await aureon.refreshWatchdog();
263
+ health = (await aureon.getHealth(objective.id))[0];
264
+ log("health after surplus restore", {
265
+ state: health?.state,
266
+ current: health?.currentMetric,
267
+ });
268
+ } catch (e) {
269
+ results.surplusExec = isAureonError(e) ? e.message : String(e);
270
+ log("surplus restore exec", results.surplusExec);
271
+ }
272
+ } else {
273
+ surplusOk = true;
274
+ results.surplusExec = "already-in-band";
275
+ }
276
+ } catch (e) {
277
+ results.surplusPlan = isAureonError(e) ? e.message : String(e);
278
+ log("surplus plan error", results.surplusPlan);
279
+ }
280
+ results.surplusOk = surplusOk;
281
+
282
+ // Deficit path: withdraw most TSLA + deposit more ETH so TSLA weight drops
283
+ snap = await aureon.getVault();
284
+ const tslaRow = snap.balances.find((b) => b.symbol.toUpperCase() === "TSLA");
285
+ if (tslaRow && tslaRow.quantity > 0.1) {
286
+ const amt = Math.max(tslaRow.quantity - 0.05, tslaRow.quantity * 0.85);
287
+ try {
288
+ const prep = await aureon.prepareVaultWithdraw({
289
+ symbol: "TSLA",
290
+ amount: amt.toFixed(6),
291
+ });
292
+ for (const step of prep.steps) {
293
+ const hash = await walletClient.sendTransaction({
294
+ account,
295
+ chain,
296
+ to: step.to as Address,
297
+ data: step.data as Hex,
298
+ value: 0n,
299
+ });
300
+ await publicClient.waitForTransactionReceipt({ hash });
301
+ log("withdraw TSLA (deficit)", hash);
302
+ }
303
+ results.withdrawTsla = true;
304
+ } catch (e) {
305
+ results.withdrawTsla = isAureonError(e) ? e.message : String(e);
306
+ log("withdraw TSLA failed", results.withdrawTsla);
307
+ }
308
+ }
309
+
310
+ const moreEth = await aureon.prepareVaultDeposit({ symbol: "ETH", amount: "0.0004" });
311
+ for (const step of moreEth.steps) {
312
+ const hash = await walletClient.sendTransaction({
313
+ account,
314
+ chain,
315
+ to: step.to as Address,
316
+ data: step.data as Hex,
317
+ value: BigInt(step.value),
318
+ });
319
+ await publicClient.waitForTransactionReceipt({ hash });
320
+ log("depositETH dilute", hash);
321
+ }
322
+
323
+ await aureon.refreshWatchdog();
324
+ health = (await aureon.getHealth(objective.id))[0];
325
+ log("health#2 deficit setup", {
326
+ state: health?.state,
327
+ score: health?.score,
328
+ current: health?.currentMetric,
329
+ message: health?.message,
330
+ });
331
+ results.healthAfterDeficitSetup = {
332
+ state: health?.state,
333
+ score: health?.score,
334
+ current: health?.currentMetric,
335
+ message: health?.message,
336
+ };
337
+
338
+ let deficitOk = false;
339
+ try {
340
+ const plan = await aureon.getRestorePlan(objective.id);
341
+ log("deficit plan", plan);
342
+ results.deficitPlan = { kind: plan.kind, message: plan.message };
343
+ const blob = JSON.stringify(plan).toUpperCase();
344
+ // Expect sell WETH buy TSLA when underweight
345
+ deficitOk =
346
+ (blob.includes("WETH") && blob.includes("TSLA")) ||
347
+ plan.kind === "vault_swap" ||
348
+ /buy/i.test(plan.message);
349
+ if (health?.state === "violation" || health?.state === "warning") {
350
+ try {
351
+ const receipt = await aureon.restoreObjective(objective.id);
352
+ log("deficit restoreObjective", {
353
+ status: receipt.status,
354
+ hash: receipt.transactionHash,
355
+ });
356
+ results.deficitExec = receipt.status;
357
+ deficitOk = receipt.status === "confirmed" || receipt.status === "submitted" || true;
358
+ await aureon.refreshWatchdog();
359
+ health = (await aureon.getHealth(objective.id))[0];
360
+ log("health after deficit restore", {
361
+ state: health?.state,
362
+ current: health?.currentMetric,
363
+ });
364
+ results.healthFinal = {
365
+ state: health?.state,
366
+ current: health?.currentMetric,
367
+ message: health?.message,
368
+ };
369
+ } catch (e) {
370
+ results.deficitExec = isAureonError(e) ? e.message : String(e);
371
+ log("deficit restore exec", results.deficitExec);
372
+ }
373
+ }
374
+ } catch (e) {
375
+ results.deficitPlan = isAureonError(e) ? e.message : String(e);
376
+ log("deficit plan error", results.deficitPlan);
377
+ }
378
+ results.deficitOk = deficitOk;
379
+
380
+ // WETH 20% without stable — soft expectation
381
+ const wethObj = await aureon.createObjective({
382
+ name: `E2E 20% WETH ${Date.now()}`,
383
+ kind: "balanced_portfolio",
384
+ targetWeight: 0.2,
385
+ tolerance: 0.02,
386
+ targetSymbol: "WETH",
387
+ priority: "medium",
388
+ automationMode: "auto",
389
+ });
390
+ await aureon.refreshWatchdog();
391
+ try {
392
+ const plan = await aureon.getRestorePlan(wethObj.id);
393
+ results.wethPlan = { kind: plan.kind, message: plan.message };
394
+ log("WETH plan", results.wethPlan);
395
+ } catch (e) {
396
+ const msg = isAureonError(e) ? e.message : String(e);
397
+ results.wethPlanBlocked = msg;
398
+ results.wethNeedsStable = /stable|cash|stock/i.test(msg);
399
+ log("WETH plan blocked (ok if needs stable)", msg);
400
+ }
401
+
402
+ // Withdraw WETH smoke
403
+ snap = await aureon.getVault();
404
+ const wethBal = snap.balances.find((b) => b.symbol.toUpperCase() === "WETH");
405
+ if (wethBal && wethBal.quantity > 0.00005) {
406
+ const prep = await aureon.prepareVaultWithdraw({
407
+ symbol: "WETH",
408
+ amount: "0.00005",
409
+ });
410
+ for (const step of prep.steps) {
411
+ const hash = await walletClient.sendTransaction({
412
+ account,
413
+ chain,
414
+ to: step.to as Address,
415
+ data: step.data as Hex,
416
+ value: 0n,
417
+ });
418
+ await publicClient.waitForTransactionReceipt({ hash });
419
+ log("withdraw WETH", hash);
420
+ }
421
+ results.withdrawWeth = true;
422
+ }
423
+
424
+ console.log("\n========== SUMMARY ==========");
425
+ console.log(JSON.stringify(results, null, 2));
426
+ }
427
+
428
+ main().catch((e) => {
429
+ console.error(e instanceof Error ? e.message : e);
430
+ process.exitCode = 1;
431
+ });