@neutral-trade/sdk 0.2.12 → 0.3.1
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/README.md +10 -1
- package/dist/index.d.mts +5 -8
- package/dist/index.mjs +26 -22
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -147,7 +147,16 @@ This is simpler and doesn't require an additional network request at initializat
|
|
|
147
147
|
|
|
148
148
|
## Examples
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
See the [examples](./examples) directory. From the `sdk/` package root (clone this repo):
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Local validator default RPC: http://127.0.0.1:8899 — override with SOLANA_RPC_URL
|
|
154
|
+
export SOLANA_KEYPAIR_PATH="$HOME/.config/solana/id.json"
|
|
155
|
+
pnpm example:devnet:deposit
|
|
156
|
+
pnpm example:devnet:withdraw
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Uses the built-in devnet registry (`src/registry/vaults.devnet.json`, e.g. vault `100000001`). Your RPC must serve that vault on-chain; override vault id with `DEVNET_BUNDLE_VAULT_ID` if you use `NeutralTrade.create({ registry: [...] })` patterns in a forked script.
|
|
151
160
|
|
|
152
161
|
## License
|
|
153
162
|
|
package/dist/index.d.mts
CHANGED
|
@@ -3377,18 +3377,17 @@ declare class NeutralTrade {
|
|
|
3377
3377
|
userAddress: string;
|
|
3378
3378
|
}): Promise<UserBalanceResult>;
|
|
3379
3379
|
/**
|
|
3380
|
-
* Build deposit instructions (
|
|
3380
|
+
* Build deposit instructions (`initializeBundleDepositor` when needed, then `requestDeposit`).
|
|
3381
|
+
* Fetches bundle and user bundle accounts on-chain.
|
|
3381
3382
|
*/
|
|
3382
3383
|
buildDepositInstructions({
|
|
3383
3384
|
vaultId,
|
|
3384
3385
|
userAddress,
|
|
3385
|
-
amount
|
|
3386
|
-
needsInit
|
|
3386
|
+
amount
|
|
3387
3387
|
}: {
|
|
3388
3388
|
vaultId: number;
|
|
3389
3389
|
userAddress: string;
|
|
3390
3390
|
amount: number;
|
|
3391
|
-
needsInit?: boolean;
|
|
3392
3391
|
}): Promise<TransactionInstruction[]>;
|
|
3393
3392
|
/**
|
|
3394
3393
|
* Build request-withdraw instruction. Fetches vault, oracle, and depositor accounts on-chain.
|
|
@@ -3412,7 +3411,6 @@ interface BuildBundleDepositInstructionsParams {
|
|
|
3412
3411
|
user: PublicKey;
|
|
3413
3412
|
/** UI token amount (multiplied by 10**on-chain decimals inside). */
|
|
3414
3413
|
amount: number;
|
|
3415
|
-
needsInit?: boolean;
|
|
3416
3414
|
}
|
|
3417
3415
|
interface BuildBundleRequestWithdrawInstructionParams {
|
|
3418
3416
|
bundleProgram: Program<Ntbundle>;
|
|
@@ -3422,15 +3420,14 @@ interface BuildBundleRequestWithdrawInstructionParams {
|
|
|
3422
3420
|
amount: number;
|
|
3423
3421
|
}
|
|
3424
3422
|
/**
|
|
3425
|
-
*
|
|
3423
|
+
* `initializeBundleDepositor` (when missing) + `requestDeposit`. Fetches bundle + user bundle internally.
|
|
3426
3424
|
*/
|
|
3427
3425
|
declare function buildBundleDepositInstructions({
|
|
3428
3426
|
bundleProgram,
|
|
3429
3427
|
bundleCluster,
|
|
3430
3428
|
vault,
|
|
3431
3429
|
user,
|
|
3432
|
-
amount
|
|
3433
|
-
needsInit
|
|
3430
|
+
amount
|
|
3434
3431
|
}: BuildBundleDepositInstructionsParams): Promise<TransactionInstruction[]>;
|
|
3435
3432
|
/**
|
|
3436
3433
|
* `requestWithdrawal` only. Fetches bundle, oracle, and user bundle internally.
|
package/dist/index.mjs
CHANGED
|
@@ -12847,25 +12847,26 @@ function getDriftProgramId(vault) {
|
|
|
12847
12847
|
/**
|
|
12848
12848
|
* Transform a registry entry to VaultConfig with program IDs
|
|
12849
12849
|
* - Drift vaults get driftProgramId
|
|
12850
|
-
* - Bundle vaults get bundleProgramId
|
|
12850
|
+
* - Bundle vaults get bundleProgramId (registry value or cluster default via {@link getBundleProgramId})
|
|
12851
12851
|
*/
|
|
12852
|
-
function toVaultConfig(entry) {
|
|
12852
|
+
function toVaultConfig(entry, cluster = "mainnet") {
|
|
12853
12853
|
return {
|
|
12854
12854
|
...entry,
|
|
12855
12855
|
driftProgramId: getDriftProgramId(entry),
|
|
12856
|
-
bundleProgramId: entry
|
|
12856
|
+
bundleProgramId: getBundleProgramId(entry, cluster)
|
|
12857
12857
|
};
|
|
12858
12858
|
}
|
|
12859
12859
|
/**
|
|
12860
12860
|
* Transform an array of registry entries to VaultRegistry
|
|
12861
|
+
* @param cluster - Used to resolve default bundle program id when `bundleProgramId` is omitted in JSON
|
|
12861
12862
|
*/
|
|
12862
|
-
function toVaultRegistry(entries) {
|
|
12863
|
-
return Object.fromEntries(entries.map((entry) => [entry.vaultId, toVaultConfig(entry)]));
|
|
12863
|
+
function toVaultRegistry(entries, cluster = "mainnet") {
|
|
12864
|
+
return Object.fromEntries(entries.map((entry) => [entry.vaultId, toVaultConfig(entry, cluster)]));
|
|
12864
12865
|
}
|
|
12865
12866
|
const parsedVaultsMainnet = VaultRegistryArraySchema.parse(vaults_default);
|
|
12866
12867
|
const parsedVaultsDevnet = VaultRegistryArraySchema.parse(vaults_devnet_default);
|
|
12867
|
-
const vaultsMainnetRegistry = toVaultRegistry(parsedVaultsMainnet);
|
|
12868
|
-
const vaultsDevnetRegistry = toVaultRegistry(parsedVaultsDevnet);
|
|
12868
|
+
const vaultsMainnetRegistry = toVaultRegistry(parsedVaultsMainnet, "mainnet");
|
|
12869
|
+
const vaultsDevnetRegistry = toVaultRegistry(parsedVaultsDevnet, "devnet");
|
|
12869
12870
|
/** Mainnet registry (default; backward compatible). */
|
|
12870
12871
|
const vaults = vaultsMainnetRegistry;
|
|
12871
12872
|
/** Devnet-only vault registry (fixtures / local testing). */
|
|
@@ -13102,18 +13103,21 @@ function bundleProgramIdForVault(vault, bundleCluster = "mainnet") {
|
|
|
13102
13103
|
return id;
|
|
13103
13104
|
}
|
|
13104
13105
|
/**
|
|
13105
|
-
*
|
|
13106
|
+
* `initializeBundleDepositor` (when missing) + `requestDeposit`. Fetches bundle + user bundle internally.
|
|
13106
13107
|
*/
|
|
13107
|
-
async function buildBundleDepositInstructions({ bundleProgram, bundleCluster = "mainnet", vault, user, amount
|
|
13108
|
+
async function buildBundleDepositInstructions({ bundleProgram, bundleCluster = "mainnet", vault, user, amount }) {
|
|
13108
13109
|
assertBundleVault(vault);
|
|
13109
13110
|
const bundlePDA = new PublicKey(vault.vaultAddress);
|
|
13110
13111
|
const programId = bundleProgramIdForVault(vault, bundleCluster);
|
|
13111
13112
|
if (programId !== bundleProgram.programId.toBase58()) throw new Error(`Vault ${vault.vaultId} program id mismatch: vault=${programId}, client=${bundleProgram.programId.toBase58()}`);
|
|
13112
|
-
const bundleInfo = await bundleProgram.account.bundle.fetch(bundlePDA);
|
|
13113
|
-
const depositAmountBN = new BN(Math.floor(amount * 10 ** bundleInfo.assetDecimals));
|
|
13114
13113
|
const programPk = bundleProgram.programId;
|
|
13115
|
-
const oraclePDA = deriveOraclePDA(bundlePDA, programPk);
|
|
13116
13114
|
const userPDA = deriveUserPDA(user, bundlePDA, programPk);
|
|
13115
|
+
const [bundleAcc, userBundleAcc] = await bundleProgram.provider.connection.getMultipleAccountsInfo([bundlePDA, userPDA]);
|
|
13116
|
+
if (!bundleAcc?.data?.length) throw new Error(`Bundle account not found for vault ${vault.vaultId}`);
|
|
13117
|
+
const bundleInfo = bundleProgram.coder.accounts.decode("bundle", bundleAcc.data);
|
|
13118
|
+
const needsInit = (userBundleAcc?.data?.length ? bundleProgram.coder.accounts.decode("userBundleAccount", userBundleAcc.data) : null) === null;
|
|
13119
|
+
const depositAmountBN = new BN(Math.floor(amount * 10 ** bundleInfo.assetDecimals));
|
|
13120
|
+
const oraclePDA = deriveOraclePDA(bundlePDA, programPk);
|
|
13117
13121
|
const tempDataPDA = deriveTempDataPDA(bundlePDA, programPk);
|
|
13118
13122
|
const pendingAuthPDA = derivePendingAuthPDA(bundlePDA, programPk);
|
|
13119
13123
|
const userTokenAcct = getAssociatedTokenAddressSync(bundleInfo.assetAddress, user, true);
|
|
@@ -13282,14 +13286,14 @@ var NeutralTrade = class NeutralTrade {
|
|
|
13282
13286
|
const cluster = config.bundleCluster ?? "mainnet";
|
|
13283
13287
|
let vaults$1 = config.includeBuiltInVaults !== false ? { ...getVaultRegistry(cluster) } : {};
|
|
13284
13288
|
if (config.registry) {
|
|
13285
|
-
const localVaults = NeutralTrade.parseVaultRegistryEntries(config.registry, "registry");
|
|
13289
|
+
const localVaults = NeutralTrade.parseVaultRegistryEntries(config.registry, "registry", cluster);
|
|
13286
13290
|
vaults$1 = {
|
|
13287
13291
|
...vaults$1,
|
|
13288
13292
|
...localVaults
|
|
13289
13293
|
};
|
|
13290
13294
|
}
|
|
13291
13295
|
if (config.registryUrl) {
|
|
13292
|
-
const remoteVaults = await NeutralTrade.fetchVaultsFromRegistry(config.registryUrl);
|
|
13296
|
+
const remoteVaults = await NeutralTrade.fetchVaultsFromRegistry(config.registryUrl, cluster);
|
|
13293
13297
|
vaults$1 = {
|
|
13294
13298
|
...vaults$1,
|
|
13295
13299
|
...remoteVaults
|
|
@@ -13321,21 +13325,21 @@ var NeutralTrade = class NeutralTrade {
|
|
|
13321
13325
|
if (!bundleProgram) throw new Error(`Bundle program client not initialized for vault ${vault.vaultId}: ${programId}. Please add it to bundlePrograms config or registry.`);
|
|
13322
13326
|
return bundleProgram;
|
|
13323
13327
|
}
|
|
13324
|
-
static parseVaultRegistryEntries(entries, sourceLabel) {
|
|
13328
|
+
static parseVaultRegistryEntries(entries, sourceLabel, cluster) {
|
|
13325
13329
|
const parseResult = VaultRegistryArraySchema.safeParse(entries);
|
|
13326
13330
|
if (!parseResult.success) throw new Error(`Invalid ${sourceLabel} data: ${parseResult.error.message}`);
|
|
13327
|
-
return toVaultRegistry(parseResult.data);
|
|
13331
|
+
return toVaultRegistry(parseResult.data, cluster);
|
|
13328
13332
|
}
|
|
13329
13333
|
/**
|
|
13330
13334
|
* Fetch vault configurations from a remote registry URL
|
|
13331
13335
|
* Expects JSON array format and transforms to Record<number, VaultConfig>
|
|
13332
13336
|
* @throws Error if fetch fails or validation fails
|
|
13333
13337
|
*/
|
|
13334
|
-
static async fetchVaultsFromRegistry(registryUrl) {
|
|
13338
|
+
static async fetchVaultsFromRegistry(registryUrl, cluster) {
|
|
13335
13339
|
const response = await fetch(registryUrl);
|
|
13336
13340
|
if (!response.ok) throw new Error(`Failed to fetch vaults from registry: ${response.status} ${response.statusText}`);
|
|
13337
13341
|
const data = await response.json();
|
|
13338
|
-
return NeutralTrade.parseVaultRegistryEntries(data, "vault registry");
|
|
13342
|
+
return NeutralTrade.parseVaultRegistryEntries(data, "vault registry", cluster);
|
|
13339
13343
|
}
|
|
13340
13344
|
/**
|
|
13341
13345
|
* Get user balance for Bundle vaults only.
|
|
@@ -13357,9 +13361,10 @@ var NeutralTrade = class NeutralTrade {
|
|
|
13357
13361
|
});
|
|
13358
13362
|
}
|
|
13359
13363
|
/**
|
|
13360
|
-
* Build deposit instructions (
|
|
13364
|
+
* Build deposit instructions (`initializeBundleDepositor` when needed, then `requestDeposit`).
|
|
13365
|
+
* Fetches bundle and user bundle accounts on-chain.
|
|
13361
13366
|
*/
|
|
13362
|
-
async buildDepositInstructions({ vaultId, userAddress, amount
|
|
13367
|
+
async buildDepositInstructions({ vaultId, userAddress, amount }) {
|
|
13363
13368
|
const vault = this.vaults[vaultId];
|
|
13364
13369
|
if (!vault) throw new Error(`Vault config not found for vaultId ${vaultId}`);
|
|
13365
13370
|
return buildBundleDepositInstructions({
|
|
@@ -13367,8 +13372,7 @@ var NeutralTrade = class NeutralTrade {
|
|
|
13367
13372
|
bundleCluster: this.bundleCluster,
|
|
13368
13373
|
vault,
|
|
13369
13374
|
user: new PublicKey(userAddress),
|
|
13370
|
-
amount
|
|
13371
|
-
needsInit
|
|
13375
|
+
amount
|
|
13372
13376
|
});
|
|
13373
13377
|
}
|
|
13374
13378
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neutral-trade/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.1",
|
|
5
5
|
"description": "SDK for Neutral Trade vaults",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/neutral-trade/sdk#readme",
|
|
@@ -69,6 +69,10 @@
|
|
|
69
69
|
"lint": "eslint",
|
|
70
70
|
"release": "bumpp",
|
|
71
71
|
"start": "tsx src/index.ts",
|
|
72
|
+
"example:devnet:deposit": "tsx examples/devnet-deposit.ts",
|
|
73
|
+
"example:devnet:withdraw": "tsx examples/devnet-withdraw.ts",
|
|
74
|
+
"diagnose:balances": "tsx diagnose/vault-balance-fetch.ts",
|
|
75
|
+
"diagnose:deposit-conservation": "tsx diagnose/deposit-conservation.ts",
|
|
72
76
|
"test": "vitest",
|
|
73
77
|
"typecheck": "tsc",
|
|
74
78
|
"docs:build": "typedoc",
|