@buildaureon/sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +532 -0
- package/config/network.json +10 -0
- package/dist/index.d.ts +792 -0
- package/dist/index.js +1030 -0
- package/dist/index.js.map +1 -0
- package/docs/architecture.md +205 -0
- package/docs/auth.md +215 -0
- package/docs/client-api.md +604 -0
- package/docs/data-contracts.md +632 -0
- package/docs/error-model.md +182 -0
- package/docs/integration-guide.md +196 -0
- package/docs/security.md +74 -0
- package/docs/transport.md +128 -0
- package/examples/e2e-policy-rebalance/main.ts +438 -0
- package/examples/e2e-policy-rebalance/underrun.ts +134 -0
- package/examples/e2e-policy-rebalance/verify-sizing.ts +147 -0
- package/examples/e2e-vault-flow/main.ts +270 -0
- package/examples/market-event/main.ts +65 -0
- package/examples/quickstart/main.ts +71 -0
- package/fixtures/reference-objectives.json +18 -0
- package/fixtures/reference-portfolio.json +10 -0
- package/package.json +64 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Detailed Error Model and Diagnostics
|
|
2
|
+
|
|
3
|
+
This document outlines the error classification system used by `@buildaureon/sdk`. It provides field specifications, JSON payloads returned by the hosted API, and diagnostic patterns for production environments.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Core Exception Classes
|
|
8
|
+
|
|
9
|
+
All custom exceptions thrown by the SDK extend the base class `AureonError`. The classes are organized to allow granular catch blocks based on failure categories.
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
graph TD
|
|
13
|
+
Error[native Error] --> AureonError[AureonError Base]
|
|
14
|
+
AureonError --> AureonValidationError[AureonValidationError HTTP 400]
|
|
15
|
+
AureonError --> AureonNotFoundError[AureonNotFoundError HTTP 404]
|
|
16
|
+
AureonError --> AureonConflictError[AureonConflictError HTTP 409]
|
|
17
|
+
AureonError --> AureonNetworkError[AureonNetworkError DNS / Connect]
|
|
18
|
+
AureonError --> AureonTimeoutError[AureonTimeoutError Abort / Limit]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Property Reference
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
export class AureonError extends Error {
|
|
25
|
+
/** Stable error code string. Use this for programmatic branching. */
|
|
26
|
+
readonly code: AureonErrorCode;
|
|
27
|
+
/** HTTP status code from the server, or null for network failures. */
|
|
28
|
+
readonly status: number | null;
|
|
29
|
+
/** Additional key-value metadata returned by the API (e.g. form fields validation). */
|
|
30
|
+
readonly details: Record<string, unknown> | null;
|
|
31
|
+
/** Indicates whether the request can be retried immediately. */
|
|
32
|
+
readonly retryable: boolean;
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
message: string,
|
|
36
|
+
code: AureonErrorCode,
|
|
37
|
+
status: number | null = null,
|
|
38
|
+
details: Record<string, unknown> | null = null
|
|
39
|
+
) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = this.constructor.name;
|
|
42
|
+
this.code = code;
|
|
43
|
+
this.status = status;
|
|
44
|
+
this.details = details;
|
|
45
|
+
this.retryable = isRetryableCode(code);
|
|
46
|
+
|
|
47
|
+
// Capture stack trace, preserving original V8 exception stack where supported
|
|
48
|
+
if (Error.captureStackTrace) {
|
|
49
|
+
Error.captureStackTrace(this, this.constructor);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. API JSON Error Payload Formats
|
|
58
|
+
|
|
59
|
+
When an API request fails, the gateway returns a structured JSON payload. The SDK's HTTP transport layer automatically parses this payload and maps it to the appropriate error class.
|
|
60
|
+
|
|
61
|
+
### 2.1 Validation Error Payload (HTTP 400)
|
|
62
|
+
Returned when objective creation weights, names, or tolerances violate system rules.
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"code": "VALIDATION_ERROR",
|
|
67
|
+
"message": "Create objective parameters failed validation checks",
|
|
68
|
+
"details": {
|
|
69
|
+
"name": "Objective display name must be at least 3 characters long",
|
|
70
|
+
"targetWeight": "Weight must be a number between 0.0 and 1.0",
|
|
71
|
+
"tolerance": "Tolerance must be a number between 0.0 and 0.5"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2.2 Conflict Error Payload (HTTP 409)
|
|
77
|
+
Returned when modifying a resource that is currently locked or undergoing execution.
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"code": "CONFLICT",
|
|
82
|
+
"message": "Cannot modify objective state while rebalance swap is processing",
|
|
83
|
+
"details": {
|
|
84
|
+
"objectiveId": "obj_01h8v12x8p8p3z2v1q45r3m2e1",
|
|
85
|
+
"executionId": "exec_01h8v5t7p8p3z2v1q45r3m2e99",
|
|
86
|
+
"status": "pending_confirmation"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 2.3 Rate Limit Payload (HTTP 429)
|
|
92
|
+
Returned when requests exceed rate limits.
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"code": "RATE_LIMITED",
|
|
97
|
+
"message": "Too many requests. Please slow down.",
|
|
98
|
+
"details": {
|
|
99
|
+
"retryAfterSeconds": 15,
|
|
100
|
+
"limit": 100,
|
|
101
|
+
"windowMs": 60000
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3. Custom Diagnostics and Logging Hooks
|
|
109
|
+
|
|
110
|
+
Integrators can register a logger interface during client construction to track network requests, retries, and errors in production.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { createAureonClient, AureonLogger } from "@buildaureon/sdk";
|
|
114
|
+
|
|
115
|
+
const productionLogger: AureonLogger = {
|
|
116
|
+
debug(msg, ctx) { console.debug(`[DEBUG] ${msg}`, ctx || ""); },
|
|
117
|
+
info(msg, ctx) { console.info(`[INFO] ${msg}`, ctx || ""); },
|
|
118
|
+
warn(msg, ctx) { console.warn(`[WARN] ${msg}`, ctx || ""); },
|
|
119
|
+
error(msg, ctx) {
|
|
120
|
+
// Send critical anomalies to third-party alert services
|
|
121
|
+
if (ctx?.code === "SERVER_ERROR" || ctx?.code === "CONFLICT") {
|
|
122
|
+
sendToSentry(msg, ctx);
|
|
123
|
+
}
|
|
124
|
+
console.error(`[ERROR] ${msg}`, ctx || "");
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const aureon = createAureonClient({
|
|
129
|
+
apiKey: process.env.AUREON_API_KEY,
|
|
130
|
+
logger: productionLogger
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 4. Operational Recovery Patterns
|
|
137
|
+
|
|
138
|
+
```mermaid
|
|
139
|
+
flowchart TD
|
|
140
|
+
Catch[Catch AureonError] --> CodeBranch{Switch error.code}
|
|
141
|
+
|
|
142
|
+
CodeBranch -->|UNAUTHORIZED| HandleAuth[Clear storage and restart EIP-191 signature challenge]
|
|
143
|
+
CodeBranch -->|VALIDATION_ERROR| HandleValidation[Parse details dictionary and highlight fields in UI]
|
|
144
|
+
CodeBranch -->|NOT_FOUND| HandleNotFound[Redirect to list and show warning toast]
|
|
145
|
+
CodeBranch -->|RATE_LIMITED| HandleRate[Wait retryAfterSeconds or exponential backoff then retry]
|
|
146
|
+
CodeBranch -->|TIMEOUT| HandleTimeout[Increase timeoutMs client configuration and retry]
|
|
147
|
+
CodeBranch -->|SERVER_ERROR| HandleServer[Alert ops team and fallback to staged settlement]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 5. Unit Testing and Mocking Guide
|
|
153
|
+
|
|
154
|
+
When writing tests for your agent rebalancing scripts, you can assert error handling behavior using mock response status codes.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { describe, it } from "node:test";
|
|
158
|
+
import assert from "node:assert";
|
|
159
|
+
import { AureonClient, AureonValidationError, isAureonError } from "@buildaureon/sdk";
|
|
160
|
+
|
|
161
|
+
describe("SDK Error Handling Tests", () => {
|
|
162
|
+
it("should throw AureonValidationError on empty objective name", async () => {
|
|
163
|
+
const client = new AureonClient({ baseUrl: "https://api.aureonlabs.network" });
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
await client.createObjective({
|
|
167
|
+
name: " ", // Empty string
|
|
168
|
+
kind: "stable_allocation",
|
|
169
|
+
targetWeight: 0.2,
|
|
170
|
+
tolerance: 0.02
|
|
171
|
+
});
|
|
172
|
+
assert.fail("Should have failed pre-flight validation");
|
|
173
|
+
} catch (err) {
|
|
174
|
+
assert.ok(isAureonError(err));
|
|
175
|
+
assert.strictEqual(err.code, "VALIDATION_ERROR");
|
|
176
|
+
assert.ok(err instanceof AureonValidationError);
|
|
177
|
+
assert.match(err.message, /length/);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
Using programmatic switches on `error.code` ensures your code resists backend modifications.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Production Integration Guide
|
|
2
|
+
|
|
3
|
+
This guide details how to integrate `@buildaureon/sdk` into server-side agents, automated rebalancing scripts, and frontend user interfaces.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. End-to-End Integration Plan
|
|
8
|
+
|
|
9
|
+
Follow this six-step sequence to configure and start the automated rebalancing loop.
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
flowchart TD
|
|
13
|
+
Client[1. Client Init] --> Auth[2. Sign Handshake]
|
|
14
|
+
Auth --> Sync[3. Sync Capital Book]
|
|
15
|
+
Sync --> Deposit[4. Fund Vault]
|
|
16
|
+
Deposit --> Objective[5. Add Objective]
|
|
17
|
+
Objective --> Watchdog[6. Run Heartbeat Loop]
|
|
18
|
+
Watchdog --> Watchdog
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Step 1: Client Construction
|
|
22
|
+
Set up the client, leveraging environment variables for configuration options.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { createAureonClient, createSessionTokenProvider } from "@buildaureon/sdk";
|
|
26
|
+
|
|
27
|
+
const session = createSessionTokenProvider(
|
|
28
|
+
typeof localStorage !== "undefined"
|
|
29
|
+
? localStorage.getItem("aureon_bearer_token")
|
|
30
|
+
: process.env.AUREON_TOKEN ?? null
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const aureon = createAureonClient({
|
|
34
|
+
baseUrl: process.env.AUREON_API_URL || "https://api.aureonlabs.network",
|
|
35
|
+
apiKey: process.env.AUREON_API_KEY ?? null,
|
|
36
|
+
getAccessToken: session.getAccessToken
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Step 2: EIP-191 Cryptographic Verification
|
|
41
|
+
Authenticate session tokens using cryptographic challenge-response verification.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
async function authenticate(walletAddress: string, signerFn: (msg: string) => Promise<string>) {
|
|
45
|
+
// 1. Fetch challenge message
|
|
46
|
+
const { message } = await aureon.getAuthNonce(walletAddress);
|
|
47
|
+
|
|
48
|
+
// 2. Sign EIP-191 personal message locally
|
|
49
|
+
const signature = await signerFn(message);
|
|
50
|
+
|
|
51
|
+
// 3. Post verification payload
|
|
52
|
+
const { token } = await aureon.verifyWallet({
|
|
53
|
+
address: walletAddress,
|
|
54
|
+
message,
|
|
55
|
+
signature
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
session.setToken(token);
|
|
59
|
+
return token;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Step 3: Align the Capital Book
|
|
64
|
+
Populate local assets into the gateway database.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const { portfolio, chainId } = await aureon.syncPortfolio();
|
|
68
|
+
console.log(`Portfolios aligned for Chain ID ${chainId}. Total Valuation: $${portfolio.totalNotionalUsd}`);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Step 4: Fund the Smart Vault
|
|
72
|
+
Automated objectives rebalance tokens held in your Smart Vault on the Robinhood Chain. Allocate capital into the vault before creating rules.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
async function ensureVaultFunded(symbol: string, amount: string, executeTx: (step: any) => Promise<string>) {
|
|
76
|
+
const status = await aureon.getVaultStatus();
|
|
77
|
+
if (status.empty) {
|
|
78
|
+
const prep = await aureon.prepareVaultDeposit({ symbol, amount });
|
|
79
|
+
for (const step of prep.steps) {
|
|
80
|
+
console.log(`Executing step: ${step.label}`);
|
|
81
|
+
const txHash = await executeTx(step);
|
|
82
|
+
console.log(`Step complete. Hash: ${txHash}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Step 5: Register the Objective
|
|
89
|
+
Create the objective. SDK integrations default to `automationMode: "auto"`.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const objective = await aureon.createObjective({
|
|
93
|
+
name: "Liquid Stable Reserves",
|
|
94
|
+
kind: "stable_allocation",
|
|
95
|
+
targetWeight: 0.30,
|
|
96
|
+
tolerance: 0.03
|
|
97
|
+
});
|
|
98
|
+
console.log(`Objective ${objective.name} registered. Status: ${objective.status}`);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step 6: Execute the Watchdog Loop
|
|
102
|
+
Poll the gateway regularly to check policy health and execute restorations.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
async function watchdogHeartbeat() {
|
|
106
|
+
try {
|
|
107
|
+
const result = await aureon.refreshWatchdog();
|
|
108
|
+
console.log(`Watchdog completed at ${result.refreshedAt}. System state: ${result.breaches.length} breaches.`);
|
|
109
|
+
|
|
110
|
+
for (const breach of result.breaches) {
|
|
111
|
+
const plan = await aureon.getRestorePlan(breach.objectiveId);
|
|
112
|
+
if (plan.kind === "vault_swap") {
|
|
113
|
+
const receipt = await aureon.restoreObjective(breach.objectiveId);
|
|
114
|
+
console.log(`Rebalance executed. Settlement: ${receipt.settlement}, Hash: ${receipt.transactionHash}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error("Watchdog heartbeat failed:", error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 2. Advanced Scripting Guidelines
|
|
126
|
+
|
|
127
|
+
### 2.1 Implementing daemon runners
|
|
128
|
+
For long-running processes, wrap the heartbeat logic in daemon controllers like PM2 or run them as systemd services.
|
|
129
|
+
|
|
130
|
+
#### PM2 Configuration (`ecosystem.config.js`)
|
|
131
|
+
```js
|
|
132
|
+
module.exports = {
|
|
133
|
+
apps: [{
|
|
134
|
+
name: "aureon-agent-loop",
|
|
135
|
+
script: "./dist/index.js",
|
|
136
|
+
instances: 1,
|
|
137
|
+
autorestart: true,
|
|
138
|
+
watch: false,
|
|
139
|
+
env: {
|
|
140
|
+
NODE_ENV: "production",
|
|
141
|
+
AUREON_API_URL: "https://api.aureonlabs.network"
|
|
142
|
+
}
|
|
143
|
+
}]
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### Systemd Service (`/etc/systemd/system/aureon.service`)
|
|
148
|
+
```ini
|
|
149
|
+
[Unit]
|
|
150
|
+
Description=Aureon Rebalance Watchdog Daemon
|
|
151
|
+
After=network.target
|
|
152
|
+
|
|
153
|
+
[Service]
|
|
154
|
+
Type=simple
|
|
155
|
+
User=node
|
|
156
|
+
WorkingDirectory=/home/node/app
|
|
157
|
+
ExecStart=/usr/bin/node dist/index.js
|
|
158
|
+
Restart=on-failure
|
|
159
|
+
RestartSec=10
|
|
160
|
+
Environment=NODE_ENV=production
|
|
161
|
+
|
|
162
|
+
[Install]
|
|
163
|
+
WantedBy=multi-user.target
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 2.2 Server-Side Logger Configuration (Pino / Winston)
|
|
167
|
+
Log JSON payloads to persistent logging collectors.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import winston from "winston";
|
|
171
|
+
import { createAureonClient } from "@buildaureon/sdk";
|
|
172
|
+
|
|
173
|
+
const logger = winston.createLogger({
|
|
174
|
+
level: "info",
|
|
175
|
+
format: winston.format.json(),
|
|
176
|
+
transports: [new winston.transports.File({ filename: "aureon-combined.log" })]
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const aureon = createAureonClient({
|
|
180
|
+
apiKey: process.env.AUREON_API_KEY,
|
|
181
|
+
logger: {
|
|
182
|
+
debug: (msg, ctx) => logger.debug(msg, ctx),
|
|
183
|
+
info: (msg, ctx) => logger.info(msg, ctx),
|
|
184
|
+
warn: (msg, ctx) => logger.warn(msg, ctx),
|
|
185
|
+
error: (msg, ctx) => logger.error(msg, ctx)
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 3. Frontend Deployment (SPA/Vite Environments)
|
|
193
|
+
|
|
194
|
+
* **Credential Leakage Prevention**: Never commit `AUREON_API_KEY` to public repositories. Deploy client credentials via backend server API proxy routes.
|
|
195
|
+
* **CORS Configurations**: The production gateway allows request origins matching allowlisted domains configured in the Developer console. For local development, localhost calls are permitted.
|
|
196
|
+
* **Decoupled loop execution**: Frontend interfaces should only allow users to manage objectives and inspect histories. Keep the active rebalancing loops (`refreshWatchdog` and `restoreObjective`) on secure server-side cron loops.
|
package/docs/security.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Security Model and Practices
|
|
2
|
+
|
|
3
|
+
This document outlines the security architecture of `@buildaureon/sdk`, its integration with Smart Vault smart contracts, and practices for secure production environments.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Gateway Trust Boundaries
|
|
8
|
+
|
|
9
|
+
AUREON operates on a non-custodial gateway model. The API acts as an analytical policy engine, price indexer, and coordinator, but does not control asset custody.
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
flowchart TD
|
|
13
|
+
Host[Host Application Boundary] -->|1. Request Calldata| Gateway[Aureon API Gateway]
|
|
14
|
+
Gateway -->|2. Generate Unsigned Steps| Host
|
|
15
|
+
Host -->|3. Sign Locally| Wallet[Private Key / HSM / KMS]
|
|
16
|
+
Wallet -->|4. Broadcast Tx| Chain[Robinhood Chain RPC]
|
|
17
|
+
|
|
18
|
+
subgraph OnChain [Smart Contract Controls]
|
|
19
|
+
Vault[Smart Vault Contract]
|
|
20
|
+
DX[Decentralized Exchanges]
|
|
21
|
+
Vault -->|Only allowlisted actions| DX
|
|
22
|
+
end
|
|
23
|
+
Wallet -.->|Call deposit / withdraw| Vault
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 1.1 Private Key Isolation
|
|
27
|
+
The SDK provides no features for loading or storing private keys or mnemonics. The host application handles transaction signing locally using EIP-191 signatures or raw transaction serializers. Because private keys are never transmitted to the AUREON API, a gateway breach cannot compromise user keys.
|
|
28
|
+
|
|
29
|
+
### 1.2 Unsigned Calldata Generation
|
|
30
|
+
Endpoints like `prepareVaultDeposit` and `prepareVaultWithdraw` return structured calldata. You can decode and verify this data against open-source contract ABIs before signing and broadcasting.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. Smart Contract Access Control
|
|
35
|
+
|
|
36
|
+
The AUREON Smart Vault contracts on the Robinhood Chain enforce strict permission boundaries:
|
|
37
|
+
|
|
38
|
+
* **Owner Gate**: Only the address that deployed the vault (or was assigned ownership) can execute direct withdrawals.
|
|
39
|
+
* **Allowlisted Keepers**: Swap routes can only be executed by registered keeper addresses. The keeper cannot withdraw tokens to external third-party addresses; they are restricted to swapping allowlisted assets within the vault.
|
|
40
|
+
* **Limits and Slippage**: The contracts enforce maximum slippage tolerances on swaps to prevent sandwich attacks and price manipulation.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 3. Credentials and API Keys Management
|
|
45
|
+
|
|
46
|
+
* **Zero Commits**: Never check API keys into git repositories. Load keys from environment variables or secure stores (e.g. AWS Secrets Manager, HashiCorp Vault).
|
|
47
|
+
* **CI/CD Configuration**: If you run tests in automated pipelines (e.g., GitHub Actions, GitLab CI), store credentials as encrypted secrets.
|
|
48
|
+
* **Frontend Mitigation**: Frontends should query an intermediate backend service instead of exposing API keys directly to the client bundle.
|
|
49
|
+
* **Key Rotation**: Generate replacement credentials and deprecate compromised tokens in the developer console immediately if a breach is suspected.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 4. Understanding Staged Settlement
|
|
54
|
+
|
|
55
|
+
AUREON receipts contain a `settlement` field:
|
|
56
|
+
|
|
57
|
+
* **Vault Settlement (`vault`)**: Transactions are settled on-chain on the Robinhood Chain. These have a real transaction hash and are verifiable via explorer.
|
|
58
|
+
* **Staged Settlement (`staged`)**: Simulated rebalances that update gateway database states without broadcasting transactions. This is used during rehearsals and testing.
|
|
59
|
+
|
|
60
|
+
> [!WARNING]
|
|
61
|
+
> Do not display staged rebalances as completed on-chain transactions in your dashboards. Always check the `settlement` attribute before presenting transaction confirmations to operators.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 5. Production Checklist
|
|
66
|
+
|
|
67
|
+
Review this security checklist before deploying your rebalancing daemon to production:
|
|
68
|
+
|
|
69
|
+
- [ ] **Private Key Isolation**: Confirm that private keys are stored in environment variables or KMS, and are never logged or exposed.
|
|
70
|
+
- [ ] **EIP-191 Handshake**: Ensure all user logins use the cryptographic challenge-response flow (`verifyWallet`).
|
|
71
|
+
- [ ] **Scope Checks**: Verify that the API Key has the minimum permissions needed to run the target agent.
|
|
72
|
+
- [ ] **Gas Auditing**: Maintain a gas reserve on the signing wallet to cover deposit and withdrawal transactions on the Robinhood Chain.
|
|
73
|
+
- [ ] **Staged Handling**: Confirm your user interface clearly distinguishes between staged and vault settlements.
|
|
74
|
+
- [ ] **Slippage Bounds**: Configure appropriate slippage tolerances on objectives to prevent execution failure during market volatility.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Transport Layer Reference
|
|
2
|
+
|
|
3
|
+
This document describes the transport layer of `@buildaureon/sdk`, implemented in `src/transport/http.ts`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Network Request Lifecycle
|
|
8
|
+
|
|
9
|
+
Every SDK client call delegates network execution to the `requestJson` helper.
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
flowchart TD
|
|
13
|
+
Call[Client Method Call] --> Prep[Join URL & Compile Headers]
|
|
14
|
+
Prep --> Auth[Resolve Bearer Token]
|
|
15
|
+
Auth --> Abort[Set AbortController Timer]
|
|
16
|
+
Abort --> Fetch[Execute fetchImpl]
|
|
17
|
+
Fetch --> Code{HTTP Status OK?}
|
|
18
|
+
Code -->|Yes| Parse[Parse Response JSON]
|
|
19
|
+
Code -->|No| Map[map Status to AureonError]
|
|
20
|
+
Map --> Retry{Is Error Retryable?}
|
|
21
|
+
Retry -->|Yes| Sleep[Sleep retryDelayMs]
|
|
22
|
+
Sleep --> Fetch
|
|
23
|
+
Retry -->|No| Throw[Throw Custom Exception]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
1. **URL Join and Query Compilation**: The transport engine normalizes the base URL and path string, then serializes any query parameters.
|
|
27
|
+
2. **Bearer Token Resolution**: The `getAccessToken` async function evaluates the current session token to attach the `Authorization` header.
|
|
28
|
+
3. **Timeout Guard Configuration**: An `AbortController` handles request timeouts, defaulting to 30 seconds.
|
|
29
|
+
4. **Execution and Error Mapping**: The client fires the request. If the gateway returns an error, it is converted to a typed `AureonError` subclass.
|
|
30
|
+
5. **Bounded Retry**: The client retries the request if it encountered a transient failure (e.g. rate limit, gateway timeout) and retry budget is remaining.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. Standard Header Layout
|
|
35
|
+
|
|
36
|
+
Every HTTP request sent by the SDK contains these default headers:
|
|
37
|
+
|
|
38
|
+
| Header | Required | Typical Value | Purpose |
|
|
39
|
+
|--------|----------|---------------|---------|
|
|
40
|
+
| `Accept` | Yes | `application/json` | Specifies the accepted media type. |
|
|
41
|
+
| `Content-Type` | Optional | `application/json` | Specifies the payload format (attached if a request body is present). |
|
|
42
|
+
| `X-Aureon-SDK` | Yes | `@buildaureon/sdk/0.1.0` | Identifies client package version. |
|
|
43
|
+
| `X-Aureon-Api-Key` | Optional | `api_key_abc123` | Sent if the client is configured with an API key. |
|
|
44
|
+
| `Authorization` | Optional | `Bearer token_xyz` | Session JWT, attached if a token provider is active. |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 3. URL Utility Implementations
|
|
49
|
+
|
|
50
|
+
### 3.1 `joinUrl`
|
|
51
|
+
Normalizes base URLs and paths to prevent double slashes at joining boundaries:
|
|
52
|
+
```ts
|
|
53
|
+
function joinUrl(base: string, path: string): string {
|
|
54
|
+
const cleanBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
55
|
+
const cleanPath = path.startsWith("/") ? path.slice(1) : path;
|
|
56
|
+
return `${cleanBase}/${cleanPath}`;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3.2 `withQuery`
|
|
61
|
+
Serializes query parameter dictionaries into standard URL format:
|
|
62
|
+
```ts
|
|
63
|
+
function withQuery(path: string, query?: Record<string, any>): string {
|
|
64
|
+
if (!query) return path;
|
|
65
|
+
const parts = Object.entries(query)
|
|
66
|
+
.filter(([_, v]) => v !== undefined && v !== null)
|
|
67
|
+
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
|
|
68
|
+
if (parts.length === 0) return path;
|
|
69
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
70
|
+
return `${path}${separator}${parts.join("&")}`;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 4. Timeout Budgets and Request Aborts
|
|
77
|
+
|
|
78
|
+
The transport engine protects applications from hanging sockets using the Fetch API's `AbortController` signal.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const response = await options.fetchImpl(url, {
|
|
86
|
+
...init,
|
|
87
|
+
signal: controller.signal
|
|
88
|
+
});
|
|
89
|
+
return response;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
92
|
+
throw new AureonTimeoutError("Request timed out", options.timeoutMs);
|
|
93
|
+
}
|
|
94
|
+
throw new AureonNetworkError(error instanceof Error ? error.message : String(error));
|
|
95
|
+
} finally {
|
|
96
|
+
clearTimeout(timeoutId);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
* **Configuring Timeout**: Pass `timeoutMs` (in milliseconds) when instantiating `createAureonClient`.
|
|
101
|
+
* **Custom Abort Signals**: You can pass a custom `AbortSignal` in `RequestOptions` to cancel requests manually based on user actions.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 5. Retry Loop and Backoff Configurations
|
|
106
|
+
|
|
107
|
+
The SDK implements a retry mechanism for transient exceptions:
|
|
108
|
+
|
|
109
|
+
* **Retryable Failures**: `NETWORK_ERROR`, `TIMEOUT`, `RATE_LIMITED` (HTTP 429), and `SERVER_ERROR` (HTTP 5xx).
|
|
110
|
+
* **Default Behavior**: `maxRetries` is 0. If you configure `maxRetries: 2` and `retryDelayMs: 500`, the client will try the request up to 3 times, waiting 500ms between attempts.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 6. Built-in Logger Adapters
|
|
115
|
+
|
|
116
|
+
Integrate with internal request diagnostics using the `AureonLogger` interface:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
export interface AureonLogger {
|
|
120
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
121
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
122
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
123
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
* `createConsoleLogger(prefix)`: Logs requests, attempts, and errors to the developer console.
|
|
128
|
+
* `silentLogger`: Suppresses logs.
|