@molpha/sdk 0.2.0-dev-20261002062009 → 0.2.0-dev-20261005191253
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 +71 -14
- package/dist/{chunk-2X22JY7Q.js → chunk-H77BBZOL.js} +6 -3
- package/dist/chunk-H77BBZOL.js.map +1 -0
- package/dist/index.d.ts +281 -42
- package/dist/index.js +484 -123
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/dist/{wallet-HfGXPpOp.d.ts → wallet--IGHoCtG.d.ts} +14 -12
- package/idl/molpha.json +25 -8
- package/package.json +1 -1
- package/dist/chunk-2X22JY7Q.js.map +0 -1
package/README.md
CHANGED
|
@@ -23,10 +23,10 @@ At a high level:
|
|
|
23
23
|
Consumer
|
|
24
24
|
└─ subscribes (USDC) on Solana
|
|
25
25
|
└─ derives sourceId = keccak256(canonical apiConfig)
|
|
26
|
-
└─ signs a RequestAuth bound to (programId, gateway, sourceId, signaturesRequired,
|
|
26
|
+
└─ signs a RequestAuth bound to (programId, gateway, sourceId, signaturesRequired, authTimestamp)
|
|
27
27
|
|
|
28
28
|
Gateway
|
|
29
|
-
└─
|
|
29
|
+
└─ assigns the round's timestamp (unix ms) from its own clock and coordinates a signing round
|
|
30
30
|
|
|
31
31
|
Verifier nodes
|
|
32
32
|
└─ fetch/recompute the API result independently
|
|
@@ -46,7 +46,7 @@ Every signed attestation commits to the same message across chains:
|
|
|
46
46
|
```text
|
|
47
47
|
message = keccak256(
|
|
48
48
|
keccak256("MOLPHA_MESSAGE_V1") || value || sourceId || u32be(registryVersion) ||
|
|
49
|
-
u8(signaturesRequired) || u64be(
|
|
49
|
+
u8(signaturesRequired) || u64be(timestamp) || signersBitmap
|
|
50
50
|
)
|
|
51
51
|
```
|
|
52
52
|
|
|
@@ -64,7 +64,7 @@ Runtime dependencies include `@solana/kit`, `@anchor-lang/core`, and `@noble/*`.
|
|
|
64
64
|
|
|
65
65
|
| Import | Use |
|
|
66
66
|
|---|---|
|
|
67
|
-
| `@molpha/sdk` | Facade (`MolphaSDK`), `MolphaGateway`, `MolphaSolanaClient`, core hashing (`deriveSourceId`, `attestationMessageHash`, `hashRequestAuth`), EVM/Starknet helpers. Browser-safe; no `fs` in the main entry. |
|
|
67
|
+
| `@molpha/sdk` | Facade (`MolphaSDK`), `MolphaGateway`, `MolphaSolanaClient`, core hashing (`deriveSourceId`, `attestationMessageHash`, `hashRequestAuth`, `timestampSeconds`), EVM/Starknet helpers. Browser-safe; no `fs` in the main entry. |
|
|
68
68
|
| `@molpha/sdk/utils` | `walletFromKeypairFile`, `loadKeypair` — load a Solana CLI keypair as an Anchor `Wallet`. Node.js only. |
|
|
69
69
|
|
|
70
70
|
The package is ESM with `"sideEffects": false`, so gateway-only or read-only apps can tree-shake unused paths.
|
|
@@ -149,11 +149,13 @@ Gateway request authorization binds the gateway's on-chain account, so the clien
|
|
|
149
149
|
|
|
150
150
|
```text
|
|
151
151
|
requestAuthHash = keccak256(
|
|
152
|
-
"MOLPHA_REQAUTH_V1" || programId || gatewayPda || sourceId || u8(signaturesRequired) || u64le(
|
|
152
|
+
"MOLPHA_REQAUTH_V1" || programId || gatewayPda || sourceId || u8(signaturesRequired) || u64le(authTimestamp)
|
|
153
153
|
)
|
|
154
154
|
gatewayPda = PDA(["molpha_gateway", gatewayAuthority], programId)
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
`authTimestamp` is the caller's unix **seconds** at signing: a freshness stamp for the authorization only (the gateway rejects stamps outside its `request_auth.window_seconds`, 60 s by default). It is read from the SDK clock for every attempt, so a retry after a 409 signs a fresh one. It has nothing to do with the round's `timestamp`.
|
|
158
|
+
|
|
157
159
|
Pass `gatewayAuthority` (the gateway's base58 signing pubkey) per endpoint to pin it. When omitted, the SDK calls `GET {url}/v1/info` once per endpoint and reads:
|
|
158
160
|
|
|
159
161
|
```json
|
|
@@ -162,6 +164,35 @@ Pass `gatewayAuthority` (the gateway's base58 signing pubkey) per endpoint to pi
|
|
|
162
164
|
|
|
163
165
|
A `programId` that differs from the client's is rejected. Because the hash differs per gateway, the auth signature is recomputed for every endpoint actually tried during failover — with a browser wallet that means one signing prompt per endpoint tried. `/v1/info` is never contacted when no signer is configured (dev zero-signature path).
|
|
164
166
|
|
|
167
|
+
### Round timestamp
|
|
168
|
+
|
|
169
|
+
The request body carries `authSig` and `authTimestamp` but no round timestamp. The gateway assigns the
|
|
170
|
+
round's `timestamp` from its own clock, in unix **milliseconds**, on a tick grid
|
|
171
|
+
(`floor(now / tickMs) * tickMs`, one second by default), and the result carries it in
|
|
172
|
+
`payload.timestamp`. Committee selection reads only the timestamp's one-second window, so
|
|
173
|
+
nobody can pick a committee by picking a time.
|
|
174
|
+
|
|
175
|
+
- The message the nodes sign is `keccak256(MOLPHA_MESSAGE_V1 || value || sourceId || u32be(registryVersion) || u8(quorum) || u64be(timestamp) || signersBitmap)`.
|
|
176
|
+
- Chain clocks, epochs and `maxAge`/staleness are in **seconds**: compare with
|
|
177
|
+
`timestampSeconds(payload.timestamp)` (floored `ts / 1000`). `timestampAgeSeconds(ts, nowSeconds)` saturates at 0.
|
|
178
|
+
- A round that was already reserved for this consumer, or dispatched to the nodes, cannot run again in the same tick (HTTP 409), so a retry waits for the next one. `tickMs` defaults to the gateway's advertised `tickMs` (read once, on the first retry, from `GET /v1/info`), else 1000.
|
|
179
|
+
|
|
180
|
+
### Retries and timeouts
|
|
181
|
+
|
|
182
|
+
`requestSignedData` makes up to `maxRetries` attempts (default 6) and chooses the wait before each by why the last one failed (`retryDelayMs`). Every wait reaches at least the next tick, then adds jitter so clients that failed together do not retry together:
|
|
183
|
+
|
|
184
|
+
| Last attempt | Wait before the next |
|
|
185
|
+
| --- | --- |
|
|
186
|
+
| 409 (this consumer already has a round for the source in this tick) | next tick, plus up to half a tick |
|
|
187
|
+
| 503 or 429 (gateway at capacity, or nodes unavailable) | the later of the next tick and the gateway's `Retry-After`, plus up to a tick |
|
|
188
|
+
| timeout, network error, other 5xx | capped exponential backoff (250 ms up to 5 s), half of it randomized |
|
|
189
|
+
| 400, 401, 402, 403 | none: terminal. 403 means the subscription is inactive or its round quota for the term is spent |
|
|
190
|
+
|
|
191
|
+
A 400 saying the `registryVersion` is not the current one (a cached context, or a registry roll between your read and the request) is the exception: the SDK reads the registry afresh and retries once, without spending an attempt.
|
|
192
|
+
|
|
193
|
+
`timeoutMs` defaults to 35 s, above the gateway's own wait for a round (`roundTimeoutSeconds` in `/v1/info`, 30 s by default). A shorter timeout abandons a round the gateway is still running, and the retry then starts another. A source that cannot be fetched is reported as soon as enough nodes have failed (usually well under a second), not after the wait.
|
|
194
|
+
- Private API secrets are encrypted for every node of the registry (the committee is unknown until the gateway stamps the round); the gateway forwards only the selected nodes' envelopes. `verifyNodeKeys` therefore authenticates all of them.
|
|
195
|
+
|
|
165
196
|
## Wallet
|
|
166
197
|
|
|
167
198
|
`wallet` is a single `MolphaWallet` used across both protocol surfaces:
|
|
@@ -169,7 +200,7 @@ A `programId` that differs from the client's is rejected. Because the hash diffe
|
|
|
169
200
|
| Layer | What it signs |
|
|
170
201
|
|---|---|
|
|
171
202
|
| Solana client | Transactions such as `subscribe`, `extendSubscription`, `submitAttestation` |
|
|
172
|
-
| Gateway client | `hashRequestAuth({ programId, gateway, sourceId, signaturesRequired,
|
|
203
|
+
| Gateway client | `hashRequestAuth({ programId, gateway, sourceId, signaturesRequired, authTimestamp })` for authenticated gateway requests |
|
|
173
204
|
|
|
174
205
|
Gateway auth is resolved automatically when you use `MolphaSDK`:
|
|
175
206
|
|
|
@@ -182,7 +213,8 @@ Gateway auth is resolved automatically when you use `MolphaSDK`:
|
|
|
182
213
|
explicit `signer`. Standalone `new MolphaGateway(...)` omits auth unless you pass
|
|
183
214
|
a `defaultSigner` (third constructor arg) or per-call `signer`.
|
|
184
215
|
|
|
185
|
-
The all-zero `authSig` path is for development only. Production jobs should authenticate gateway requests.
|
|
216
|
+
The all-zero `authSig` path is for development only: a gateway rejects it with 401. Production jobs should authenticate gateway requests.
|
|
217
|
+
|
|
186
218
|
|
|
187
219
|
### Node.js utility
|
|
188
220
|
|
|
@@ -276,7 +308,7 @@ const result = await sdk.gateway.requestSignedData({
|
|
|
276
308
|
|
|
277
309
|
The gateway round uses the current on-chain registry version. Selected verifier nodes independently fetch/recompute the result and sign only if the observed value matches the canonical result.
|
|
278
310
|
|
|
279
|
-
The returned `Attestation` matches the cross-VM struct (`payload` + `signature`), plus gateway-only `value` (human-readable) and `fresh`. `payload` carries `sourceId`, the signed 32-byte `value`, `
|
|
311
|
+
The returned `Attestation` matches the cross-VM struct (`payload` + `signature`), plus gateway-only `value` (human-readable) and `fresh`. `payload` carries `sourceId`, the signed 32-byte `value`, `timestamp`, `registryVersion`, and `signaturesRequired`; `signature` carries the aggregate Schnorr material and `signersBitmap`. `signaturesRequired` must be at least the protocol's `min_signers` (currently 3) or the chain rejects the submit.
|
|
280
312
|
|
|
281
313
|
A gateway response is a coordination result, not proof of settlement or of on-chain verification. Consumers still decide freshness, source, quorum and replay policy.
|
|
282
314
|
|
|
@@ -294,6 +326,10 @@ If the signed 32-byte value is the keccak digest of a longer preimage, pass `{ r
|
|
|
294
326
|
const { signature, feed } = await sdk.solana.submitAttestation(result, { rawValue });
|
|
295
327
|
```
|
|
296
328
|
|
|
329
|
+
**Compute budget and fees.** The transaction requests `estimateSubmitComputeUnits(signers)` compute units (about `43k + 9.2k` per signer, plus 15% and 10k of margin: roughly 140k at 8 signers), not the 1.4M maximum the old default asked for, which mattered once a priority fee is priced per requested unit. Pass `{ computeUnitLimit }` to override it. No priority fee is attached unless you ask: `{ priorityFeeMicroLamports: 2_000 }` sets a price in micro-lamports per unit, and `{ priorityFeeMicroLamports: "auto" }` uses the 75th percentile of the fees recently paid by writers of that feed (capped at 1 lamport per unit; an unreadable fee market means no fee). Use one of them when submits are dropped under load.
|
|
330
|
+
|
|
331
|
+
**Many feeds.** The client caches what feeds sharing a registry version have in common: the registry read (30 s), each signer `Node` key (never changes) and the coalition key of each signer set, and concurrent submits share one read. Submitting a fleet of feeds therefore costs one registry read and one `Node` read per distinct signer, not per submit. A stale or duplicate round is refused by the program in about 17-20k compute units, before it verifies the signature.
|
|
332
|
+
|
|
297
333
|
Then read the feed this wallet wrote for that source and quorum:
|
|
298
334
|
|
|
299
335
|
```ts
|
|
@@ -302,7 +338,7 @@ const feedState = await sdk.solana.readFeed(result.payload.sourceId, signaturesR
|
|
|
302
338
|
|
|
303
339
|
`FeedAccount.value` is the 32 signed bytes (`valueKind.value`) or their keccak preimage hash (`valueKind.hash`); `submitter` is the wallet that created the feed.
|
|
304
340
|
|
|
305
|
-
The subscription read
|
|
341
|
+
The subscription read does not expose usage: the program stores no `used_rounds` / `prepaid_usdc` / `price`, and round quota is counted by the gateway's off-chain outbox. `SubscriptionInfo` carries only `owner`, `planType`, `validUntil`, `maxRounds`, `delegateCount`, `maxDelegates`, `maxSigners`.
|
|
306
342
|
|
|
307
343
|
### One-call request + submit
|
|
308
344
|
|
|
@@ -320,6 +356,27 @@ const result = await sdk.gateway.requestSignedData({ apiConfig, signaturesRequir
|
|
|
320
356
|
const { signature, feed } = await sdk.solana.submitAttestation(result);
|
|
321
357
|
```
|
|
322
358
|
|
|
359
|
+
If the round succeeds but submitting fails, `requestAndSubmit` throws a `SubmitFailedError` that carries the signed attestation (`error.result`). The round already consumed quota and the attestation is valid, so submit `error.result` again instead of requesting a new round.
|
|
360
|
+
|
|
361
|
+
### Many feeds
|
|
362
|
+
|
|
363
|
+
For a large set of feeds use `requestMany` (also exported from the package root) instead of looping over `requestAndSubmit`:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
import { requestMany } from "@molpha/sdk";
|
|
367
|
+
|
|
368
|
+
const results = await requestMany(sdk, feeds, {
|
|
369
|
+
spreadMs: 1000, // spread starts by source hash so feeds due together do not arrive together
|
|
370
|
+
request: { maxRetries: 6 },
|
|
371
|
+
});
|
|
372
|
+
for (const r of results) {
|
|
373
|
+
if (!r.ok) console.error(r.label, r.error);
|
|
374
|
+
else if (r.submitError) console.warn(r.label, "round ok, submit failed", r.submitError);
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
It reads the registry inputs once for the whole batch; bounds concurrency, starting from half the gateway's advertised `maxInflightRounds` (at most 64, else 32) and adapting (halving on a busy answer, growing back while requests succeed); runs Solana submits on their own smaller limiter (`submitConcurrency`, default 8); never discards the signed attestation of a round whose submit failed; and returns one result per feed in input order, so a failing feed does not stop the others. Pass `submit: false` to collect attestations only. Throughput is limited by the submit path (one transaction per attestation) long before it is limited by the gateway.
|
|
379
|
+
|
|
323
380
|
### Fast requests with a cached context
|
|
324
381
|
|
|
325
382
|
By default every `requestSignedData` call reads the on-chain registry up front
|
|
@@ -540,7 +597,7 @@ attestation:
|
|
|
540
597
|
sourceId: `0x${string}`, // bytes32
|
|
541
598
|
registryVersion: number, // uint32
|
|
542
599
|
signaturesRequired: number, // uint8
|
|
543
|
-
|
|
600
|
+
timestamp: bigint, // uint64
|
|
544
601
|
},
|
|
545
602
|
signature: {
|
|
546
603
|
signature: `0x${string}`, // bytes32 (Attestation.signature.s)
|
|
@@ -692,7 +749,7 @@ attestation:
|
|
|
692
749
|
source_id: u256,
|
|
693
750
|
registry_version: u32,
|
|
694
751
|
signatures_required: u8,
|
|
695
|
-
|
|
752
|
+
timestamp: u64,
|
|
696
753
|
},
|
|
697
754
|
signature: {
|
|
698
755
|
signature: u256,
|
|
@@ -742,7 +799,7 @@ shared with the EVM verifier contract and exported as `VERIFY_CODES`:
|
|
|
742
799
|
| 0 | `OK` | Verified |
|
|
743
800
|
| 2 | `BAD_REGISTRY_VERSION` | `registryVersion` does not exist on this verifier |
|
|
744
801
|
| 3 | `MALFORMED` | Structurally invalid input, or dated in the future when `maxAge != 0` |
|
|
745
|
-
| 4 | `NOT_YET_ACTIVE` | `
|
|
802
|
+
| 4 | `NOT_YET_ACTIVE` | `timestamp` predates the registry version's activation |
|
|
746
803
|
| 5 | `VERSION_EXPIRED` | Registry version superseded more than the grace window earlier |
|
|
747
804
|
| 7 | `BAD_QUORUM` | Signers are not within the round's derived selection group |
|
|
748
805
|
| 8 | `BAD_AGGREGATE` | The signers' aggregate key is the point at infinity |
|
|
@@ -770,7 +827,7 @@ A Molpha attestation is valid only if the verifier can confirm:
|
|
|
770
827
|
- the update targets the expected `sourceId`;
|
|
771
828
|
- the result was signed against a specific `registryVersion` (an immutable node-set snapshot);
|
|
772
829
|
- the quorum satisfies `signaturesRequired`;
|
|
773
|
-
- the signer bitmap is a subset of the deterministic selection for `(sourceId, registryVersion,
|
|
830
|
+
- the signer bitmap is a subset of the deterministic selection for `(sourceId, registryVersion, timestamp)`;
|
|
774
831
|
- the aggregate Schnorr signature over `attestationMessageHash(...)` is valid;
|
|
775
832
|
- the timestamp is within the accepted freshness bounds;
|
|
776
833
|
- on Solana, the signer `Node` accounts passed as remaining accounts are exactly `registry.nodes[bit]` for every set bit, and the supplied coalition key matches the sum of their keys.
|
|
@@ -834,7 +891,7 @@ Current scope:
|
|
|
834
891
|
|
|
835
892
|
- Solana subscription and extend flow;
|
|
836
893
|
- deterministic source id and attestation message hashing;
|
|
837
|
-
- gateway signed-data requests (failover, retries, per-gateway request auth, context cache);
|
|
894
|
+
- gateway signed-data requests (failover, tick-aware retries, per-gateway request auth, context cache);
|
|
838
895
|
- Solana attestation submission and feed/registry reads;
|
|
839
896
|
- private API encryption helpers (pre-production);
|
|
840
897
|
- caller-funded x402 payments for paywalled API sources (Base USDC, pre-production);
|
|
@@ -34,10 +34,13 @@ function getAssociatedTokenAddressSync(mint, owner, tokenProgram = TOKEN_PROGRAM
|
|
|
34
34
|
function setComputeUnitLimit(units) {
|
|
35
35
|
return web3.ComputeBudgetProgram.setComputeUnitLimit({ units });
|
|
36
36
|
}
|
|
37
|
+
function setComputeUnitPrice(microLamports) {
|
|
38
|
+
return web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports });
|
|
39
|
+
}
|
|
37
40
|
function keypairFromSecretKey(secretKey) {
|
|
38
41
|
return web3.Keypair.fromSecretKey(secretKey);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
export { SYSTEM_PROGRAM_ADDRESS, TOKEN_PROGRAM_ADDRESS, addressBytes, addressFromBytes, findProgramAddressSync, getAssociatedTokenAddressSync, keypairFromSecretKey, setComputeUnitLimit, toPublicKey, toSolanaAddress };
|
|
42
|
-
//# sourceMappingURL=chunk-
|
|
43
|
-
//# sourceMappingURL=chunk-
|
|
44
|
+
export { SYSTEM_PROGRAM_ADDRESS, TOKEN_PROGRAM_ADDRESS, addressBytes, addressFromBytes, findProgramAddressSync, getAssociatedTokenAddressSync, keypairFromSecretKey, setComputeUnitLimit, setComputeUnitPrice, toPublicKey, toSolanaAddress };
|
|
45
|
+
//# sourceMappingURL=chunk-H77BBZOL.js.map
|
|
46
|
+
//# sourceMappingURL=chunk-H77BBZOL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/solana/kit.ts"],"names":[],"mappings":";;;;AAaO,IAAM,qBAAA,GAAwB,QAAQ,6CAA6C;AACnF,IAAM,gCAAA,GAAmC,OAAA;AAAA,EAC9C;AACF,CAAA;AACO,IAAM,sBAAA,GAAyB,QAAQ,kCAAkC;AAEhF,IAAM,iBAAiB,iBAAA,EAAkB;AACzC,IAAM,iBAAiB,iBAAA,EAAkB;AAElC,SAAS,gBAAgB,KAAA,EAA+B;AAC7D,EAAA,OAAO,QAAQ,OAAO,KAAA,KAAU,WAAW,KAAA,GAAQ,KAAA,CAAM,UAAU,CAAA;AACrE;AAEO,SAAS,YAAY,KAAA,EAA2D;AACrF,EAAA,OAAO,iBAAiB,IAAA,CAAK,SAAA,GAAY,QAAQ,IAAI,IAAA,CAAK,UAAU,KAAK,CAAA;AAC3E;AAEO,SAAS,aAAa,KAAA,EAAkC;AAC7D,EAAA,OAAO,WAAW,IAAA,CAAK,cAAA,CAAe,OAAO,eAAA,CAAgB,KAAK,CAAC,CAAC,CAAA;AACtE;AAGO,SAAS,iBAAiB,KAAA,EAA4B;AAC3D,EAAA,OAAO,cAAA,CAAe,OAAO,KAAK,CAAA;AACpC;AAEO,SAAS,sBAAA,CACd,OACA,cAAA,EACS;AACT,EAAA,MAAM,CAAC,GAAG,CAAA,GAAI,IAAA,CAAK,UAAU,sBAAA,CAAuB,KAAA,EAAO,WAAA,CAAY,cAAc,CAAC,CAAA;AACtF,EAAA,OAAO,gBAAgB,GAAG,CAAA;AAC5B;AAUO,SAAS,6BAAA,CACd,IAAA,EACA,KAAA,EACA,YAAA,GAA8B,qBAAA,EACrB;AACT,EAAA,OAAO,sBAAA;AAAA,IACL,CAAC,aAAa,KAAK,CAAA,EAAG,aAAa,YAAY,CAAA,EAAG,YAAA,CAAa,IAAI,CAAC,CAAA;AAAA,IACpE;AAAA,GACF;AACF;AAEO,SAAS,oBAAoB,KAAA,EAAkC;AACpE,EAAA,OAAO,IAAA,CAAK,oBAAA,CAAqB,mBAAA,CAAoB,EAAE,OAAO,CAAA;AAChE;AAEO,SAAS,oBAAoB,aAAA,EAA0C;AAC5E,EAAA,OAAO,IAAA,CAAK,oBAAA,CAAqB,mBAAA,CAAoB,EAAE,eAAe,CAAA;AACxE;AAEO,SAAS,qBAAqB,SAAA,EAAsC;AACzE,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,SAAS,CAAA;AAC7C","file":"chunk-H77BBZOL.js","sourcesContent":["import { web3 } from \"@anchor-lang/core\";\nimport { address, getAddressDecoder, getAddressEncoder, type Address } from \"@solana/kit\";\n\nexport type SolanaAddress = Address | string | InstanceType<typeof web3.PublicKey>;\nexport type SolanaConnection = InstanceType<typeof web3.Connection>;\nexport type SolanaKeypair = InstanceType<typeof web3.Keypair>;\nexport type SolanaInstruction = InstanceType<typeof web3.TransactionInstruction>;\nexport type SolanaAccountMeta = {\n pubkey: InstanceType<typeof web3.PublicKey>;\n isSigner: boolean;\n isWritable: boolean;\n};\n\nexport const TOKEN_PROGRAM_ADDRESS = address(\"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\");\nexport const ASSOCIATED_TOKEN_PROGRAM_ADDRESS = address(\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\",\n);\nexport const SYSTEM_PROGRAM_ADDRESS = address(\"11111111111111111111111111111111\");\n\nconst addressEncoder = getAddressEncoder();\nconst addressDecoder = getAddressDecoder();\n\nexport function toSolanaAddress(value: SolanaAddress): Address {\n return address(typeof value === \"string\" ? value : value.toBase58());\n}\n\nexport function toPublicKey(value: SolanaAddress): InstanceType<typeof web3.PublicKey> {\n return value instanceof web3.PublicKey ? value : new web3.PublicKey(value);\n}\n\nexport function addressBytes(value: SolanaAddress): Uint8Array {\n return Uint8Array.from(addressEncoder.encode(toSolanaAddress(value)));\n}\n\n/** Base58 `Address` from 32 raw bytes (e.g. a `Registry.nodes[i]` entry). */\nexport function addressFromBytes(bytes: Uint8Array): Address {\n return addressDecoder.decode(bytes);\n}\n\nexport function findProgramAddressSync(\n seeds: Uint8Array[],\n programAddress: SolanaAddress,\n): Address {\n const [pda] = web3.PublicKey.findProgramAddressSync(seeds, toPublicKey(programAddress));\n return toSolanaAddress(pda);\n}\n\nexport function findProgramPublicKeySync(\n seeds: Uint8Array[],\n programAddress: SolanaAddress,\n): InstanceType<typeof web3.PublicKey> {\n const [pda] = web3.PublicKey.findProgramAddressSync(seeds, toPublicKey(programAddress));\n return pda;\n}\n\nexport function getAssociatedTokenAddressSync(\n mint: SolanaAddress,\n owner: SolanaAddress,\n tokenProgram: SolanaAddress = TOKEN_PROGRAM_ADDRESS,\n): Address {\n return findProgramAddressSync(\n [addressBytes(owner), addressBytes(tokenProgram), addressBytes(mint)],\n ASSOCIATED_TOKEN_PROGRAM_ADDRESS,\n );\n}\n\nexport function setComputeUnitLimit(units: number): SolanaInstruction {\n return web3.ComputeBudgetProgram.setComputeUnitLimit({ units });\n}\n\nexport function setComputeUnitPrice(microLamports: number): SolanaInstruction {\n return web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports });\n}\n\nexport function keypairFromSecretKey(secretKey: Uint8Array): SolanaKeypair {\n return web3.Keypair.fromSecretKey(secretKey);\n}\n\nexport function generateKeypair(): SolanaKeypair {\n return web3.Keypair.generate();\n}\n"]}
|