@kehtus/proportion-sdk 0.1.1 → 0.1.3
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/dist/abi/factory.d.ts +1 -0
- package/dist/abi/factory.d.ts.map +1 -0
- package/dist/abi/factory.js +1 -0
- package/dist/abi/factory.js.map +1 -0
- package/dist/abi/forwarder.d.ts +1 -0
- package/dist/abi/forwarder.d.ts.map +1 -0
- package/dist/abi/forwarder.js +1 -0
- package/dist/abi/forwarder.js.map +1 -0
- package/dist/abi/fundedAccount.d.ts +1 -0
- package/dist/abi/fundedAccount.d.ts.map +1 -0
- package/dist/abi/fundedAccount.js +1 -0
- package/dist/abi/fundedAccount.js.map +1 -0
- package/dist/abi/mainVault.d.ts +198 -16
- package/dist/abi/mainVault.d.ts.map +1 -0
- package/dist/abi/mainVault.js +253 -19
- package/dist/abi/mainVault.js.map +1 -0
- package/dist/account.d.ts +3 -2
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +46 -43
- package/dist/account.js.map +1 -0
- package/dist/base.d.ts +9 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +19 -0
- package/dist/base.js.map +1 -0
- package/dist/constants.d.ts +5 -4
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +5 -4
- package/dist/constants.js.map +1 -0
- package/dist/factory.d.ts +1 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +56 -10
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer.d.ts +8 -3
- package/dist/indexer.d.ts.map +1 -0
- package/dist/indexer.js +81 -136
- package/dist/indexer.js.map +1 -0
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +1 -0
- package/dist/sdk.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +10 -0
- package/dist/utils.js.map +1 -0
- package/dist/vault.d.ts +7 -4
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +76 -51
- package/dist/vault.js.map +1 -0
- package/package.json +12 -1
- package/SDK_IMPROVEMENT_PLAN.md +0 -197
- package/arch.md +0 -455
- package/dist/__tests__/account.test.d.ts +0 -1
- package/dist/__tests__/account.test.js +0 -36
- package/dist/__tests__/indexer.test.d.ts +0 -1
- package/dist/__tests__/indexer.test.js +0 -230
- package/dist/__tests__/lifecycle.test.d.ts +0 -1
- package/dist/__tests__/lifecycle.test.js +0 -186
- package/dist/__tests__/reads.test.d.ts +0 -1
- package/dist/__tests__/reads.test.js +0 -184
- package/dist/__tests__/utils.test.d.ts +0 -1
- package/dist/__tests__/utils.test.js +0 -185
- package/src/__tests__/account.test.ts +0 -40
- package/src/__tests__/indexer.test.ts +0 -255
- package/src/__tests__/lifecycle.test.ts +0 -231
- package/src/__tests__/reads.test.ts +0 -208
- package/src/__tests__/utils.test.ts +0 -245
- package/src/abi/factory.ts +0 -417
- package/src/abi/forwarder.ts +0 -373
- package/src/abi/fundedAccount.ts +0 -1296
- package/src/abi/mainVault.ts +0 -1852
- package/src/account.ts +0 -325
- package/src/constants.ts +0 -51
- package/src/factory.ts +0 -157
- package/src/index.ts +0 -16
- package/src/indexer.ts +0 -636
- package/src/sdk.ts +0 -93
- package/src/types.ts +0 -421
- package/src/utils.ts +0 -143
- package/src/vault.ts +0 -479
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -8
package/arch.md
DELETED
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
# Proportion SDK
|
|
2
|
-
|
|
3
|
-
TypeScript SDK over the current local Proportion Solidity contracts.
|
|
4
|
-
|
|
5
|
-
This document is intentionally aligned to the code in:
|
|
6
|
-
|
|
7
|
-
- `contracts/MainVault.sol`
|
|
8
|
-
- `contracts/FundedAccount.sol`
|
|
9
|
-
- `contracts/FundedAccountFactory.sol`
|
|
10
|
-
- `prop-sdk/src/*`
|
|
11
|
-
|
|
12
|
-
If documentation and Solidity diverge, Solidity is the source of truth.
|
|
13
|
-
|
|
14
|
-
## Key Contract Integration Notes
|
|
15
|
-
|
|
16
|
-
- **Single Managed Signer:** Only `apiWallet` exists on FundedAccount. It is set by the relayer via `setApiWallet()`. No `riskEngineWallet` or `builderRiskEngineWallet`.
|
|
17
|
-
- **Unified Mode:** FundedAccount operates in Hyperliquid unified mode (shared spot + perp balance). Withdrawals use one-step `spotSend` instead of two-step `usdClassTransfer` + `spotSend`.
|
|
18
|
-
- **6dec Account Values:** `accountMarginSummary` returns 6dec. `highWaterMark`, `dayStartValue`, and drawdown floors are all 6dec. `spotBalance` and `spotSend` use 8dec.
|
|
19
|
-
- **Multi-DEX:** `PERP_DEX_COUNT = 2` replaces `PERP_DEX_INDEX = 0`. Account value is summed across all DEXes + spot.
|
|
20
|
-
- **`bridgeToEvm()`** is restricted to `Returning` state only (retry `spotSend` for stuck funds during close flow).
|
|
21
|
-
|
|
22
|
-
## Architecture
|
|
23
|
-
|
|
24
|
-
The SDK has four runtime modules:
|
|
25
|
-
|
|
26
|
-
- `vault`: `MainVault` reads, LP flows, builder flows, and owner admin writes.
|
|
27
|
-
- `account`: `FundedAccount` reads and writes for a specific funded account clone.
|
|
28
|
-
- `factory`: `FundedAccountFactory` helpers around deterministic account addresses and factory state.
|
|
29
|
-
- `indexer`: optional Envio GraphQL/WebSocket client for off-chain querying and subscriptions.
|
|
30
|
-
|
|
31
|
-
`ProportionSDK` itself is a thin composition layer over `viem`.
|
|
32
|
-
|
|
33
|
-
## Initialization
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
import { ProportionSDK, hyperEvm } from "@proportion/sdk";
|
|
37
|
-
import { createWalletClient, http } from "viem";
|
|
38
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
39
|
-
|
|
40
|
-
const wallet = createWalletClient({
|
|
41
|
-
account: privateKeyToAccount("0x..."),
|
|
42
|
-
chain: hyperEvm,
|
|
43
|
-
transport: http(),
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const sdk = new ProportionSDK({
|
|
47
|
-
graphqlUrl: "https://your-envio-endpoint/graphql",
|
|
48
|
-
walletClient: wallet,
|
|
49
|
-
});
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
There are two construction modes:
|
|
53
|
-
|
|
54
|
-
- `new ProportionSDK(config)`: uses addresses from `config.addresses` or `src/constants.ts`.
|
|
55
|
-
- `await ProportionSDK.create(config)`: resolves addresses in this order:
|
|
56
|
-
1. `config.addresses`
|
|
57
|
-
2. `PROPORTION_VAULT_ADDRESS`, `PROPORTION_FACTORY_ADDRESS`, `PROPORTION_USDC_ADDRESS`
|
|
58
|
-
3. `indexer.getProtocolConfig()`
|
|
59
|
-
4. if vault is already known but `USDC` is missing, `usdc()` is read from `MainVault`
|
|
60
|
-
5. hardcoded SDK defaults
|
|
61
|
-
|
|
62
|
-
Best practice:
|
|
63
|
-
|
|
64
|
-
- Prefer explicit `config.addresses` or ENV in applications and services.
|
|
65
|
-
- Treat `indexer.getProtocolConfig()` as a convenience fallback, not as the primary source of deployment addresses.
|
|
66
|
-
- Use `new ProportionSDK(config)` when you already know the full address set and want direct construction without async resolution.
|
|
67
|
-
|
|
68
|
-
## Config
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
interface SDKConfig {
|
|
72
|
-
graphqlUrl: string;
|
|
73
|
-
graphqlWsUrl?: string;
|
|
74
|
-
rpcUrl?: string;
|
|
75
|
-
walletClient?: WalletClient;
|
|
76
|
-
fetchFn?: typeof fetch;
|
|
77
|
-
webSocketCtor?: WebSocketConstructor;
|
|
78
|
-
addresses?: {
|
|
79
|
-
MAIN_VAULT?: string;
|
|
80
|
-
FACTORY?: string;
|
|
81
|
-
USDC?: string;
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
For service or server integrations, `fetchFn` and `webSocketCtor` can be injected explicitly instead of relying on global runtime objects.
|
|
87
|
-
|
|
88
|
-
The exported addresses in `src/constants.ts` are SDK defaults for the current environment, not a guarantee of future deployments.
|
|
89
|
-
|
|
90
|
-
## Modules
|
|
91
|
-
|
|
92
|
-
### `prop.vault`
|
|
93
|
-
|
|
94
|
-
Reads:
|
|
95
|
-
|
|
96
|
-
```ts
|
|
97
|
-
const stats = await prop.vault.getStats();
|
|
98
|
-
const position = await prop.vault.getLPPosition("0x...");
|
|
99
|
-
const builder = await prop.vault.getBuilderInfo("0x...");
|
|
100
|
-
const perps = await prop.vault.getAllowedPerps();
|
|
101
|
-
const allowed = await prop.vault.isAllowedPerp(0);
|
|
102
|
-
const fee = await prop.vault.calculateFee(toUsdc(5000), 500, false);
|
|
103
|
-
const paused = await prop.vault.isPaused();
|
|
104
|
-
const remainingCap = await prop.vault.getRemainingCap();
|
|
105
|
-
const isFa = await prop.vault.isFundedAccount("0x...");
|
|
106
|
-
const delegatedTo = await prop.vault.getDelegateBuilder("0x...");
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
`getStats()` returns both operational metrics and current mutable vault config:
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
type VaultStats = {
|
|
113
|
-
totalAssets: bigint;
|
|
114
|
-
sharePrice: bigint;
|
|
115
|
-
utilizationBps: bigint;
|
|
116
|
-
availableForAllocation: bigint;
|
|
117
|
-
maxAccountSize: bigint;
|
|
118
|
-
remainingCap: bigint;
|
|
119
|
-
paused: boolean;
|
|
120
|
-
feeMultiplier: number;
|
|
121
|
-
subscriptionFeeMultiplier: number;
|
|
122
|
-
totalShares: bigint;
|
|
123
|
-
totalAllocated: bigint;
|
|
124
|
-
owner: Address;
|
|
125
|
-
pendingOwner: Address;
|
|
126
|
-
relayer: Address;
|
|
127
|
-
protocolFeeReceiver: Address;
|
|
128
|
-
maxCap: bigint;
|
|
129
|
-
hypeForSpot: bigint;
|
|
130
|
-
factory: Address;
|
|
131
|
-
minBuilderShares: bigint;
|
|
132
|
-
builderLeverage: bigint;
|
|
133
|
-
protocolFeeBps: bigint;
|
|
134
|
-
minAccountSize: bigint;
|
|
135
|
-
maxAccountSizeLimit: bigint;
|
|
136
|
-
minDrawdownBps: number;
|
|
137
|
-
maxDrawdownBps: number;
|
|
138
|
-
maxUtilizationBps: bigint;
|
|
139
|
-
maxSingleAccountBps: bigint;
|
|
140
|
-
dailyDdDiscountBps: number;
|
|
141
|
-
};
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Writes:
|
|
145
|
-
|
|
146
|
-
```ts
|
|
147
|
-
await prop.vault.approveUsdc(toUsdc(1000));
|
|
148
|
-
await prop.vault.deposit(toUsdc(1000));
|
|
149
|
-
await prop.vault.withdraw(shareAmount);
|
|
150
|
-
|
|
151
|
-
await prop.vault.registerBuilder();
|
|
152
|
-
await prop.vault.setDelegate("0x...");
|
|
153
|
-
await prop.vault.removeDelegate("0x...");
|
|
154
|
-
|
|
155
|
-
await prop.vault.activateFunded({
|
|
156
|
-
trader: "0x...",
|
|
157
|
-
accountSize: toUsdc(5000),
|
|
158
|
-
drawdownBps: 500,
|
|
159
|
-
dailyDrawdownEnabled: false,
|
|
160
|
-
});
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
`activateFunded()` now reads `hypeForSpot()` from the vault when `hypeValue` is not supplied, so the SDK follows the current contract config instead of hardcoding a stale native value.
|
|
164
|
-
|
|
165
|
-
Admin writes covered by the SDK:
|
|
166
|
-
|
|
167
|
-
```ts
|
|
168
|
-
await prop.vault.pause();
|
|
169
|
-
await prop.vault.unpause();
|
|
170
|
-
await prop.vault.setRelayer("0x...");
|
|
171
|
-
await prop.vault.setFactory("0x...");
|
|
172
|
-
await prop.vault.setProtocolFeeReceiver("0x...");
|
|
173
|
-
await prop.vault.setFeeMultiplier(120);
|
|
174
|
-
await prop.vault.setSubscriptionFeeMultiplier(150);
|
|
175
|
-
await prop.vault.setHypeForSpot(1_000_000_000_000_000n);
|
|
176
|
-
await prop.vault.setMaxCap(0n);
|
|
177
|
-
await prop.vault.setMinBuilderShares(toUsdc(10));
|
|
178
|
-
await prop.vault.setBuilderLeverage(10n);
|
|
179
|
-
await prop.vault.setProtocolFeeBps(1000n);
|
|
180
|
-
await prop.vault.setMinAccountSize(toUsdc(10));
|
|
181
|
-
await prop.vault.setMaxAccountSize(toUsdc(50_000));
|
|
182
|
-
await prop.vault.setMinDrawdownBps(500);
|
|
183
|
-
await prop.vault.setMaxDrawdownBps(2500);
|
|
184
|
-
await prop.vault.setMaxUtilizationBps(8000n);
|
|
185
|
-
await prop.vault.setMaxSingleAccountBps(1000n);
|
|
186
|
-
await prop.vault.setDailyDdDiscountBps(2000);
|
|
187
|
-
await prop.vault.addAllowedPerp(4);
|
|
188
|
-
await prop.vault.removeAllowedPerp(4);
|
|
189
|
-
await prop.vault.transferOwnership("0x...");
|
|
190
|
-
await prop.vault.acceptOwnership();
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### `prop.account`
|
|
194
|
-
|
|
195
|
-
Reads:
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
const details = await prop.account.getDetails("0xAccount");
|
|
199
|
-
const state = await prop.account.getState("0xAccount");
|
|
200
|
-
const trailing = await prop.account.getTrailingFloor("0xAccount");
|
|
201
|
-
const daily = await prop.account.getDailyFloor("0xAccount");
|
|
202
|
-
const canWithdraw = await prop.account.canWithdrawProfit("0xAccount");
|
|
203
|
-
const subActive = await prop.account.isSubscriptionActive("0xAccount");
|
|
204
|
-
const checkpoints = await prop.account.getCheckpoints("0xAccount");
|
|
205
|
-
const pending = await prop.account.getPendingWithdrawal("0xAccount");
|
|
206
|
-
const config = await prop.account.getAccountConfig("0xAccount");
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
`getDetails()` includes the current per-account `subscriptionFeeMultiplier`, exposes `checkpointIndex`, and normalizes the on-chain checkpoint ring buffer into chronological order.
|
|
210
|
-
|
|
211
|
-
Writes:
|
|
212
|
-
|
|
213
|
-
```ts
|
|
214
|
-
await prop.account.setApiWallet("0xAccount", "0xWallet"); // relayer-only
|
|
215
|
-
await prop.account.requestWithdrawProfit("0xAccount");
|
|
216
|
-
await prop.account.cancelSubscription("0xAccount");
|
|
217
|
-
|
|
218
|
-
await prop.account.checkpoint("0xAccount");
|
|
219
|
-
await prop.account.initiateClose("0xAccount");
|
|
220
|
-
await prop.account.initiateCloseForPerp("0xAccount", 0);
|
|
221
|
-
await prop.account.initiateCloseAdmin("0xAccount");
|
|
222
|
-
await prop.account.closeAndReturn("0xAccount");
|
|
223
|
-
await prop.account.bridgeToEvm("0xAccount"); // Returning state only — retry spotSend
|
|
224
|
-
await prop.account.finalizeReturn("0xAccount");
|
|
225
|
-
await prop.account.claimWithdrawal("0xAccount");
|
|
226
|
-
await prop.account.claimSubscriptionFee("0xAccount");
|
|
227
|
-
await prop.account.rescueStuckFunds("0xAccount");
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### `prop.factory`
|
|
231
|
-
|
|
232
|
-
Canonical on-chain surface of the current factory:
|
|
233
|
-
|
|
234
|
-
- `predictFundedAccountAddress(owner, builder)`
|
|
235
|
-
- `allAccounts(index)`
|
|
236
|
-
- `allAccountsIndex(account)`
|
|
237
|
-
- `traderBuilderNonce(owner, builder)`
|
|
238
|
-
- public config getters such as `implementation`, `owner`, `pendingOwner`, `usdc`, and `vault`
|
|
239
|
-
|
|
240
|
-
SDK helpers:
|
|
241
|
-
|
|
242
|
-
```ts
|
|
243
|
-
const predicted = await prop.factory.predictAddress(owner, builder);
|
|
244
|
-
const nonce = await prop.factory.getTraderBuilderNonce(owner, builder);
|
|
245
|
-
const account0 = await prop.factory.getAccountAt(0n);
|
|
246
|
-
const index = await prop.factory.getAccountIndex(account0);
|
|
247
|
-
const exists = await prop.factory.hasAccount(account0);
|
|
248
|
-
const safeIndex = await prop.factory.findAccountIndex(account0);
|
|
249
|
-
const cfg = await prop.factory.getConfig();
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
For backwards compatibility, the SDK still exposes:
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
const count = await prop.factory.getAccountsCount();
|
|
256
|
-
const page = await prop.factory.getAccounts(0n, 10n);
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
These are now implemented in the SDK by probing `allAccounts(index)` because the current Solidity factory does not expose explicit `getAccountsCount()` or paginated `getAccounts()` functions.
|
|
260
|
-
|
|
261
|
-
### `prop.indexer`
|
|
262
|
-
|
|
263
|
-
GraphQL queries:
|
|
264
|
-
|
|
265
|
-
```ts
|
|
266
|
-
await prop.indexer.getVault();
|
|
267
|
-
await prop.indexer.getLP("0x...");
|
|
268
|
-
await prop.indexer.getLPDeposits("0x...", { limit: 20, offset: 0 });
|
|
269
|
-
await prop.indexer.getLPWithdrawals("0x...");
|
|
270
|
-
await prop.indexer.getBuilder("0x...");
|
|
271
|
-
await prop.indexer.getBuilder("0x...", "0xVault...");
|
|
272
|
-
await prop.indexer.getDelegates("0x...");
|
|
273
|
-
await prop.indexer.getDelegates("0x...", "0xVault...");
|
|
274
|
-
await prop.indexer.getAccount("0x...");
|
|
275
|
-
await prop.indexer.getAccountsByOwner("0x...");
|
|
276
|
-
await prop.indexer.getAccountsByBuilder("0x...");
|
|
277
|
-
await prop.indexer.getAccountsByBuilder("0x...", "0xVault...");
|
|
278
|
-
await prop.indexer.getAccountsByState("ACTIVE");
|
|
279
|
-
await prop.indexer.getAccountsByStates(["ACTIVE", "CLOSING"]);
|
|
280
|
-
await prop.indexer.getAccountsUpdatedSince("1709500000");
|
|
281
|
-
await prop.indexer.getCheckpoints("0x...");
|
|
282
|
-
await prop.indexer.getWithdrawals("0x...");
|
|
283
|
-
await prop.indexer.getSubscriptionPayments("0x...");
|
|
284
|
-
await prop.indexer.getEvents("0x...");
|
|
285
|
-
await prop.indexer.getEventsByType("Initialized", 5);
|
|
286
|
-
await prop.indexer.getProtocolConfig();
|
|
287
|
-
await prop.indexer.getMainVaultConfig();
|
|
288
|
-
await prop.indexer.getFactoryConfig();
|
|
289
|
-
await prop.indexer.getConfigChanges({ field: "protocolFeeBps", limit: 20 });
|
|
290
|
-
await prop.indexer.getVaultDayData();
|
|
291
|
-
await prop.indexer.getVaultDayData("0xVault...", { limit: 30 });
|
|
292
|
-
await prop.indexer.getLPDayData("0x...");
|
|
293
|
-
await prop.indexer.getAllowedPerps();
|
|
294
|
-
await prop.indexer.getAllowedPerps("0xVault...");
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
When `vaultAddress` is omitted, `getVault()`, `getMainVaultConfig()`, `getBuilder()`, `getDelegates()`, `getAccountsByBuilder()`, `getVaultDayData()`, and `getAllowedPerps()` default to the active vault from `ProtocolConfig`.
|
|
298
|
-
This is a convenience default only; production callers can pass `vaultAddress` explicitly to avoid hidden address resolution.
|
|
299
|
-
|
|
300
|
-
When `factoryAddress` is omitted, `getFactoryConfig()` defaults to the active factory from `ProtocolConfig`.
|
|
301
|
-
This is a convenience default only; production callers can pass `factoryAddress` explicitly to avoid hidden address resolution.
|
|
302
|
-
|
|
303
|
-
The SDK indexer layer follows `envio-funded/schema.graphql`, not the on-chain enum surface directly. That means:
|
|
304
|
-
|
|
305
|
-
- indexer account states start at `INITIALIZED`, not `UNINITIALIZED`
|
|
306
|
-
- `breachType` includes `POSITION_LEVERAGE`
|
|
307
|
-
- the SDK exposes address-keyed config/history entities like `MainVaultConfig`, `FactoryConfig`, `ConfigChange`, and `VaultDayData`
|
|
308
|
-
- `Vault` and `FundedAccount` GraphQL objects expose extra indexed fields such as `totalAllocated`, `totalShares`, `subscriptionFeeMultiplier`, `lastWithdrawalId`, `closePendingSubFee`, `closePendingProfit`, `cumulativeActivationFeesToVault`, `cumulativeCancelledProfit`, `cumulativeProtocolFeesRouted`, `cumulativeHypercoreFees`, `cumulativeRescuedFunds`, `protocolFeeBps`, and `protocolFeeReceiver`
|
|
309
|
-
- `LiquidityProviderDayData` exists in the current schema and is wrapped by the SDK, but the current indexer handlers do not populate it yet, so queries may legitimately return empty arrays
|
|
310
|
-
|
|
311
|
-
Subscriptions:
|
|
312
|
-
|
|
313
|
-
```ts
|
|
314
|
-
const unsubActive = prop.indexer.subscribeActiveAccounts((accounts) => {});
|
|
315
|
-
const unsubAccount = prop.indexer.subscribeAccount("0x...", (account) => {});
|
|
316
|
-
const unsubEvents = prop.indexer.subscribeAccountEvents("0x...", (events) => {});
|
|
317
|
-
const unsubStates = prop.indexer.subscribeStateChanges((accounts) => {});
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
Call `prop.disconnect()` to close all WebSocket state.
|
|
321
|
-
|
|
322
|
-
## Utility Math
|
|
323
|
-
|
|
324
|
-
The utility layer mirrors the current contract formulas.
|
|
325
|
-
|
|
326
|
-
Decimals:
|
|
327
|
-
|
|
328
|
-
```ts
|
|
329
|
-
toUsdc(100); // 100_000_000n (6dec)
|
|
330
|
-
fromUsdc(100_000_000n); // 100
|
|
331
|
-
to8Dec(100_000_000n); // 10_000_000_000n (6dec→8dec, for spotSend)
|
|
332
|
-
toUsdc6(10_000_000_000n); // 100_000_000n (8dec→6dec)
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
Note: On-chain `highWaterMark`, `dayStartValue`, and drawdown floors are all 6dec (matching `accountMarginSummary` output). `spotBalance` and `spotSend` use 8dec.
|
|
336
|
-
|
|
337
|
-
Activation fee:
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
activationFee(toUsdc(5000), 500, false, 120); // 300 USDC
|
|
341
|
-
activationFee(toUsdc(5000), 500, true, 120, 2000); // 240 USDC
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
Formula:
|
|
345
|
-
|
|
346
|
-
```text
|
|
347
|
-
accountSize * drawdownBps * feeMultiplier / 1_000_000
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
The helper then rounds up to whole USDC units, matching the current contract behavior.
|
|
351
|
-
|
|
352
|
-
If daily drawdown is enabled, the helper applies `dailyDdDiscountBps`:
|
|
353
|
-
|
|
354
|
-
```text
|
|
355
|
-
fee * (10000 - dailyDdDiscountBps) / 10000
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
`activationFee()` defaults `dailyDdDiscountBps` from `src/constants.ts`.
|
|
359
|
-
For exact live parity with a deployed vault, pass `vault.getStats().dailyDdDiscountBps`.
|
|
360
|
-
|
|
361
|
-
Subscription fee:
|
|
362
|
-
|
|
363
|
-
```ts
|
|
364
|
-
subscriptionFee(toUsdc(5000), 150); // 75 USDC
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
Canonical formula:
|
|
368
|
-
|
|
369
|
-
```text
|
|
370
|
-
accountSize * subscriptionFeeMultiplier / 10000
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
The helper rounds the result up to whole USDC units.
|
|
374
|
-
|
|
375
|
-
The helper still accepts the legacy 4-argument signature for compatibility, but drawdown and daily-DD no longer affect the result because the current contracts do not use them in subscription pricing.
|
|
376
|
-
|
|
377
|
-
Profit split:
|
|
378
|
-
|
|
379
|
-
```ts
|
|
380
|
-
const { owner, vault, protocol } = splitProfit(toUsdc(1000));
|
|
381
|
-
// owner = 800
|
|
382
|
-
// vault = 130
|
|
383
|
-
// protocol = 70
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
State labels:
|
|
387
|
-
|
|
388
|
-
```ts
|
|
389
|
-
stateToLabel(AccountState.Uninitialized); // "UNINITIALIZED"
|
|
390
|
-
labelToState("CLOSING"); // AccountState.Closing
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
## Defaults vs Dynamic Config
|
|
394
|
-
|
|
395
|
-
Two categories exist in the SDK:
|
|
396
|
-
|
|
397
|
-
- Static source defaults exported from `src/constants.ts`.
|
|
398
|
-
- Mutable on-chain config read from `MainVault`.
|
|
399
|
-
|
|
400
|
-
Examples of values that can change on-chain through admin setters:
|
|
401
|
-
|
|
402
|
-
- `feeMultiplier`
|
|
403
|
-
- `subscriptionFeeMultiplier`
|
|
404
|
-
- `MIN_BUILDER_SHARES`
|
|
405
|
-
- `BUILDER_LEVERAGE`
|
|
406
|
-
- `PROTOCOL_FEE_BPS`
|
|
407
|
-
- `MIN_ACCOUNT_SIZE`
|
|
408
|
-
- `MAX_ACCOUNT_SIZE`
|
|
409
|
-
- `MIN_DRAWDOWN_BPS`
|
|
410
|
-
- `MAX_DRAWDOWN_BPS`
|
|
411
|
-
- `MAX_UTILIZATION_BPS`
|
|
412
|
-
- `MAX_SINGLE_ACCOUNT_BPS`
|
|
413
|
-
- `dailyDdDiscountBps`
|
|
414
|
-
- `hypeForSpot`
|
|
415
|
-
- `maxCap`
|
|
416
|
-
|
|
417
|
-
Best practice:
|
|
418
|
-
|
|
419
|
-
- Use exported constants for local validation defaults and tests.
|
|
420
|
-
- Use `vault.getStats()` before showing risk, pricing, or activation constraints to users.
|
|
421
|
-
|
|
422
|
-
## Testing
|
|
423
|
-
|
|
424
|
-
```bash
|
|
425
|
-
npm run check
|
|
426
|
-
npm run test:unit
|
|
427
|
-
npm run test:reads
|
|
428
|
-
npm run test:lifecycle
|
|
429
|
-
npm run test:indexer
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
Notes:
|
|
433
|
-
|
|
434
|
-
- `test:unit` is fully local.
|
|
435
|
-
- `test:reads`, `test:lifecycle`, and `test:indexer` require reachable RPC/GraphQL endpoints.
|
|
436
|
-
- Current Foundry tests in `/test` are still on an older contract API and should not be treated as SDK source of truth until updated.
|
|
437
|
-
|
|
438
|
-
## File Layout
|
|
439
|
-
|
|
440
|
-
```text
|
|
441
|
-
src/
|
|
442
|
-
sdk.ts
|
|
443
|
-
vault.ts
|
|
444
|
-
account.ts
|
|
445
|
-
factory.ts
|
|
446
|
-
indexer.ts
|
|
447
|
-
types.ts
|
|
448
|
-
constants.ts
|
|
449
|
-
utils.ts
|
|
450
|
-
index.ts
|
|
451
|
-
abi/
|
|
452
|
-
mainVault.ts
|
|
453
|
-
fundedAccount.ts
|
|
454
|
-
factory.ts
|
|
455
|
-
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { normalizeCheckpoints } from "../account.js";
|
|
3
|
-
describe("normalizeCheckpoints", () => {
|
|
4
|
-
it("keeps linear order before the ring buffer wraps", () => {
|
|
5
|
-
const checkpoints = [
|
|
6
|
-
{ accountValue: 100n, timestamp: 1n, profitable: false },
|
|
7
|
-
{ accountValue: 110n, timestamp: 2n, profitable: true },
|
|
8
|
-
{ accountValue: 120n, timestamp: 3n, profitable: true },
|
|
9
|
-
{ accountValue: 0n, timestamp: 0n, profitable: false },
|
|
10
|
-
{ accountValue: 0n, timestamp: 0n, profitable: false },
|
|
11
|
-
{ accountValue: 0n, timestamp: 0n, profitable: false },
|
|
12
|
-
{ accountValue: 0n, timestamp: 0n, profitable: false },
|
|
13
|
-
];
|
|
14
|
-
expect(normalizeCheckpoints(checkpoints, 3, 3).map((cp) => cp.accountValue)).toEqual([100n, 110n, 120n]);
|
|
15
|
-
});
|
|
16
|
-
it("returns chronological order after the ring buffer wraps", () => {
|
|
17
|
-
const checkpoints = [
|
|
18
|
-
{ accountValue: 800n, timestamp: 8n, profitable: true },
|
|
19
|
-
{ accountValue: 200n, timestamp: 2n, profitable: false },
|
|
20
|
-
{ accountValue: 300n, timestamp: 3n, profitable: false },
|
|
21
|
-
{ accountValue: 400n, timestamp: 4n, profitable: false },
|
|
22
|
-
{ accountValue: 500n, timestamp: 5n, profitable: true },
|
|
23
|
-
{ accountValue: 600n, timestamp: 6n, profitable: true },
|
|
24
|
-
{ accountValue: 700n, timestamp: 7n, profitable: true },
|
|
25
|
-
];
|
|
26
|
-
expect(normalizeCheckpoints(checkpoints, 7, 1).map((cp) => cp.accountValue)).toEqual([
|
|
27
|
-
200n,
|
|
28
|
-
300n,
|
|
29
|
-
400n,
|
|
30
|
-
500n,
|
|
31
|
-
600n,
|
|
32
|
-
700n,
|
|
33
|
-
800n,
|
|
34
|
-
]);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "dotenv/config";
|