northstar-eva-sdk 0.2.0 → 0.3.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 CHANGED
@@ -16,6 +16,27 @@ 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
+ ## What's new in 0.3.0
20
+
21
+ **Construct from your existing `program` + `provider`, and an exported `EVA_IDL` — minimal code change.**
22
+
23
+ - **Pass a pre-built Anchor `program`.** `NorthstarEva.create({ program, provider, erRpc })` mirrors the old `new EvaArenaSDK(program, provider)` shape. The SDK **adopts `program.programId` as the single source of truth** (all PDA derivations follow it) and reuses the program's `provider.wallet` + `provider.connection` — so the program id can never disagree between L1 and the ER, or across environments. (If you *also* pass a conflicting `evaProgramId`, the SDK throws instead of silently mismatching.)
24
+ - **`EVA_IDL` is now exported** — build your program exactly like before:
25
+ ```ts
26
+ import { NorthstarEva, EVA_IDL } from "northstar-eva-sdk";
27
+
28
+ const wallet = new ReadOnlyWallet(userPubkey); // no Keypair (Turnkey)
29
+ const provider = new anchor.AnchorProvider(connection, wallet, { commitment: "confirmed" });
30
+ const programId = getProgramId(); // per-environment id
31
+ const program = new anchor.Program({ ...EVA_IDL, address: programId.toBase58() }, provider);
32
+
33
+ const sdk = NorthstarEva.create({ program, provider, erRpc: ER_RPC_URL });
34
+ // sdk.evaProgramId === programId (adopted from your program)
35
+ ```
36
+ - The eva program is **one address, identical on L1 and ER** (the ER reanchors and executes the L1 program — there is no separate ER deployment), and both `evaProgramId`/`portalProgramId` remain configurable + readable via `sdk.evaProgramId` / `sdk.portalProgramId`.
37
+
38
+ > Backwards compatible: `{ network, wallet: keypair }` and `{ provider, erRpc, evaProgramId }` both still work.
39
+
19
40
  ## What's new in 0.2.0
20
41
 
21
42
  Integration-friendly construction — **no Keypair required, keep your provider, any RPC URL.**
@@ -249,6 +249,16 @@ export interface NorthstarEvaOptions extends NorthstarEvaInput {
249
249
  provider?: anchor.AnchorProvider;
250
250
  /** Explicit L1 connection (alternative to `provider`/`l1Rpc`). */
251
251
  connection?: Connection;
252
+ /**
253
+ * A pre-built Anchor `Program` for eva (as you already build with your IDL + program id).
254
+ * If given, it becomes the SINGLE SOURCE OF TRUTH for the program id — the SDK adopts
255
+ * `program.programId` (so all PDA derivations follow it), and reuses the program's
256
+ * `provider.wallet`/`provider.connection` for the signer + L1 endpoint. Use the exported
257
+ * `EVA_IDL` to build it: `new anchor.Program({ ...EVA_IDL, address }, provider)`.
258
+ */
259
+ program?: anchor.Program<Idl>;
260
+ /** Alias of `program`. */
261
+ evaProgram?: anchor.Program<Idl>;
252
262
  /** eva IDL object. If omitted, loaded from `evaIdlPath` or the bundled IDL. */
253
263
  evaIdl?: Idl;
254
264
  evaIdlPath?: string;
@@ -257,6 +267,12 @@ export interface NorthstarEvaOptions extends NorthstarEvaInput {
257
267
  /** ms between status/read polls. */
258
268
  pollIntervalMs?: number;
259
269
  }
270
+ /**
271
+ * The eva Anchor IDL, exported as a constant so you can build your own `Program`:
272
+ * `new anchor.Program({ ...EVA_IDL, address: programId.toBase58() }, provider)` and pass it
273
+ * to `NorthstarEva.create({ program, provider, erRpc })`.
274
+ */
275
+ export declare const EVA_IDL: Idl;
260
276
  export declare class NorthstarEva {
261
277
  readonly cfg: ResolvedConfig;
262
278
  readonly l1: Connection;
@@ -2144,6 +2144,12 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
2144
2144
  function loadBundledIdl() {
2145
2145
  return __EVA_IDL__;
2146
2146
  }
2147
+ /**
2148
+ * The eva Anchor IDL, exported as a constant so you can build your own `Program`:
2149
+ * `new anchor.Program({ ...EVA_IDL, address: programId.toBase58() }, provider)` and pass it
2150
+ * to `NorthstarEva.create({ program, provider, erRpc })`.
2151
+ */
2152
+ export const EVA_IDL = loadBundledIdl();
2147
2153
  export class NorthstarEva {
2148
2154
  cfg;
2149
2155
  l1;
@@ -2160,10 +2166,18 @@ export class NorthstarEva {
2160
2166
  /** The Portal program id in use. */
2161
2167
  get portalProgramId() { return this.cfg.portalProgramId; }
2162
2168
  constructor(opts) {
2163
- // ── endpoints: a provider/connection can supply the L1 endpoint; ER is always separate ──
2164
- const providerConn = opts.provider?.connection ?? opts.connection;
2165
- this.cfg = resolveConfig({ ...opts, l1Rpc: opts.l1Rpc ?? providerConn?.rpcEndpoint });
2166
- // ── signer: accept a Keypair (wrap it), a wallet adapter, or provider.wallet ──
2169
+ // A pre-built Anchor program (Bai's `(program, provider)` shape) is the source of truth
2170
+ // for the program id, and can also supply the provider's wallet + L1 connection.
2171
+ const passedProgram = opts.program ?? opts.evaProgram;
2172
+ const programProvider = passedProgram?.provider;
2173
+ const programId = passedProgram?.programId?.toBase58();
2174
+ if (passedProgram && opts.evaProgramId && new PublicKey(opts.evaProgramId).toBase58() !== programId) {
2175
+ throw new Error(`evaProgramId (${new PublicKey(opts.evaProgramId).toBase58()}) does not match the passed program.programId (${programId}). Pass one source of truth.`);
2176
+ }
2177
+ // ── endpoints: a provider/connection/program can supply the L1 endpoint; ER is always separate ──
2178
+ const providerConn = opts.provider?.connection ?? opts.connection ?? programProvider?.connection;
2179
+ this.cfg = resolveConfig({ ...opts, l1Rpc: opts.l1Rpc ?? providerConn?.rpcEndpoint, evaProgramId: opts.evaProgramId ?? programId });
2180
+ // ── signer: accept a Keypair (wrap it), a wallet adapter, provider.wallet, or program.provider.wallet ──
2167
2181
  const w = opts.wallet;
2168
2182
  let signer;
2169
2183
  if (isWalletLike(w))
@@ -2172,8 +2186,10 @@ export class NorthstarEva {
2172
2186
  signer = new A.Wallet(w); // a Keypair → wrap (NodeWallet)
2173
2187
  else if (opts.provider?.wallet)
2174
2188
  signer = opts.provider.wallet;
2189
+ else if (programProvider?.wallet)
2190
+ signer = programProvider.wallet;
2175
2191
  if (!signer)
2176
- throw new Error("Pass `wallet` (a Keypair or a wallet adapter with signTransaction) or a `provider` (AnchorProvider).");
2192
+ throw new Error("Pass `wallet` (a Keypair or a wallet adapter with signTransaction), a `provider` (AnchorProvider), or a `program` whose provider has a wallet.");
2177
2193
  this.wallet = signer;
2178
2194
  this.payer = signer.publicKey;
2179
2195
  this.validatorIdentity = opts.validatorIdentity
@@ -2190,11 +2206,17 @@ export class NorthstarEva {
2190
2206
  if (customL1 && erDefaulted && !/127\.0\.0\.1|localhost/.test(this.cfg.l1Rpc)) {
2191
2207
  throw new Error(`Custom L1 endpoint (${this.cfg.l1Rpc}) but no ER endpoint — NorthStar's ER is a SEPARATE URL. Pass erRpc (e.g. the :8910 endpoint).`);
2192
2208
  }
2193
- const idl = opts.evaIdl ?? (opts.evaIdlPath ? JSON.parse(readFileSync(opts.evaIdlPath, "utf8")) : loadBundledIdl());
2194
- idl.address = this.cfg.evaProgramId.toBase58(); // honor config / devnet override
2195
- // eva program is bound to the ER connection (it executes there) + signs through the same wallet.
2196
- const provider = new A.AnchorProvider(this.er, this.wallet, { commitment: "processed" });
2197
- this.program = new A.Program(idl, provider);
2209
+ if (passedProgram) {
2210
+ // Use the caller's program as-is (only used to BUILD instructions; the SDK sends manually).
2211
+ this.program = passedProgram;
2212
+ }
2213
+ else {
2214
+ const idl = opts.evaIdl ?? (opts.evaIdlPath ? JSON.parse(readFileSync(opts.evaIdlPath, "utf8")) : loadBundledIdl());
2215
+ idl.address = this.cfg.evaProgramId.toBase58(); // honor config / devnet override
2216
+ // eva program is bound to the ER connection (it executes there) + signs through the same wallet.
2217
+ const provider = new A.AnchorProvider(this.er, this.wallet, { commitment: "processed" });
2218
+ this.program = new A.Program(idl, provider);
2219
+ }
2198
2220
  }
2199
2221
  static create(opts) { return new NorthstarEva(opts); }
2200
2222
  // ───────────────────────── ER transport (raw RPC, retries, processed) ─────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "northstar-eva-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.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",