northstar-eva-sdk 0.3.0 → 0.5.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/README.md +56 -0
- package/dist/northstar-eva-sdk.d.ts +140 -6
- package/dist/northstar-eva-sdk.js +209 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,62 @@ const sdk = NorthstarEva.create({ provider, erRpc: ER_RPC_URL, evaProgramId });
|
|
|
16
16
|
```
|
|
17
17
|
> Ships compiled JS + TypeScript types — works in any Node ≥18 project (JS or TS). The three Solana libs are **peer dependencies** (install them alongside). Prefer a single drop-in file instead? See `share/` (no npm). Publishing it yourself? See [PUBLISHING.md](PUBLISHING.md).
|
|
18
18
|
|
|
19
|
+
## Construction — one SDK, three ways (NorthStar or not)
|
|
20
|
+
|
|
21
|
+
The SDK splits two method families: **eva-contract methods** (`initialize`/`createTrench`/`deposit`/`withdraw`/`finalize`/`buy`/`sell`/…) always run on your **`program` + `provider`**; the **NorthStar bridge methods** (`openSession`/`fundFeeToErPayer`/`withdrawFeeFromEr`) need the **L1 + ER** lanes. Pick the construction that fits your service — `sdk.isNorthStar` tells you which mode you're in.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// (1) provider IS the ER, L1 passed separately — RECOMMENDED for NorthStar apps
|
|
25
|
+
const sdk = NorthstarEva.create({ program, provider, l1Endpoint: "https://api.devnet.solana.com" });
|
|
26
|
+
// → provider.connection = ER, l1Endpoint = L1. sdk.isNorthStar === true
|
|
27
|
+
|
|
28
|
+
// (2) NO NorthStar — the SAME SDK as a plain eva client (one chain, no ER/Portal)
|
|
29
|
+
const sdk = NorthstarEva.create({ program, provider });
|
|
30
|
+
// → eva methods run on the provider; deposit/withdraw/session throw "requires NorthStar". sdk.isNorthStar === false
|
|
31
|
+
|
|
32
|
+
// (3) legacy: provider = L1, ER passed as erRpc (still supported)
|
|
33
|
+
const sdk = NorthstarEva.create({ provider, erRpc: "https://ephemeral.devnet.sonic.game" });
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **`l1Endpoint`** means "the provider's RPC is the ER; this is the L1." It's the cleanest fit when your app's provider already points at the ER. (`L1Endpoint` is accepted too.)
|
|
37
|
+
- **Same SDK, both services:** with no `l1Endpoint`/`erRpc`, you get a normal eva client — one codebase covers the NorthStar and non-NorthStar deployments.
|
|
38
|
+
- **Withdraw returns to the sender:** `withdrawFeeFromEr({ lamports })` reclaims the fee to whoever funded the ER (the SDK signer) — no recipient needed.
|
|
39
|
+
|
|
40
|
+
## What's new in 0.4.0
|
|
41
|
+
|
|
42
|
+
**Complete eva coverage — the SDK now mirrors all 11 eva instructions.** Added the 5 that were missing: `updateConfig`, `withdraw`, `closePool`, `claimTokens`, `distributePrize` (each with a `build…Ix` twin):
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// admin / lifecycle
|
|
46
|
+
await sdk.updateConfig({ biddingDuration: 120n, tradingDuration: 100_000n, feeRecipient });
|
|
47
|
+
await sdk.withdraw({ trenchId, amount: 20_000_000n }); // withdraw a bid deposit from a trench
|
|
48
|
+
await sdk.closePool({ trenchId });
|
|
49
|
+
await sdk.claimTokens({ trenchId, user }); // release a user's tokens from the vault
|
|
50
|
+
await sdk.distributePrize({ trenchId, winners: [w1, w2], amounts: [a1, a2] });
|
|
51
|
+
```
|
|
52
|
+
> Note: eva `withdraw` (withdraw a trench bid deposit) is **different** from the Portal `withdrawFeeFromEr` (bridge SOL ER→L1). They coexist.
|
|
53
|
+
|
|
54
|
+
**Instruction builders — get the unsigned instruction instead of sending it.** Every send-method now has a `build…Ix` twin with the **same inputs** that returns an unsigned `TransactionInstruction`, so your backend can compose it with its own instructions, sign, and submit however it needs.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { NorthstarEva } from "northstar-eva-sdk";
|
|
58
|
+
|
|
59
|
+
// 1) build instructions (no signing, no network send — only the reads needed to resolve accounts)
|
|
60
|
+
const ataIx = sdk.buildUserAtaIx({ trenchId });
|
|
61
|
+
const buyIx = await sdk.buildBuyIx({ trenchId, solPayWithFee: 10_000_000n });
|
|
62
|
+
|
|
63
|
+
// 2) compose them (add your own instructions too), get an unsigned Transaction
|
|
64
|
+
const tx = await sdk.buildTransaction([ataIx, buyIx], { lane: "er" }); // feePayer + blockhash set
|
|
65
|
+
|
|
66
|
+
// 3) your backend signs + submits — the SDK never sends it
|
|
67
|
+
tx.sign(myKeypair); // or wallet.signTransaction(tx)
|
|
68
|
+
await connection.sendRawTransaction(tx.serialize());
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Builders (each mirrors the send-method's inputs): `buildOpenSessionIx()`, `buildCloseSessionIx()`, `buildDepositFeeIx(lamports, recipient?)`, `buildWithdrawFeeFromErIx({ lamports, recipient?, toL1? })` (Portal SOL bridge), `buildInitializeIx(p)`, `buildUpdateConfigIx(p)`, `buildCreateTrenchIx({ trenchId?, initialVirtualTokenReserves? })`, `buildDepositIx(p)`, `buildWithdrawIx({ trenchId, amount, thinkId? })` (eva trench withdraw), `buildFinalizeIx(p)`, `buildUserAtaIx(p)`, `buildBuyIx(p)`, `buildSellIx(p)`, `buildClosePoolIx(p)`, `buildClaimTokensIx(p)`, `buildDistributePrizeIx(p)`, plus `buildTransaction(ixs, { lane?, feePayer? })`, `nextTrenchId()`, and the `agentPda(id, user?)` PDA helper.
|
|
72
|
+
|
|
73
|
+
> The existing send-methods (`buy`, `sell`, `fundFeeToErPayer`, …) are unchanged — they now just call these builders internally. Builders perform the same state **reads** to resolve accounts (e.g. `buildBuyIx` reads global for `feeRecipient`) but never **send**.
|
|
74
|
+
|
|
19
75
|
## What's new in 0.3.0
|
|
20
76
|
|
|
21
77
|
**Construct from your existing `program` + `provider`, and an exported `EVA_IDL` — minimal code change.**
|
|
@@ -145,6 +145,12 @@ export interface NorthstarEvaInput {
|
|
|
145
145
|
l1Rpc?: string;
|
|
146
146
|
erRpc?: string;
|
|
147
147
|
erWs?: string;
|
|
148
|
+
/**
|
|
149
|
+
* The L1 endpoint, for the "provider is the ER" convention: when set, the SDK treats the
|
|
150
|
+
* `provider`/`connection` RPC as the **ER** and uses `l1Endpoint` as the **L1** (Portal) lane.
|
|
151
|
+
* (Alternative to passing `erRpc` with a provider that points at L1.)
|
|
152
|
+
*/
|
|
153
|
+
l1Endpoint?: string;
|
|
148
154
|
portalProgramId?: string | PublicKey;
|
|
149
155
|
evaProgramId?: string | PublicKey;
|
|
150
156
|
gridId?: number | bigint;
|
|
@@ -283,11 +289,17 @@ export declare class NorthstarEva {
|
|
|
283
289
|
readonly payer: PublicKey;
|
|
284
290
|
readonly validatorIdentity: PublicKey;
|
|
285
291
|
readonly program: anchor.Program<Idl>;
|
|
292
|
+
/** Whether the NorthStar ER + Portal bridge is configured (false = plain Solana, eva only). */
|
|
293
|
+
readonly northstar: boolean;
|
|
286
294
|
private readonly pollMs;
|
|
287
295
|
/** The eva program id in use (configurable per environment). */
|
|
288
296
|
get evaProgramId(): PublicKey;
|
|
289
297
|
/** The Portal program id in use. */
|
|
290
298
|
get portalProgramId(): PublicKey;
|
|
299
|
+
/** True when deposit/withdraw/session (the NorthStar Portal/ER bridge) are available. */
|
|
300
|
+
get isNorthStar(): boolean;
|
|
301
|
+
/** Throws if the NorthStar bridge isn't configured (used to guard Portal-only methods). */
|
|
302
|
+
private requireNorthStar;
|
|
291
303
|
constructor(opts: NorthstarEvaOptions);
|
|
292
304
|
static create(opts: NorthstarEvaOptions): NorthstarEva;
|
|
293
305
|
erRpc<T = any>(method: string, params?: unknown[]): Promise<T>;
|
|
@@ -317,6 +329,97 @@ export declare class NorthstarEva {
|
|
|
317
329
|
private requireGlobal;
|
|
318
330
|
private get methods();
|
|
319
331
|
private bn;
|
|
332
|
+
/** Portal OpenSession instruction (L1). */
|
|
333
|
+
buildOpenSessionIx(): TransactionInstruction;
|
|
334
|
+
/** Portal CloseSession instruction (L1). */
|
|
335
|
+
buildCloseSessionIx(): TransactionInstruction;
|
|
336
|
+
/** Portal DepositFee instruction (L1) — "fund fee to ER payer". (Caller must ensure a session exists.) */
|
|
337
|
+
buildDepositFeeIx(lamports: bigint, recipient?: PublicKey): TransactionInstruction;
|
|
338
|
+
/** "Withdraw fee from ER" instruction (ER) — system transfer from `recipient` (default: signer) → its WithdrawalSink. (Portal SOL bridge; distinct from the eva `withdraw` instruction.) */
|
|
339
|
+
buildWithdrawFeeFromErIx(p: {
|
|
340
|
+
lamports: bigint;
|
|
341
|
+
recipient?: PublicKey;
|
|
342
|
+
toL1?: PublicKey;
|
|
343
|
+
}): TransactionInstruction;
|
|
344
|
+
/** Next sequential trench id (= total_trenches + 1) read from the ER global state. */
|
|
345
|
+
nextTrenchId(): Promise<bigint>;
|
|
346
|
+
/** eva initialize instruction (ER). */
|
|
347
|
+
buildInitializeIx(p: {
|
|
348
|
+
biddingDuration: bigint;
|
|
349
|
+
tradingDuration: bigint;
|
|
350
|
+
}): Promise<TransactionInstruction>;
|
|
351
|
+
/** eva createTrench instruction (ER). `trenchId` defaults to {@link nextTrenchId}. */
|
|
352
|
+
buildCreateTrenchIx(p?: {
|
|
353
|
+
trenchId?: bigint;
|
|
354
|
+
initialVirtualTokenReserves?: bigint;
|
|
355
|
+
}): Promise<TransactionInstruction>;
|
|
356
|
+
/** eva deposit instruction (ER). */
|
|
357
|
+
buildDepositIx(p: {
|
|
358
|
+
trenchId: bigint;
|
|
359
|
+
lamports: bigint;
|
|
360
|
+
thinkId?: bigint;
|
|
361
|
+
user?: PublicKey;
|
|
362
|
+
}): Promise<TransactionInstruction>;
|
|
363
|
+
/** eva finalize instruction (ER). Reads global for feeRecipient; does NOT wait for the bidding window. */
|
|
364
|
+
buildFinalizeIx(p: {
|
|
365
|
+
trenchId: bigint;
|
|
366
|
+
}): Promise<TransactionInstruction>;
|
|
367
|
+
/** ATA-create instruction (ER) for a user's trench token account (idempotent). */
|
|
368
|
+
buildUserAtaIx(p: {
|
|
369
|
+
trenchId: bigint;
|
|
370
|
+
user?: PublicKey;
|
|
371
|
+
}): TransactionInstruction;
|
|
372
|
+
/** eva buy instruction (ER). Reads global for feeRecipient. */
|
|
373
|
+
buildBuyIx(p: {
|
|
374
|
+
trenchId: bigint;
|
|
375
|
+
solPayWithFee: bigint;
|
|
376
|
+
thinkId?: bigint;
|
|
377
|
+
user?: PublicKey;
|
|
378
|
+
}): Promise<TransactionInstruction>;
|
|
379
|
+
/** eva sell instruction (ER). Reads global for feeRecipient. */
|
|
380
|
+
buildSellIx(p: {
|
|
381
|
+
trenchId: bigint;
|
|
382
|
+
tokenAmount: bigint;
|
|
383
|
+
minSolOutput?: bigint;
|
|
384
|
+
thinkId?: bigint;
|
|
385
|
+
user?: PublicKey;
|
|
386
|
+
}): Promise<TransactionInstruction>;
|
|
387
|
+
/** eva updateConfig instruction (ER, admin) — change bidding/trading durations + fee recipient. */
|
|
388
|
+
buildUpdateConfigIx(p: {
|
|
389
|
+
biddingDuration: bigint;
|
|
390
|
+
tradingDuration: bigint;
|
|
391
|
+
feeRecipient: PublicKey;
|
|
392
|
+
}): Promise<TransactionInstruction>;
|
|
393
|
+
/** eva withdraw instruction (ER) — withdraw a bid deposit from a trench (inverse of {@link buildDepositIx}). NOT the Portal SOL bridge ({@link buildWithdrawFeeFromErIx}). */
|
|
394
|
+
buildWithdrawIx(p: {
|
|
395
|
+
trenchId: bigint;
|
|
396
|
+
amount: bigint;
|
|
397
|
+
thinkId?: bigint;
|
|
398
|
+
user?: PublicKey;
|
|
399
|
+
}): Promise<TransactionInstruction>;
|
|
400
|
+
/** eva closePool instruction (ER, admin) — close a finished trench's pool. */
|
|
401
|
+
buildClosePoolIx(p: {
|
|
402
|
+
trenchId: bigint;
|
|
403
|
+
}): Promise<TransactionInstruction>;
|
|
404
|
+
/** eva claimTokens instruction (ER, admin) — release `user`'s tokens from the trench vault to their ATA. */
|
|
405
|
+
buildClaimTokensIx(p: {
|
|
406
|
+
trenchId: bigint;
|
|
407
|
+
user?: PublicKey;
|
|
408
|
+
}): Promise<TransactionInstruction>;
|
|
409
|
+
/** eva distributePrize instruction (ER, admin) — pay out the prize pool to `winners` by `amounts` (lamports). */
|
|
410
|
+
buildDistributePrizeIx(p: {
|
|
411
|
+
trenchId: bigint;
|
|
412
|
+
winners: PublicKey[];
|
|
413
|
+
amounts: bigint[];
|
|
414
|
+
}): Promise<TransactionInstruction>;
|
|
415
|
+
/**
|
|
416
|
+
* Bundle instruction(s) into an UNSIGNED `Transaction` (feePayer + recent blockhash set) for the
|
|
417
|
+
* given lane (`"er"` default, or `"l1"`). The backend signs + submits it (or adds more instructions first).
|
|
418
|
+
*/
|
|
419
|
+
buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], opts?: {
|
|
420
|
+
lane?: Lane;
|
|
421
|
+
feePayer?: PublicKey;
|
|
422
|
+
}): Promise<Transaction>;
|
|
320
423
|
openSession(): Promise<{
|
|
321
424
|
signature: string | null;
|
|
322
425
|
sessionPda: PublicKey;
|
|
@@ -358,6 +461,7 @@ export declare class NorthstarEva {
|
|
|
358
461
|
tokenMintPda(id: bigint): anchor.web3.PublicKey;
|
|
359
462
|
trenchVault(id: bigint): anchor.web3.PublicKey;
|
|
360
463
|
userAta(id: bigint, user?: PublicKey): anchor.web3.PublicKey;
|
|
464
|
+
agentPda(id: bigint, user?: PublicKey): anchor.web3.PublicKey;
|
|
361
465
|
getGlobal(source?: Lane): Promise<GlobalState | null>;
|
|
362
466
|
getTrench(id: bigint, source?: Lane, retries?: number): Promise<Trench | null>;
|
|
363
467
|
getUserTokenBalance(id: bigint, user?: PublicKey, source?: Lane): Promise<bigint>;
|
|
@@ -383,13 +487,16 @@ export declare class NorthstarEva {
|
|
|
383
487
|
/** The ER WithdrawalSink PDA for a recipient (where ER withdrawal requests are sent). */
|
|
384
488
|
getWithdrawalSink(recipient?: PublicKey): PublicKey;
|
|
385
489
|
/**
|
|
386
|
-
* "Withdraw fee from ER" (path 2): an ER `system_transfer` from
|
|
387
|
-
* WithdrawalSink. The validator pays the L1 SOL
|
|
388
|
-
* (use {@link waitForL1Settlement} to await it).
|
|
389
|
-
*
|
|
390
|
-
*
|
|
490
|
+
* "Withdraw fee from ER" (path 2): an ER `system_transfer` from the **sender** → its
|
|
491
|
+
* WithdrawalSink, returning the fee to whoever sent it. The validator pays the L1 SOL
|
|
492
|
+
* ASYNCHRONOUSLY at the next settlement (use {@link waitForL1Settlement} to await it).
|
|
493
|
+
*
|
|
494
|
+
* By default the **sender = the SDK's signer** (the account that funded the ER), so
|
|
495
|
+
* `withdrawFeeFromEr({ lamports })` reclaims to the sender — no recipient needed. You may
|
|
496
|
+
* still pass `recipient` (a Keypair OR a wallet adapter) to reclaim a different funded
|
|
497
|
+
* account; it signs the ER transfer (the L1 receiver never signs).
|
|
391
498
|
*
|
|
392
|
-
* NOTE: the L1 payout
|
|
499
|
+
* NOTE: the L1 payout goes to the SAME account that deposited (the sender) — an arbitrary
|
|
393
500
|
* `toL1` destination is not supported by the Portal program yet (pending protocol change).
|
|
394
501
|
*/
|
|
395
502
|
requestWithdraw(p: {
|
|
@@ -449,4 +556,31 @@ export declare class NorthstarEva {
|
|
|
449
556
|
trench: Trench;
|
|
450
557
|
userTokens: bigint;
|
|
451
558
|
}>;
|
|
559
|
+
/** eva updateConfig (ER, admin) — set bidding/trading durations + fee recipient on the global config. */
|
|
560
|
+
updateConfig(p: {
|
|
561
|
+
biddingDuration: bigint;
|
|
562
|
+
tradingDuration: bigint;
|
|
563
|
+
feeRecipient: PublicKey;
|
|
564
|
+
}): Promise<string>;
|
|
565
|
+
/** eva withdraw (ER) — withdraw a bid deposit from a trench (inverse of {@link deposit}; NOT the Portal SOL bridge {@link withdrawFeeFromEr}). */
|
|
566
|
+
withdraw(p: {
|
|
567
|
+
trenchId: bigint;
|
|
568
|
+
amount: bigint;
|
|
569
|
+
thinkId?: bigint;
|
|
570
|
+
}): Promise<string>;
|
|
571
|
+
/** eva closePool (ER, admin) — close a finished trench's pool. */
|
|
572
|
+
closePool(p: {
|
|
573
|
+
trenchId: bigint;
|
|
574
|
+
}): Promise<string>;
|
|
575
|
+
/** eva claimTokens (ER, admin) — release `user`'s tokens from the trench vault to their ATA. */
|
|
576
|
+
claimTokens(p: {
|
|
577
|
+
trenchId: bigint;
|
|
578
|
+
user?: PublicKey;
|
|
579
|
+
}): Promise<string>;
|
|
580
|
+
/** eva distributePrize (ER, admin) — pay the prize pool to `winners` by `amounts` (lamports). */
|
|
581
|
+
distributePrize(p: {
|
|
582
|
+
trenchId: bigint;
|
|
583
|
+
winners: PublicKey[];
|
|
584
|
+
amounts: bigint[];
|
|
585
|
+
}): Promise<string>;
|
|
452
586
|
}
|
|
@@ -2159,12 +2159,21 @@ export class NorthstarEva {
|
|
|
2159
2159
|
/** The fee-payer / signer public key. */
|
|
2160
2160
|
payer;
|
|
2161
2161
|
validatorIdentity;
|
|
2162
|
-
program; // eva,
|
|
2162
|
+
program; // eva, runs on the ER (= provider) connection
|
|
2163
|
+
/** Whether the NorthStar ER + Portal bridge is configured (false = plain Solana, eva only). */
|
|
2164
|
+
northstar;
|
|
2163
2165
|
pollMs;
|
|
2164
2166
|
/** The eva program id in use (configurable per environment). */
|
|
2165
2167
|
get evaProgramId() { return this.cfg.evaProgramId; }
|
|
2166
2168
|
/** The Portal program id in use. */
|
|
2167
2169
|
get portalProgramId() { return this.cfg.portalProgramId; }
|
|
2170
|
+
/** True when deposit/withdraw/session (the NorthStar Portal/ER bridge) are available. */
|
|
2171
|
+
get isNorthStar() { return this.northstar; }
|
|
2172
|
+
/** Throws if the NorthStar bridge isn't configured (used to guard Portal-only methods). */
|
|
2173
|
+
requireNorthStar(op) {
|
|
2174
|
+
if (!this.northstar)
|
|
2175
|
+
throw new Error(`${op} requires NorthStar (the ER + Portal bridge), which is not configured. Pass \`l1Endpoint\` (with a provider whose RPC is the ER) or \`erRpc\` to enable deposit/withdraw/session. Without it, only the eva program methods work (plain Solana).`);
|
|
2176
|
+
}
|
|
2168
2177
|
constructor(opts) {
|
|
2169
2178
|
// A pre-built Anchor program (Bai's `(program, provider)` shape) is the source of truth
|
|
2170
2179
|
// for the program id, and can also supply the provider's wallet + L1 connection.
|
|
@@ -2174,9 +2183,39 @@ export class NorthstarEva {
|
|
|
2174
2183
|
if (passedProgram && opts.evaProgramId && new PublicKey(opts.evaProgramId).toBase58() !== programId) {
|
|
2175
2184
|
throw new Error(`evaProgramId (${new PublicKey(opts.evaProgramId).toBase58()}) does not match the passed program.programId (${programId}). Pass one source of truth.`);
|
|
2176
2185
|
}
|
|
2177
|
-
// ── endpoints:
|
|
2186
|
+
// ── endpoints: resolve the L1 + ER lanes and whether NorthStar (ER+Portal) is active ──
|
|
2178
2187
|
const providerConn = opts.provider?.connection ?? opts.connection ?? programProvider?.connection;
|
|
2179
|
-
|
|
2188
|
+
const providerEndpoint = providerConn?.rpcEndpoint;
|
|
2189
|
+
const l1Endpoint = opts.l1Endpoint ?? opts.L1Endpoint; // accept Bai's casing too
|
|
2190
|
+
let l1RpcStr, erRpcStr, northstar;
|
|
2191
|
+
if (l1Endpoint) {
|
|
2192
|
+
// NEW convention: the provider's RPC IS the ER; l1Endpoint is the L1 (Portal) lane.
|
|
2193
|
+
northstar = true;
|
|
2194
|
+
l1RpcStr = l1Endpoint;
|
|
2195
|
+
erRpcStr = opts.erRpc ?? providerEndpoint;
|
|
2196
|
+
if (!erRpcStr)
|
|
2197
|
+
throw new Error("`l1Endpoint` was given but no ER RPC — pass a `provider`/`connection` (its RPC is the ER) or an explicit `erRpc`.");
|
|
2198
|
+
}
|
|
2199
|
+
else if (opts.erRpc) {
|
|
2200
|
+
// LEGACY convention: provider's RPC is L1, erRpc is the ER.
|
|
2201
|
+
northstar = true;
|
|
2202
|
+
l1RpcStr = opts.l1Rpc ?? providerEndpoint;
|
|
2203
|
+
erRpcStr = opts.erRpc;
|
|
2204
|
+
}
|
|
2205
|
+
else if (providerEndpoint || opts.l1Rpc) {
|
|
2206
|
+
// NO-NORTHSTAR: a single chain (provider / l1Rpc). eva runs there; no Portal/ER bridge.
|
|
2207
|
+
northstar = false;
|
|
2208
|
+
l1RpcStr = erRpcStr = opts.l1Rpc ?? providerEndpoint;
|
|
2209
|
+
}
|
|
2210
|
+
else {
|
|
2211
|
+
// Network preset (e.g. localnet has both lanes; devnet needs explicit endpoints).
|
|
2212
|
+
const presetEr = NETWORKS[opts.network === "devnet" ? "devnet" : "localnet"].erRpc;
|
|
2213
|
+
northstar = presetEr !== "";
|
|
2214
|
+
l1RpcStr = opts.l1Rpc;
|
|
2215
|
+
erRpcStr = opts.erRpc; // resolved from preset by resolveConfig below
|
|
2216
|
+
}
|
|
2217
|
+
this.northstar = northstar;
|
|
2218
|
+
this.cfg = resolveConfig({ ...opts, l1Rpc: l1RpcStr ?? opts.l1Rpc, erRpc: erRpcStr ?? opts.erRpc, evaProgramId: opts.evaProgramId ?? programId });
|
|
2180
2219
|
// ── signer: accept a Keypair (wrap it), a wallet adapter, provider.wallet, or program.provider.wallet ──
|
|
2181
2220
|
const w = opts.wallet;
|
|
2182
2221
|
let signer;
|
|
@@ -2196,24 +2235,31 @@ export class NorthstarEva {
|
|
|
2196
2235
|
? (typeof opts.validatorIdentity === "string" ? new PublicKey(opts.validatorIdentity) : opts.validatorIdentity)
|
|
2197
2236
|
: this.payer;
|
|
2198
2237
|
this.pollMs = opts.pollIntervalMs ?? 500;
|
|
2199
|
-
|
|
2200
|
-
//
|
|
2201
|
-
this.
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2238
|
+
// Assign lanes per the resolved convention. `this.er` is where the eva program executes
|
|
2239
|
+
// (the provider's connection in the new/no-NorthStar modes); reads use "processed" so
|
|
2240
|
+
// read-after-write is fresh. `this.l1` is the Portal control lane.
|
|
2241
|
+
if (l1Endpoint) {
|
|
2242
|
+
// provider IS the ER; l1Endpoint is the L1.
|
|
2243
|
+
this.er = providerConn ?? new Connection(this.cfg.erRpc, "processed");
|
|
2244
|
+
this.l1 = new Connection(this.cfg.l1Rpc, "confirmed");
|
|
2245
|
+
}
|
|
2246
|
+
else if (!northstar) {
|
|
2247
|
+
// single chain: eva runs on the provider; no separate Portal/ER lane.
|
|
2248
|
+
this.l1 = this.er = providerConn ?? new Connection(this.cfg.l1Rpc, "confirmed");
|
|
2249
|
+
}
|
|
2250
|
+
else {
|
|
2251
|
+
// legacy / preset: provider (if any) is L1, ER is its own endpoint.
|
|
2252
|
+
this.l1 = providerConn ?? new Connection(this.cfg.l1Rpc, "confirmed");
|
|
2253
|
+
this.er = new Connection(this.cfg.erRpc, "processed");
|
|
2208
2254
|
}
|
|
2209
2255
|
if (passedProgram) {
|
|
2210
|
-
// Use the caller's program as-is
|
|
2256
|
+
// Use the caller's program (program + provider) as-is — eva methods build from it.
|
|
2211
2257
|
this.program = passedProgram;
|
|
2212
2258
|
}
|
|
2213
2259
|
else {
|
|
2214
2260
|
const idl = opts.evaIdl ?? (opts.evaIdlPath ? JSON.parse(readFileSync(opts.evaIdlPath, "utf8")) : loadBundledIdl());
|
|
2215
2261
|
idl.address = this.cfg.evaProgramId.toBase58(); // honor config / devnet override
|
|
2216
|
-
// eva program
|
|
2262
|
+
// eva program runs on `this.er` (= provider) + signs through the same wallet.
|
|
2217
2263
|
const provider = new A.AnchorProvider(this.er, this.wallet, { commitment: "processed" });
|
|
2218
2264
|
this.program = new A.Program(idl, provider);
|
|
2219
2265
|
}
|
|
@@ -2352,21 +2398,119 @@ export class NorthstarEva {
|
|
|
2352
2398
|
}
|
|
2353
2399
|
get methods() { return this.program.methods; }
|
|
2354
2400
|
bn(v) { return new A.BN(v.toString()); }
|
|
2401
|
+
// ───────────────────────── instruction builders (build, DON'T send) ─────────────────────────
|
|
2402
|
+
// Same inputs as the matching send-methods, but each RETURNS the unsigned instruction instead
|
|
2403
|
+
// of signing + submitting — so a backend can compose it with its own instructions, sign, and
|
|
2404
|
+
// send however it wants. State reads needed to resolve accounts still happen; only the network
|
|
2405
|
+
// SEND is omitted. Pair with `buildTransaction()` to get a ready-to-sign Transaction.
|
|
2406
|
+
/** Portal OpenSession instruction (L1). */
|
|
2407
|
+
buildOpenSessionIx() {
|
|
2408
|
+
return portal.openSessionIx({
|
|
2409
|
+
programId: this.cfg.portalProgramId, payer: this.payer,
|
|
2410
|
+
gridId: this.cfg.gridId, ttlSlots: this.cfg.ttlSlots, feeCap: this.cfg.feeCap,
|
|
2411
|
+
validator: this.validatorIdentity, settlementIntervalSlots: this.cfg.settlementIntervalSlots,
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
/** Portal CloseSession instruction (L1). */
|
|
2415
|
+
buildCloseSessionIx() {
|
|
2416
|
+
return portal.closeSessionIx({ programId: this.cfg.portalProgramId, closer: this.payer });
|
|
2417
|
+
}
|
|
2418
|
+
/** Portal DepositFee instruction (L1) — "fund fee to ER payer". (Caller must ensure a session exists.) */
|
|
2419
|
+
buildDepositFeeIx(lamports, recipient = this.payer) {
|
|
2420
|
+
return portal.depositFeeIx({ programId: this.cfg.portalProgramId, depositor: this.payer, recipient, lamports });
|
|
2421
|
+
}
|
|
2422
|
+
/** "Withdraw fee from ER" instruction (ER) — system transfer from `recipient` (default: signer) → its WithdrawalSink. (Portal SOL bridge; distinct from the eva `withdraw` instruction.) */
|
|
2423
|
+
buildWithdrawFeeFromErIx(p) {
|
|
2424
|
+
const recipient = p.recipient ?? this.payer;
|
|
2425
|
+
if (p.toL1 && !p.toL1.equals(recipient))
|
|
2426
|
+
throw new Error("Arbitrary L1 withdrawal destination is not supported yet (Portal pays the deposit recipient). Omit `toL1` or set it equal to recipient.");
|
|
2427
|
+
return SystemProgram.transfer({ fromPubkey: recipient, toPubkey: this.getWithdrawalSink(recipient), lamports: Number(p.lamports) });
|
|
2428
|
+
}
|
|
2429
|
+
/** Next sequential trench id (= total_trenches + 1) read from the ER global state. */
|
|
2430
|
+
async nextTrenchId() { return (await this.requireGlobal()).totalTrenches + 1n; }
|
|
2431
|
+
/** eva initialize instruction (ER). */
|
|
2432
|
+
buildInitializeIx(p) {
|
|
2433
|
+
return this.methods.initialize(this.bn(p.biddingDuration), this.bn(p.tradingDuration)).accounts({ admin: this.payer }).instruction();
|
|
2434
|
+
}
|
|
2435
|
+
/** eva createTrench instruction (ER). `trenchId` defaults to {@link nextTrenchId}. */
|
|
2436
|
+
async buildCreateTrenchIx(p = {}) {
|
|
2437
|
+
const trenchId = p.trenchId ?? await this.nextTrenchId();
|
|
2438
|
+
const ivtr = p.initialVirtualTokenReserves ?? INITIAL_TOKEN_SUPPLY / 2n;
|
|
2439
|
+
return this.methods.createTrench(this.bn(trenchId), this.bn(ivtr)).accounts({ globalState: this.globalStatePda(), creator: this.payer }).instruction();
|
|
2440
|
+
}
|
|
2441
|
+
/** eva deposit instruction (ER). */
|
|
2442
|
+
buildDepositIx(p) {
|
|
2443
|
+
return this.methods.deposit(this.bn(p.lamports), this.bn(p.thinkId ?? 0n)).accounts({ trench: this.trenchPda(p.trenchId), user: p.user ?? this.payer }).instruction();
|
|
2444
|
+
}
|
|
2445
|
+
/** eva finalize instruction (ER). Reads global for feeRecipient; does NOT wait for the bidding window. */
|
|
2446
|
+
async buildFinalizeIx(p) {
|
|
2447
|
+
const g = await this.requireGlobal();
|
|
2448
|
+
return this.methods.finalize().accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), admin: this.payer }).instruction();
|
|
2449
|
+
}
|
|
2450
|
+
/** ATA-create instruction (ER) for a user's trench token account (idempotent). */
|
|
2451
|
+
buildUserAtaIx(p) {
|
|
2452
|
+
const user = p.user ?? this.payer;
|
|
2453
|
+
return createAssociatedTokenAccountIdempotentInstruction(this.payer, this.userAta(p.trenchId, user), user, this.tokenMintPda(p.trenchId), TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID);
|
|
2454
|
+
}
|
|
2455
|
+
/** eva buy instruction (ER). Reads global for feeRecipient. */
|
|
2456
|
+
async buildBuyIx(p) {
|
|
2457
|
+
const g = await this.requireGlobal();
|
|
2458
|
+
const user = p.user ?? this.payer;
|
|
2459
|
+
return this.methods.buy(this.bn(p.solPayWithFee), this.bn(p.thinkId ?? 0n)).accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), user, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId, user), systemProgram: SystemProgram.programId, tokenProgram: TOKEN_PROGRAM_ID }).instruction();
|
|
2460
|
+
}
|
|
2461
|
+
/** eva sell instruction (ER). Reads global for feeRecipient. */
|
|
2462
|
+
async buildSellIx(p) {
|
|
2463
|
+
const g = await this.requireGlobal();
|
|
2464
|
+
const user = p.user ?? this.payer;
|
|
2465
|
+
return this.methods.sell(this.bn(p.tokenAmount), this.bn(p.minSolOutput ?? 0n), this.bn(p.thinkId ?? 0n)).accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), user, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId, user), tokenProgram: TOKEN_PROGRAM_ID }).instruction();
|
|
2466
|
+
}
|
|
2467
|
+
/** eva updateConfig instruction (ER, admin) — change bidding/trading durations + fee recipient. */
|
|
2468
|
+
buildUpdateConfigIx(p) {
|
|
2469
|
+
return this.methods.updateConfig(this.bn(p.biddingDuration), this.bn(p.tradingDuration), p.feeRecipient).accounts({ globalState: this.globalStatePda(), admin: this.payer }).instruction();
|
|
2470
|
+
}
|
|
2471
|
+
/** eva withdraw instruction (ER) — withdraw a bid deposit from a trench (inverse of {@link buildDepositIx}). NOT the Portal SOL bridge ({@link buildWithdrawFeeFromErIx}). */
|
|
2472
|
+
buildWithdrawIx(p) {
|
|
2473
|
+
const user = p.user ?? this.payer;
|
|
2474
|
+
return this.methods.withdraw(this.bn(p.amount), this.bn(p.thinkId ?? 0n)).accounts({ trench: this.trenchPda(p.trenchId), agent: this.agentPda(p.trenchId, user), user }).instruction();
|
|
2475
|
+
}
|
|
2476
|
+
/** eva closePool instruction (ER, admin) — close a finished trench's pool. */
|
|
2477
|
+
async buildClosePoolIx(p) {
|
|
2478
|
+
const g = await this.requireGlobal();
|
|
2479
|
+
return this.methods.closePool().accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), admin: this.payer }).instruction();
|
|
2480
|
+
}
|
|
2481
|
+
/** eva claimTokens instruction (ER, admin) — release `user`'s tokens from the trench vault to their ATA. */
|
|
2482
|
+
buildClaimTokensIx(p) {
|
|
2483
|
+
const user = p.user ?? this.payer;
|
|
2484
|
+
return this.methods.claimTokens().accounts({ globalState: this.globalStatePda(), trench: this.trenchPda(p.trenchId), agent: this.agentPda(p.trenchId, user), user, admin: this.payer, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId, user), tokenProgram: TOKEN_PROGRAM_ID }).instruction();
|
|
2485
|
+
}
|
|
2486
|
+
/** eva distributePrize instruction (ER, admin) — pay out the prize pool to `winners` by `amounts` (lamports). */
|
|
2487
|
+
async buildDistributePrizeIx(p) {
|
|
2488
|
+
const g = await this.requireGlobal();
|
|
2489
|
+
return this.methods.distributePrize(p.winners, p.amounts.map((a) => this.bn(a))).accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), admin: this.payer }).instruction();
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* Bundle instruction(s) into an UNSIGNED `Transaction` (feePayer + recent blockhash set) for the
|
|
2493
|
+
* given lane (`"er"` default, or `"l1"`). The backend signs + submits it (or adds more instructions first).
|
|
2494
|
+
*/
|
|
2495
|
+
async buildTransaction(instructions, opts = {}) {
|
|
2496
|
+
const conn = opts.lane === "l1" ? this.l1 : this.er;
|
|
2497
|
+
const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash(opts.lane === "l1" ? "confirmed" : "processed");
|
|
2498
|
+
const tx = new Transaction({ feePayer: opts.feePayer ?? this.payer, blockhash, lastValidBlockHeight });
|
|
2499
|
+
tx.add(...(Array.isArray(instructions) ? instructions : [instructions]));
|
|
2500
|
+
return tx;
|
|
2501
|
+
}
|
|
2355
2502
|
// ───────────────────────── Portal control (L1) ─────────────────────────
|
|
2356
2503
|
async openSession() {
|
|
2504
|
+
this.requireNorthStar("openSession");
|
|
2357
2505
|
const pda = this.sessionPda();
|
|
2358
2506
|
if (await this.l1GetAccount(pda))
|
|
2359
2507
|
return { signature: null, sessionPda: pda, alreadyOpen: true };
|
|
2360
|
-
const
|
|
2361
|
-
programId: this.cfg.portalProgramId, payer: this.wallet.publicKey,
|
|
2362
|
-
gridId: this.cfg.gridId, ttlSlots: this.cfg.ttlSlots, feeCap: this.cfg.feeCap,
|
|
2363
|
-
validator: this.validatorIdentity, settlementIntervalSlots: this.cfg.settlementIntervalSlots,
|
|
2364
|
-
});
|
|
2365
|
-
const signature = await this.sendOnL1([ix], [this.wallet]);
|
|
2508
|
+
const signature = await this.sendOnL1([this.buildOpenSessionIx()], [this.wallet]);
|
|
2366
2509
|
return { signature, sessionPda: pda, alreadyOpen: false };
|
|
2367
2510
|
}
|
|
2368
2511
|
async closeSession() {
|
|
2369
|
-
|
|
2512
|
+
this.requireNorthStar("closeSession");
|
|
2513
|
+
return this.sendOnL1([this.buildCloseSessionIx()], [this.wallet]);
|
|
2370
2514
|
}
|
|
2371
2515
|
/**
|
|
2372
2516
|
* Ensure the Portal session is open (idempotent). Opens it via {@link openSession} only if
|
|
@@ -2391,9 +2535,10 @@ export class NorthstarEva {
|
|
|
2391
2535
|
* Returns the DepositFee transaction signature.
|
|
2392
2536
|
*/
|
|
2393
2537
|
async fundErFeePayer(lamports, recipient = this.wallet.publicKey, opts = {}) {
|
|
2538
|
+
this.requireNorthStar("fundFeeToErPayer (deposit L1→ER)");
|
|
2394
2539
|
if (opts.ensureSession !== false)
|
|
2395
2540
|
await this.ensureSession();
|
|
2396
|
-
return this.sendOnL1([
|
|
2541
|
+
return this.sendOnL1([this.buildDepositFeeIx(lamports, recipient)], [this.wallet]);
|
|
2397
2542
|
}
|
|
2398
2543
|
/** Ensure the ER fee payer has >= `lamports`; tops up via DepositFee + waits for the credit. */
|
|
2399
2544
|
async ensureErFunds(lamports, recipient = this.wallet.publicKey) {
|
|
@@ -2431,6 +2576,7 @@ export class NorthstarEva {
|
|
|
2431
2576
|
tokenMintPda(id) { return evaPdas.tokenMintPda(this.cfg.evaProgramId, this.trenchPda(id)); }
|
|
2432
2577
|
trenchVault(id) { return evaPdas.trenchTokenVault(this.tokenMintPda(id), this.trenchPda(id)); }
|
|
2433
2578
|
userAta(id, user = this.wallet.publicKey) { return evaPdas.userTokenAccount(this.tokenMintPda(id), user); }
|
|
2579
|
+
agentPda(id, user = this.wallet.publicKey) { return evaPdas.agentPda(this.cfg.evaProgramId, this.trenchPda(id), user); }
|
|
2434
2580
|
// ───────────────────────── eva reads (processed by default) ─────────────────────────
|
|
2435
2581
|
async getGlobal(source = "er") {
|
|
2436
2582
|
const info = source === "er" ? await this.erGetAccount(this.globalStatePda()) : await this.l1GetAccount(this.globalStatePda());
|
|
@@ -2480,23 +2626,23 @@ export class NorthstarEva {
|
|
|
2480
2626
|
return portal.withdrawalSinkPda(this.cfg.portalProgramId, this.sessionPda(), recipient);
|
|
2481
2627
|
}
|
|
2482
2628
|
/**
|
|
2483
|
-
* "Withdraw fee from ER" (path 2): an ER `system_transfer` from
|
|
2484
|
-
* WithdrawalSink. The validator pays the L1 SOL
|
|
2485
|
-
* (use {@link waitForL1Settlement} to await it).
|
|
2486
|
-
*
|
|
2487
|
-
*
|
|
2629
|
+
* "Withdraw fee from ER" (path 2): an ER `system_transfer` from the **sender** → its
|
|
2630
|
+
* WithdrawalSink, returning the fee to whoever sent it. The validator pays the L1 SOL
|
|
2631
|
+
* ASYNCHRONOUSLY at the next settlement (use {@link waitForL1Settlement} to await it).
|
|
2632
|
+
*
|
|
2633
|
+
* By default the **sender = the SDK's signer** (the account that funded the ER), so
|
|
2634
|
+
* `withdrawFeeFromEr({ lamports })` reclaims to the sender — no recipient needed. You may
|
|
2635
|
+
* still pass `recipient` (a Keypair OR a wallet adapter) to reclaim a different funded
|
|
2636
|
+
* account; it signs the ER transfer (the L1 receiver never signs).
|
|
2488
2637
|
*
|
|
2489
|
-
* NOTE: the L1 payout
|
|
2638
|
+
* NOTE: the L1 payout goes to the SAME account that deposited (the sender) — an arbitrary
|
|
2490
2639
|
* `toL1` destination is not supported by the Portal program yet (pending protocol change).
|
|
2491
2640
|
*/
|
|
2492
2641
|
async requestWithdraw(p) {
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
const sink = this.getWithdrawalSink(recipient.publicKey);
|
|
2498
|
-
const ix = SystemProgram.transfer({ fromPubkey: recipient.publicKey, toPubkey: sink, lamports: Number(p.lamports) });
|
|
2499
|
-
return this.sendOnEr([ix], [recipient]);
|
|
2642
|
+
this.requireNorthStar("withdrawFeeFromEr (withdraw ER→L1)");
|
|
2643
|
+
const sender = p.recipient ?? this.wallet; // default: the sender (SDK signer)
|
|
2644
|
+
const ix = this.buildWithdrawFeeFromErIx({ lamports: p.lamports, recipient: sender.publicKey, toL1: p.toL1 });
|
|
2645
|
+
return this.sendOnEr([ix], [sender]);
|
|
2500
2646
|
}
|
|
2501
2647
|
/** "Withdraw fee from ER" (the green-box withdraw API) — alias of {@link requestWithdraw}. */
|
|
2502
2648
|
async withdrawFeeFromEr(p) {
|
|
@@ -2519,30 +2665,20 @@ export class NorthstarEva {
|
|
|
2519
2665
|
async initialize(p) {
|
|
2520
2666
|
if (await this.getGlobal("er"))
|
|
2521
2667
|
return null; // already initialized
|
|
2522
|
-
|
|
2523
|
-
.accounts({ admin: this.wallet.publicKey }).instruction();
|
|
2524
|
-
return this.sendEva(ix, "initialize");
|
|
2668
|
+
return this.sendEva(await this.buildInitializeIx(p), "initialize");
|
|
2525
2669
|
}
|
|
2526
2670
|
/** createTrench with the next sequential id (id == total_trenches + 1). */
|
|
2527
2671
|
async createTrench(p = {}) {
|
|
2528
|
-
const
|
|
2529
|
-
|
|
2530
|
-
throw new Error("global state not initialized — call initialize() first");
|
|
2531
|
-
const trenchId = g.totalTrenches + 1n;
|
|
2532
|
-
const ivtr = p.initialVirtualTokenReserves ?? INITIAL_TOKEN_SUPPLY / 2n;
|
|
2533
|
-
const ix = await this.methods.createTrench(this.bn(trenchId), this.bn(ivtr))
|
|
2534
|
-
.accounts({ globalState: this.globalStatePda(), creator: this.wallet.publicKey }).instruction();
|
|
2672
|
+
const trenchId = await this.nextTrenchId();
|
|
2673
|
+
const ix = await this.buildCreateTrenchIx({ trenchId, initialVirtualTokenReserves: p.initialVirtualTokenReserves });
|
|
2535
2674
|
const signature = await this.sendEva(ix, "createTrench");
|
|
2536
2675
|
return { trenchId, signature };
|
|
2537
2676
|
}
|
|
2538
2677
|
async deposit(p) {
|
|
2539
|
-
|
|
2540
|
-
.accounts({ trench: this.trenchPda(p.trenchId), user: this.wallet.publicKey }).instruction();
|
|
2541
|
-
return this.sendEva(ix, "deposit");
|
|
2678
|
+
return this.sendEva(await this.buildDepositIx(p), "deposit");
|
|
2542
2679
|
}
|
|
2543
2680
|
/** finalize — waits for the ER slot to pass biddingEndBlock, then seeds the AMM. */
|
|
2544
2681
|
async finalize(p) {
|
|
2545
|
-
const g = await this.requireGlobal();
|
|
2546
2682
|
const t = await this.getTrench(p.trenchId, "er", 10);
|
|
2547
2683
|
if (t)
|
|
2548
2684
|
for (let i = 0; i < 80; i++) {
|
|
@@ -2551,28 +2687,38 @@ export class NorthstarEva {
|
|
|
2551
2687
|
break;
|
|
2552
2688
|
await sleep(this.pollMs);
|
|
2553
2689
|
}
|
|
2554
|
-
|
|
2555
|
-
.accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), admin: this.wallet.publicKey }).instruction();
|
|
2556
|
-
return this.sendEva(ix, "finalize");
|
|
2690
|
+
return this.sendEva(await this.buildFinalizeIx(p), "finalize");
|
|
2557
2691
|
}
|
|
2558
2692
|
/** Create the user's token ATA on the ER (buy/sell require it to pre-exist). */
|
|
2559
2693
|
async ensureUserAta(p) {
|
|
2560
|
-
|
|
2561
|
-
const ix = createAssociatedTokenAccountIdempotentInstruction(this.wallet.publicKey, this.userAta(p.trenchId, user), user, this.tokenMintPda(p.trenchId), TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID);
|
|
2562
|
-
return this.sendEva(ix, "ensureUserAta");
|
|
2694
|
+
return this.sendEva(this.buildUserAtaIx(p), "ensureUserAta");
|
|
2563
2695
|
}
|
|
2564
2696
|
async buy(p) {
|
|
2565
|
-
const
|
|
2566
|
-
const ix = await this.methods.buy(this.bn(p.solPayWithFee), this.bn(p.thinkId ?? 0n))
|
|
2567
|
-
.accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), user: this.wallet.publicKey, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId), systemProgram: SystemProgram.programId, tokenProgram: TOKEN_PROGRAM_ID }).instruction();
|
|
2568
|
-
const signature = await this.sendEva(ix, "buy");
|
|
2697
|
+
const signature = await this.sendEva(await this.buildBuyIx(p), "buy");
|
|
2569
2698
|
return { signature, trench: (await this.getTrench(p.trenchId, "er", 5)), userTokens: await this.getUserTokenBalance(p.trenchId) };
|
|
2570
2699
|
}
|
|
2571
2700
|
async sell(p) {
|
|
2572
|
-
const
|
|
2573
|
-
const ix = await this.methods.sell(this.bn(p.tokenAmount), this.bn(p.minSolOutput ?? 0n), this.bn(p.thinkId ?? 0n))
|
|
2574
|
-
.accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), user: this.wallet.publicKey, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId), tokenProgram: TOKEN_PROGRAM_ID }).instruction();
|
|
2575
|
-
const signature = await this.sendEva(ix, "sell");
|
|
2701
|
+
const signature = await this.sendEva(await this.buildSellIx(p), "sell");
|
|
2576
2702
|
return { signature, trench: (await this.getTrench(p.trenchId, "er", 5)), userTokens: await this.getUserTokenBalance(p.trenchId) };
|
|
2577
2703
|
}
|
|
2704
|
+
/** eva updateConfig (ER, admin) — set bidding/trading durations + fee recipient on the global config. */
|
|
2705
|
+
async updateConfig(p) {
|
|
2706
|
+
return this.sendEva(await this.buildUpdateConfigIx(p), "updateConfig");
|
|
2707
|
+
}
|
|
2708
|
+
/** eva withdraw (ER) — withdraw a bid deposit from a trench (inverse of {@link deposit}; NOT the Portal SOL bridge {@link withdrawFeeFromEr}). */
|
|
2709
|
+
async withdraw(p) {
|
|
2710
|
+
return this.sendEva(await this.buildWithdrawIx(p), "withdraw");
|
|
2711
|
+
}
|
|
2712
|
+
/** eva closePool (ER, admin) — close a finished trench's pool. */
|
|
2713
|
+
async closePool(p) {
|
|
2714
|
+
return this.sendEva(await this.buildClosePoolIx(p), "closePool");
|
|
2715
|
+
}
|
|
2716
|
+
/** eva claimTokens (ER, admin) — release `user`'s tokens from the trench vault to their ATA. */
|
|
2717
|
+
async claimTokens(p) {
|
|
2718
|
+
return this.sendEva(await this.buildClaimTokensIx(p), "claimTokens");
|
|
2719
|
+
}
|
|
2720
|
+
/** eva distributePrize (ER, admin) — pay the prize pool to `winners` by `amounts` (lamports). */
|
|
2721
|
+
async distributePrize(p) {
|
|
2722
|
+
return this.sendEva(await this.buildDistributePrizeIx(p), "distributePrize");
|
|
2723
|
+
}
|
|
2578
2724
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "northstar-eva-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Run the eva program on a NorthStar ephemeral rollup (zero-fee hot path). A high-level class SDK over the NorthStar Portal/ER protocol + the eva Anchor program. Works localnet & devnet.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|