@x1id/resolve 0.10.0 → 0.12.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 +74 -5
- package/dist/adminConfig.d.ts +63 -0
- package/dist/adminConfig.js +113 -0
- package/dist/adminMarket.d.ts +67 -0
- package/dist/adminMarket.js +134 -0
- package/dist/attestation.d.ts +103 -1
- package/dist/attestation.js +124 -0
- package/dist/gateClient.d.ts +98 -0
- package/dist/gateClient.js +118 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +138 -2
- package/dist/lease.d.ts +92 -0
- package/dist/lease.js +117 -0
- package/dist/namespaceOverride.d.ts +123 -0
- package/dist/namespaceOverride.js +204 -0
- package/dist/register.d.ts +30 -0
- package/dist/register.js +37 -0
- package/dist/scoped.d.ts +84 -0
- package/dist/scoped.js +126 -0
- package/dist/types.d.ts +23 -4
- package/dist/types.js +2 -1
- package/dist/universal.d.ts +58 -0
- package/dist/universal.js +67 -0
- package/dist/universalDetect.d.ts +44 -0
- package/dist/universalDetect.js +105 -0
- package/dist/universalEns.d.ts +44 -0
- package/dist/universalEns.js +138 -0
- package/dist/universalNative.d.ts +13 -0
- package/dist/universalNative.js +43 -0
- package/dist/universalSns.d.ts +95 -0
- package/dist/universalSns.js +223 -0
- package/dist/universalTypes.d.ts +117 -0
- package/dist/universalTypes.js +24 -0
- package/dist/voucher.d.ts +53 -0
- package/dist/voucher.js +56 -0
- package/dist/wasm.d.ts +17 -0
- package/dist/wasm.js +38 -0
- package/package.json +1 -1
- package/wasm/x1_resolve_wasm.wasm +0 -0
package/README.md
CHANGED
|
@@ -274,6 +274,65 @@ for (const a of liveAttestations(atts)) {
|
|
|
274
274
|
integrator joining a live attestation to its paired text record reads the same
|
|
275
275
|
mapping the program, resolver and app badge use.
|
|
276
276
|
|
|
277
|
+
## Attestation gating (allowlists)
|
|
278
|
+
|
|
279
|
+
Gate your app, Discord, mint, or airdrop by whether an `@handle` holds a
|
|
280
|
+
**verified on-chain attestation** — any signal, or a specific platform like
|
|
281
|
+
"verified GitHub." You reuse X1ID's blue-tick oracle as your allowlist instead of
|
|
282
|
+
running your own verification, and the staleness rule (an attestation only counts
|
|
283
|
+
for the *current* owner) is enforced for you.
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import {
|
|
287
|
+
handlePassesGate, attestationsPassGate, GateKind, type Gate,
|
|
288
|
+
} from "@x1id/resolve";
|
|
289
|
+
|
|
290
|
+
const anyVerified: Gate = "any-verified"; // any blue-tick
|
|
291
|
+
const githubOnly: Gate = { kind: GateKind.github }; // one platform
|
|
292
|
+
const xOrGithub: Gate = { anyOf: [GateKind.x, GateKind.github] };
|
|
293
|
+
|
|
294
|
+
// One-call fetch + check (handleAccount/registeredAt/recordsClearedAt come from
|
|
295
|
+
// the handle you resolved):
|
|
296
|
+
const { passed, attestations } = await handlePassesGate(
|
|
297
|
+
rpc, programId, handleAccount, registeredAt, recordsClearedAt, githubOnly,
|
|
298
|
+
);
|
|
299
|
+
if (!passed) throw new Error("Not allowed — verify your GitHub on X1ID first.");
|
|
300
|
+
|
|
301
|
+
// Already have the attestations? The check is pure + synchronous:
|
|
302
|
+
attestationsPassGate(attestations, xOrGithub); // boolean
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
`GateKind`: `dns`, `social`, `x`, `discord`, `github`, `telegram`.
|
|
306
|
+
|
|
307
|
+
**On-chain gate (CPI):** another program can verify the same thing inside its own
|
|
308
|
+
transaction via the program-native `assert_attestation_gate` instruction — it
|
|
309
|
+
returns Ok when the gate passes and errors otherwise, so a CPI that errors fails
|
|
310
|
+
the caller's tx. Full call contract (discriminator, accounts, kind codes) is in
|
|
311
|
+
the program's `docs/attestation-gating.md`.
|
|
312
|
+
|
|
313
|
+
**Hosted gate + drop-in middleware (X1ID Gate):** if you'd rather not run your own
|
|
314
|
+
attestation reads, `requireGate()` calls the hosted decision service
|
|
315
|
+
(`POST /v1/gate/check`, api.x1id.io) and returns pass/fail. A tiny, framework-
|
|
316
|
+
agnostic **server** guard (keep your API key server-side):
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
import { requireGate, GateKind } from "@x1id/resolve";
|
|
320
|
+
|
|
321
|
+
const gate = requireGate({ apiKey: process.env.X1ID_API_KEY! }, { kind: GateKind.github });
|
|
322
|
+
|
|
323
|
+
export async function POST(req: Request) { // any server runtime with fetch
|
|
324
|
+
const { handle } = await req.json();
|
|
325
|
+
const { allowed } = await gate({ handle }); // or gate({ wallet })
|
|
326
|
+
if (!allowed) return Response.json({ error: "verified GitHub required" }, { status: 403 });
|
|
327
|
+
// …proceed
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Fail-closed by default (re-throws if the decision can't be obtained; pass
|
|
332
|
+
`{ onError: "allow" }` to fail-open). `checkGate()` is the lower-level client for
|
|
333
|
+
the full decision; pass a stored policy's `gp_…` id as the policy to reuse a named
|
|
334
|
+
policy. The hosted check is keyed/metered — see `services/dev-api`'s README.
|
|
335
|
+
|
|
277
336
|
## What works today
|
|
278
337
|
|
|
279
338
|
| | Status |
|
|
@@ -284,17 +343,19 @@ mapping the program, resolver and app badge use.
|
|
|
284
343
|
| Per-chain ETH/BTC records | ✅ read with the staleness rule enforced structurally |
|
|
285
344
|
| Control proofs (prove you control a `@handle`) | ✅ `createControlChallenge` / `verifyControlProof` — spec: `docs/control-proof.md` |
|
|
286
345
|
| Records read (per-chain, staleness-enforced) | ✅ `fetchRecords` |
|
|
287
|
-
|
|
|
288
|
-
| Registration
|
|
346
|
+
| Attestation gating (verified-only allowlists) | ✅ off-chain (`handlePassesGate`) + on-chain CPI (`assert_attestation_gate`) |
|
|
347
|
+
| Registration · lease-to-own · FORTI · commit-reveal · gift-voucher claim (write) | ✅ instruction builders; you sign & relay |
|
|
348
|
+
| Subnames · gifts · integrator rev-share · name-lock · record-delegate · text records · attestations (write) | ✅ instruction builders; you sign & relay |
|
|
349
|
+
| `transfer` / `set_primary` (write) | 🔜 roadmap — use [x1id.io](https://x1id.io) |
|
|
289
350
|
|
|
290
351
|
The `@handle` registry program id is configurable (`handleProgramId`) and
|
|
291
352
|
defaults to the canonical X1 deployment
|
|
292
353
|
(`8JgnNWi24bq9uzfnT9XmkWxvaWMVgoEs9bu8QsHhLe1P`).
|
|
293
354
|
|
|
294
|
-
## Beyond resolve: the registry write surface
|
|
355
|
+
## Beyond resolve: the registry write surface
|
|
295
356
|
|
|
296
357
|
`resolve()` / `reverse()` / `fetchRecords()` are read-only and need only an RPC.
|
|
297
|
-
|
|
358
|
+
The package also ships **instruction builders** for the on-chain registry. Each
|
|
298
359
|
returns an unsigned `BuiltInstruction` (`{ programId, keys, data }`) — you
|
|
299
360
|
assemble it into a transaction, **sign, and relay** yourself; the SDK never
|
|
300
361
|
holds keys. Every discriminator and account order matches the deployed program.
|
|
@@ -328,7 +389,10 @@ const ix = buildCreateSubnameIx({
|
|
|
328
389
|
```
|
|
329
390
|
|
|
330
391
|
**Register a handle** (pays whatever the on-chain ramp charges as of the
|
|
331
|
-
landing slot — there is no client-supplied price)
|
|
392
|
+
landing slot — there is no client-supplied price). `buildRegisterIx` builds the
|
|
393
|
+
plain **name-only** `register`; the default **NFT-included** purchase
|
|
394
|
+
(`register_tokenized`, which mints the capability pNFT in the same transaction)
|
|
395
|
+
is driven by app.x1id.io today and has no standalone SDK builder yet:
|
|
332
396
|
|
|
333
397
|
```ts
|
|
334
398
|
import { buildRegisterIx, fetchConfigTreasury, HandleType } from "@x1id/resolve";
|
|
@@ -369,6 +433,11 @@ Also shipped, same build → sign → relay shape:
|
|
|
369
433
|
| Record-write delegation | `buildSetRecordDelegateIx`, `buildRevokeRecordDelegateIx` |
|
|
370
434
|
| Typed text records (website / avatar / socials) | `buildCreateTextRecordIx`, `buildUpdateTextRecordIx`, `buildCloseTextRecordIx` |
|
|
371
435
|
| Register a handle | `buildRegisterIx` (+ `fetchConfigTreasury`) |
|
|
436
|
+
| Lease-to-own | `buildRegisterLeasedIx`, `buildRenewLeaseIx`, `buildReclaimExpiredLeaseIx` |
|
|
437
|
+
| Register at a FORTI discount | `buildRegisterWithFortiIx` |
|
|
438
|
+
| Commit-reveal registration (front-run-safe) | `buildCommitIx`, `buildRegisterRevealedIx`, `buildCancelCommitmentIx` |
|
|
439
|
+
| Claim a gifted name (prepaid voucher) | `buildClaimVoucherIx`, `buildClaimVoucherTokenizedIx` |
|
|
440
|
+
| Attestation gating | `handlePassesGate`, `attestationsPassGate`, `GateKind` — see [Attestation gating](#attestation-gating-allowlists) |
|
|
372
441
|
| Verify a non-SVM address record | `buildCreateRecordIx`, `buildVerifyRecordEthIx`, `buildVerifyRecordSvmIx`, `buildVerifyRecordBtcIx` (+ `buildRecordChallenge`, `splitEthSignature`, `splitBtcSignature`) — see [Verifying a non-SVM address record](#verifying-a-non-svm-address-record) |
|
|
373
442
|
| Domain / social / per-platform attestations | `buildCreateAttestationIx` (kinds 0–5), `buildCloseAttestationIx` (+ `fetchAttestations`, `isHandleVerified`, `platformSlug`, `textRecordKeyFor`) — see [Per-platform verification](#per-platform-verification-verified-by-platform) |
|
|
374
443
|
| Agent records (identity, manifest, x402 hints) | `validateManifest`, `agentVerificationLevel`, `x402AcceptsFromManifest`, `agentTextRecords` — see [Agent records](#agent-records) below |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin-only `Config` setters — `set_tiers` / `set_nft_tiers` (#8398) and (as
|
|
3
|
+
* the on-chain admin batch lands) the rest of the AdminOnly config instructions.
|
|
4
|
+
*
|
|
5
|
+
* Hand-rolled like the rest of this package — no Anchor client, no
|
|
6
|
+
* `@solana/web3.js`. All of these share the `AdminOnly` account shape:
|
|
7
|
+
* admin (signer, NOT writable — these setters init nothing, so no rent)
|
|
8
|
+
* config (the ["config"] PDA, writable)
|
|
9
|
+
* and must be signed by `Config.admin`. PDAs are not derived here — derive
|
|
10
|
+
* `["config"]` with your runtime's `findProgramAddress`.
|
|
11
|
+
*/
|
|
12
|
+
import type { AddressLike, BuiltInstruction } from "./delegate.js";
|
|
13
|
+
/** Anchor instruction discriminator: `sha256("global:set_tiers")[0..8]`. */
|
|
14
|
+
export declare const SET_TIERS_DISCRIMINATOR: Uint8Array;
|
|
15
|
+
/** Anchor instruction discriminator: `sha256("global:set_nft_tiers")[0..8]`. */
|
|
16
|
+
export declare const SET_NFT_TIERS_DISCRIMINATOR: Uint8Array;
|
|
17
|
+
/** The number of length-tiers in `Config.tier_lamports` / `nft_tier_lamports`.
|
|
18
|
+
* Tier index = `clamp(nameLen, 1, 10) - 1`, so tier[0] = 1-char … tier[9] = 10+. */
|
|
19
|
+
export declare const TIER_COUNT = 10;
|
|
20
|
+
export interface SetTiersParams {
|
|
21
|
+
readonly programId: AddressLike;
|
|
22
|
+
/** `Config.admin` — the ONLY key accepted (has_one = admin). Signs; not mut. */
|
|
23
|
+
readonly admin: AddressLike;
|
|
24
|
+
/** The `["config"]` PDA (writable). */
|
|
25
|
+
readonly config: AddressLike;
|
|
26
|
+
/** Exactly 10 per-length-tier base prices in lamports (tier[0]=1-char …
|
|
27
|
+
* tier[9]=10+). Accepts number or bigint; each must be a non-negative
|
|
28
|
+
* integer that fits u64. */
|
|
29
|
+
readonly tierLamports: ReadonlyArray<number | bigint>;
|
|
30
|
+
}
|
|
31
|
+
/** Build `set_tiers` — replace the 10 length-tier base registration prices. */
|
|
32
|
+
export declare function buildSetTiersIx(p: SetTiersParams): BuiltInstruction;
|
|
33
|
+
export interface SetNftTiersParams {
|
|
34
|
+
readonly programId: AddressLike;
|
|
35
|
+
readonly admin: AddressLike;
|
|
36
|
+
readonly config: AddressLike;
|
|
37
|
+
/** Exactly 10 per-length-tier NFT mint fees in lamports. */
|
|
38
|
+
readonly nftTierLamports: ReadonlyArray<number | bigint>;
|
|
39
|
+
}
|
|
40
|
+
/** Build `set_nft_tiers` — replace the 10 length-tier `mint_handle_nft` fees. */
|
|
41
|
+
export declare function buildSetNftTiersIx(p: SetNftTiersParams): BuiltInstruction;
|
|
42
|
+
export declare const SET_LEASE_RATE_DIVISOR_DISCRIMINATOR: Uint8Array;
|
|
43
|
+
export declare const SET_LEASE_GRACE_PERIOD_DISCRIMINATOR: Uint8Array;
|
|
44
|
+
export declare const SET_RECOVERY_TIMELOCK_DISCRIMINATOR: Uint8Array;
|
|
45
|
+
export declare const SET_MIN_COMMITMENT_AGE_DISCRIMINATOR: Uint8Array;
|
|
46
|
+
export declare const SET_MAX_COMMITMENT_AGE_DISCRIMINATOR: Uint8Array;
|
|
47
|
+
/** Map an admin config action name → its discriminator (for a relay executor
|
|
48
|
+
* that dispatches on the action string). set_admin/set_attestor intentionally
|
|
49
|
+
* absent — those are owner-gated, never dispatched here. */
|
|
50
|
+
export declare const ADMIN_SCALAR_DISCRIMINATORS: Readonly<Record<string, Uint8Array>>;
|
|
51
|
+
export interface AdminScalarParams {
|
|
52
|
+
readonly programId: AddressLike;
|
|
53
|
+
readonly admin: AddressLike;
|
|
54
|
+
readonly config: AddressLike;
|
|
55
|
+
/** The discriminator for the specific setter (from ADMIN_SCALAR_DISCRIMINATORS). */
|
|
56
|
+
readonly discriminator: Uint8Array;
|
|
57
|
+
/** The integer arg (u64/i64 encoding is identical for a non-negative value). */
|
|
58
|
+
readonly value: number | bigint;
|
|
59
|
+
}
|
|
60
|
+
/** Build any one-integer-arg AdminOnly setter (lease rate divisor, lease grace,
|
|
61
|
+
* recovery timelock, min/max commitment age). disc(8) + value as little-endian
|
|
62
|
+
* u64(8). The value must be a non-negative integer that fits u64. */
|
|
63
|
+
export declare function buildAdminScalarSetterIx(p: AdminScalarParams): BuiltInstruction;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin-only `Config` setters — `set_tiers` / `set_nft_tiers` (#8398) and (as
|
|
3
|
+
* the on-chain admin batch lands) the rest of the AdminOnly config instructions.
|
|
4
|
+
*
|
|
5
|
+
* Hand-rolled like the rest of this package — no Anchor client, no
|
|
6
|
+
* `@solana/web3.js`. All of these share the `AdminOnly` account shape:
|
|
7
|
+
* admin (signer, NOT writable — these setters init nothing, so no rent)
|
|
8
|
+
* config (the ["config"] PDA, writable)
|
|
9
|
+
* and must be signed by `Config.admin`. PDAs are not derived here — derive
|
|
10
|
+
* `["config"]` with your runtime's `findProgramAddress`.
|
|
11
|
+
*/
|
|
12
|
+
import { encodeBase58, decodeBase58_32 } from "./base58.js";
|
|
13
|
+
function toBytes32(v, what) {
|
|
14
|
+
if (typeof v === "string") {
|
|
15
|
+
const b = decodeBase58_32(v);
|
|
16
|
+
if (!b)
|
|
17
|
+
throw new Error(`${what} is not a valid base58 address`);
|
|
18
|
+
return b;
|
|
19
|
+
}
|
|
20
|
+
if (v.length !== 32)
|
|
21
|
+
throw new Error(`${what} must be exactly 32 bytes`);
|
|
22
|
+
return v;
|
|
23
|
+
}
|
|
24
|
+
function toBase58(v, what) {
|
|
25
|
+
return encodeBase58(toBytes32(v, what));
|
|
26
|
+
}
|
|
27
|
+
/** Anchor instruction discriminator: `sha256("global:set_tiers")[0..8]`. */
|
|
28
|
+
export const SET_TIERS_DISCRIMINATOR = Uint8Array.from([
|
|
29
|
+
170, 131, 109, 175, 156, 214, 177, 121,
|
|
30
|
+
]);
|
|
31
|
+
/** Anchor instruction discriminator: `sha256("global:set_nft_tiers")[0..8]`. */
|
|
32
|
+
export const SET_NFT_TIERS_DISCRIMINATOR = Uint8Array.from([
|
|
33
|
+
116, 68, 126, 146, 252, 206, 87, 61,
|
|
34
|
+
]);
|
|
35
|
+
/** The number of length-tiers in `Config.tier_lamports` / `nft_tier_lamports`.
|
|
36
|
+
* Tier index = `clamp(nameLen, 1, 10) - 1`, so tier[0] = 1-char … tier[9] = 10+. */
|
|
37
|
+
export const TIER_COUNT = 10;
|
|
38
|
+
function encodeTiers(disc, tiers) {
|
|
39
|
+
if (tiers.length !== TIER_COUNT) {
|
|
40
|
+
throw new Error(`expected exactly ${TIER_COUNT} tiers, got ${tiers.length}`);
|
|
41
|
+
}
|
|
42
|
+
// Fixed-size [u64; 10] — borsh writes 10 little-endian u64s back to back, NO
|
|
43
|
+
// length prefix (unlike a Vec or a String).
|
|
44
|
+
const data = new Uint8Array(8 + TIER_COUNT * 8);
|
|
45
|
+
data.set(disc, 0);
|
|
46
|
+
const dv = new DataView(data.buffer);
|
|
47
|
+
for (let i = 0; i < TIER_COUNT; i++) {
|
|
48
|
+
const raw = tiers[i]; // length checked above
|
|
49
|
+
const v = typeof raw === "bigint" ? raw : BigInt(raw);
|
|
50
|
+
if (v < 0n || v > 0xffffffffffffffffn) {
|
|
51
|
+
throw new Error(`tier[${i}] = ${raw} is out of u64 range`);
|
|
52
|
+
}
|
|
53
|
+
dv.setBigUint64(8 + i * 8, v, true);
|
|
54
|
+
}
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
function adminOnlyKeys(admin, config) {
|
|
58
|
+
return [
|
|
59
|
+
// admin signs but is NOT writable — these setters init nothing (no rent).
|
|
60
|
+
{ pubkey: toBase58(admin, "admin"), isSigner: true, isWritable: false },
|
|
61
|
+
{ pubkey: toBase58(config, "config"), isSigner: false, isWritable: true },
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
/** Build `set_tiers` — replace the 10 length-tier base registration prices. */
|
|
65
|
+
export function buildSetTiersIx(p) {
|
|
66
|
+
return {
|
|
67
|
+
programId: toBase58(p.programId, "programId"),
|
|
68
|
+
keys: adminOnlyKeys(p.admin, p.config),
|
|
69
|
+
data: encodeTiers(SET_TIERS_DISCRIMINATOR, p.tierLamports),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Build `set_nft_tiers` — replace the 10 length-tier `mint_handle_nft` fees. */
|
|
73
|
+
export function buildSetNftTiersIx(p) {
|
|
74
|
+
return {
|
|
75
|
+
programId: toBase58(p.programId, "programId"),
|
|
76
|
+
keys: adminOnlyKeys(p.admin, p.config),
|
|
77
|
+
data: encodeTiers(SET_NFT_TIERS_DISCRIMINATOR, p.nftTierLamports),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// ===== Scalar AdminOnly setters (#8399/recovery/commitment) =====
|
|
81
|
+
// Each takes one little-endian integer arg. Same AdminOnly account shape.
|
|
82
|
+
export const SET_LEASE_RATE_DIVISOR_DISCRIMINATOR = Uint8Array.from([181, 218, 76, 213, 80, 99, 181, 52]);
|
|
83
|
+
export const SET_LEASE_GRACE_PERIOD_DISCRIMINATOR = Uint8Array.from([212, 2, 110, 20, 130, 50, 194, 186]);
|
|
84
|
+
export const SET_RECOVERY_TIMELOCK_DISCRIMINATOR = Uint8Array.from([178, 183, 148, 243, 155, 166, 79, 6]);
|
|
85
|
+
export const SET_MIN_COMMITMENT_AGE_DISCRIMINATOR = Uint8Array.from([181, 20, 114, 43, 51, 23, 47, 248]);
|
|
86
|
+
export const SET_MAX_COMMITMENT_AGE_DISCRIMINATOR = Uint8Array.from([163, 106, 196, 206, 146, 156, 79, 249]);
|
|
87
|
+
/** Map an admin config action name → its discriminator (for a relay executor
|
|
88
|
+
* that dispatches on the action string). set_admin/set_attestor intentionally
|
|
89
|
+
* absent — those are owner-gated, never dispatched here. */
|
|
90
|
+
export const ADMIN_SCALAR_DISCRIMINATORS = {
|
|
91
|
+
set_lease_rate_divisor: SET_LEASE_RATE_DIVISOR_DISCRIMINATOR,
|
|
92
|
+
set_lease_grace_period: SET_LEASE_GRACE_PERIOD_DISCRIMINATOR,
|
|
93
|
+
set_recovery_timelock: SET_RECOVERY_TIMELOCK_DISCRIMINATOR,
|
|
94
|
+
set_min_commitment_age: SET_MIN_COMMITMENT_AGE_DISCRIMINATOR,
|
|
95
|
+
set_max_commitment_age: SET_MAX_COMMITMENT_AGE_DISCRIMINATOR,
|
|
96
|
+
};
|
|
97
|
+
/** Build any one-integer-arg AdminOnly setter (lease rate divisor, lease grace,
|
|
98
|
+
* recovery timelock, min/max commitment age). disc(8) + value as little-endian
|
|
99
|
+
* u64(8). The value must be a non-negative integer that fits u64. */
|
|
100
|
+
export function buildAdminScalarSetterIx(p) {
|
|
101
|
+
const raw = typeof p.value === "bigint" ? p.value : BigInt(p.value);
|
|
102
|
+
if (raw < 0n || raw > 0xffffffffffffffffn) {
|
|
103
|
+
throw new Error(`value ${p.value} is out of u64 range`);
|
|
104
|
+
}
|
|
105
|
+
const data = new Uint8Array(8 + 8);
|
|
106
|
+
data.set(p.discriminator, 0);
|
|
107
|
+
new DataView(data.buffer).setBigUint64(8, raw, true);
|
|
108
|
+
return {
|
|
109
|
+
programId: toBase58(p.programId, "programId"),
|
|
110
|
+
keys: adminOnlyKeys(p.admin, p.config),
|
|
111
|
+
data,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin-only marketplace config (`set_market_config`, #8401) and the namespace
|
|
3
|
+
* directory setters (`create_namespace` / `set_namespace_status`, #8403). The
|
|
4
|
+
* integrator setters (add/set_rate/remove) already live in ./integrator.ts and
|
|
5
|
+
* are reused, not duplicated here.
|
|
6
|
+
*
|
|
7
|
+
* Hand-rolled like the rest of this package — no Anchor client, no
|
|
8
|
+
* `@solana/web3.js`. Unlike the AdminOnly setters in adminConfig.ts, these do
|
|
9
|
+
* NOT share one account shape: `config` is read-only here (it's the has_one =
|
|
10
|
+
* admin authority check), and the written account differs per instruction
|
|
11
|
+
* (`market_config` or a `Namespace`). PDAs are not derived here — derive
|
|
12
|
+
* `["market_config"]`, `["namespace", label]`, `["config"]` with your runtime's
|
|
13
|
+
* findProgramAddress and pass them in, same convention as adminConfig.ts.
|
|
14
|
+
*/
|
|
15
|
+
import type { AddressLike, BuiltInstruction } from "./delegate.js";
|
|
16
|
+
/** The System Program — required by the two `init` instructions (add_integrator,
|
|
17
|
+
* create_namespace). A fixed well-known address, hardcoded so callers can't
|
|
18
|
+
* mistype it. */
|
|
19
|
+
export declare const SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
20
|
+
/** Anchor discriminator sha256("global:set_market_config")[0..8]. */
|
|
21
|
+
export declare const SET_MARKET_CONFIG_DISCRIMINATOR: Uint8Array;
|
|
22
|
+
export interface SetMarketConfigParams {
|
|
23
|
+
readonly programId: AddressLike;
|
|
24
|
+
/** `Config.admin` — signs; NOT writable. */
|
|
25
|
+
readonly admin: AddressLike;
|
|
26
|
+
/** `["config"]` PDA — read-only (the has_one authority check). */
|
|
27
|
+
readonly config: AddressLike;
|
|
28
|
+
/** `["market_config"]` PDA — writable. */
|
|
29
|
+
readonly marketConfig: AddressLike;
|
|
30
|
+
readonly feeBps: number;
|
|
31
|
+
readonly minBidIncrementBps: number;
|
|
32
|
+
readonly antiSnipeWindow: number;
|
|
33
|
+
readonly antiSnipeExtend: number;
|
|
34
|
+
readonly minAuctionSecs: number;
|
|
35
|
+
readonly maxAuctionSecs: number;
|
|
36
|
+
readonly paused: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Build `set_market_config` — fee/auction params + the global pause flag.
|
|
39
|
+
* Enforces the same bounds the program's validate_market_params does. */
|
|
40
|
+
export declare function buildSetMarketConfigIx(p: SetMarketConfigParams): BuiltInstruction;
|
|
41
|
+
export declare const CREATE_NAMESPACE_DISCRIMINATOR: Uint8Array;
|
|
42
|
+
export declare const SET_NAMESPACE_STATUS_DISCRIMINATOR: Uint8Array;
|
|
43
|
+
export declare const NAMESPACE_MAX_LEN = 16;
|
|
44
|
+
export type NamespaceStatus = "Active" | "Paused" | "Retired";
|
|
45
|
+
export interface CreateNamespaceParams {
|
|
46
|
+
readonly programId: AddressLike;
|
|
47
|
+
/** admin — signs AND pays rent; writable. */
|
|
48
|
+
readonly admin: AddressLike;
|
|
49
|
+
readonly config: AddressLike;
|
|
50
|
+
/** `["namespace", label]` PDA — init, writable. */
|
|
51
|
+
readonly namespace: AddressLike;
|
|
52
|
+
/** Canonical ASCII label (a-z 0-9 -), 1..=16 bytes — an instruction ARG. */
|
|
53
|
+
readonly label: string;
|
|
54
|
+
readonly systemProgram?: AddressLike;
|
|
55
|
+
}
|
|
56
|
+
/** Build `create_namespace` — label is a borsh String arg. */
|
|
57
|
+
export declare function buildCreateNamespaceIx(p: CreateNamespaceParams): BuiltInstruction;
|
|
58
|
+
export interface SetNamespaceStatusParams {
|
|
59
|
+
readonly programId: AddressLike;
|
|
60
|
+
readonly admin: AddressLike;
|
|
61
|
+
readonly config: AddressLike;
|
|
62
|
+
/** `["namespace", label]` PDA — writable. */
|
|
63
|
+
readonly namespace: AddressLike;
|
|
64
|
+
readonly status: NamespaceStatus;
|
|
65
|
+
}
|
|
66
|
+
/** Build `set_namespace_status` — status enum as a single-byte discriminant. */
|
|
67
|
+
export declare function buildSetNamespaceStatusIx(p: SetNamespaceStatusParams): BuiltInstruction;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin-only marketplace config (`set_market_config`, #8401) and the namespace
|
|
3
|
+
* directory setters (`create_namespace` / `set_namespace_status`, #8403). The
|
|
4
|
+
* integrator setters (add/set_rate/remove) already live in ./integrator.ts and
|
|
5
|
+
* are reused, not duplicated here.
|
|
6
|
+
*
|
|
7
|
+
* Hand-rolled like the rest of this package — no Anchor client, no
|
|
8
|
+
* `@solana/web3.js`. Unlike the AdminOnly setters in adminConfig.ts, these do
|
|
9
|
+
* NOT share one account shape: `config` is read-only here (it's the has_one =
|
|
10
|
+
* admin authority check), and the written account differs per instruction
|
|
11
|
+
* (`market_config` or a `Namespace`). PDAs are not derived here — derive
|
|
12
|
+
* `["market_config"]`, `["namespace", label]`, `["config"]` with your runtime's
|
|
13
|
+
* findProgramAddress and pass them in, same convention as adminConfig.ts.
|
|
14
|
+
*/
|
|
15
|
+
import { encodeBase58, decodeBase58_32 } from "./base58.js";
|
|
16
|
+
/** The System Program — required by the two `init` instructions (add_integrator,
|
|
17
|
+
* create_namespace). A fixed well-known address, hardcoded so callers can't
|
|
18
|
+
* mistype it. */
|
|
19
|
+
export const SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
20
|
+
function toBytes32(v, what) {
|
|
21
|
+
if (typeof v === "string") {
|
|
22
|
+
const b = decodeBase58_32(v);
|
|
23
|
+
if (!b)
|
|
24
|
+
throw new Error(`${what} is not a valid base58 address`);
|
|
25
|
+
return b;
|
|
26
|
+
}
|
|
27
|
+
if (v.length !== 32)
|
|
28
|
+
throw new Error(`${what} must be exactly 32 bytes`);
|
|
29
|
+
return v;
|
|
30
|
+
}
|
|
31
|
+
function toBase58(v, what) {
|
|
32
|
+
return encodeBase58(toBytes32(v, what));
|
|
33
|
+
}
|
|
34
|
+
// ---- borsh scalar writers -------------------------------------------------
|
|
35
|
+
function u16le(n) {
|
|
36
|
+
if (!Number.isInteger(n) || n < 0 || n > 0xffff)
|
|
37
|
+
throw new Error(`u16 out of range: ${n}`);
|
|
38
|
+
const b = new Uint8Array(2);
|
|
39
|
+
new DataView(b.buffer).setUint16(0, n, true);
|
|
40
|
+
return b;
|
|
41
|
+
}
|
|
42
|
+
function u32le(n) {
|
|
43
|
+
if (!Number.isInteger(n) || n < 0 || n > 0xffff_ffff)
|
|
44
|
+
throw new Error(`u32 out of range: ${n}`);
|
|
45
|
+
const b = new Uint8Array(4);
|
|
46
|
+
new DataView(b.buffer).setUint32(0, n, true);
|
|
47
|
+
return b;
|
|
48
|
+
}
|
|
49
|
+
function concat(parts) {
|
|
50
|
+
const len = parts.reduce((n, p) => n + p.length, 0);
|
|
51
|
+
const out = new Uint8Array(len);
|
|
52
|
+
let o = 0;
|
|
53
|
+
for (const p of parts) {
|
|
54
|
+
out.set(p, o);
|
|
55
|
+
o += p.length;
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
// ===== #8401 set_market_config =====
|
|
60
|
+
/** Anchor discriminator sha256("global:set_market_config")[0..8]. */
|
|
61
|
+
export const SET_MARKET_CONFIG_DISCRIMINATOR = Uint8Array.from([128, 237, 216, 59, 122, 62, 156, 30]);
|
|
62
|
+
/** Build `set_market_config` — fee/auction params + the global pause flag.
|
|
63
|
+
* Enforces the same bounds the program's validate_market_params does. */
|
|
64
|
+
export function buildSetMarketConfigIx(p) {
|
|
65
|
+
if (p.feeBps > 10_000)
|
|
66
|
+
throw new Error("feeBps must be <= 10000");
|
|
67
|
+
if (p.minBidIncrementBps > 10_000)
|
|
68
|
+
throw new Error("minBidIncrementBps must be <= 10000");
|
|
69
|
+
if (p.minAuctionSecs <= 0)
|
|
70
|
+
throw new Error("minAuctionSecs must be > 0");
|
|
71
|
+
if (p.maxAuctionSecs < p.minAuctionSecs)
|
|
72
|
+
throw new Error("maxAuctionSecs must be >= minAuctionSecs");
|
|
73
|
+
if (p.antiSnipeExtend < p.antiSnipeWindow)
|
|
74
|
+
throw new Error("antiSnipeExtend must be >= antiSnipeWindow");
|
|
75
|
+
const data = concat([
|
|
76
|
+
SET_MARKET_CONFIG_DISCRIMINATOR,
|
|
77
|
+
u16le(p.feeBps),
|
|
78
|
+
u16le(p.minBidIncrementBps),
|
|
79
|
+
u32le(p.antiSnipeWindow),
|
|
80
|
+
u32le(p.antiSnipeExtend),
|
|
81
|
+
u32le(p.minAuctionSecs),
|
|
82
|
+
u32le(p.maxAuctionSecs),
|
|
83
|
+
Uint8Array.from([p.paused ? 1 : 0]),
|
|
84
|
+
]);
|
|
85
|
+
const keys = [
|
|
86
|
+
{ pubkey: toBase58(p.admin, "admin"), isSigner: true, isWritable: false },
|
|
87
|
+
{ pubkey: toBase58(p.config, "config"), isSigner: false, isWritable: false },
|
|
88
|
+
{ pubkey: toBase58(p.marketConfig, "marketConfig"), isSigner: false, isWritable: true },
|
|
89
|
+
];
|
|
90
|
+
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
91
|
+
}
|
|
92
|
+
// NOTE: the integrator builders (add_integrator / set_integrator_rate /
|
|
93
|
+
// remove_integrator) + decodeAllowlistEntry already live in ./integrator.ts —
|
|
94
|
+
// reuse those, they are not duplicated here.
|
|
95
|
+
// ===== #8403 namespaces =====
|
|
96
|
+
export const CREATE_NAMESPACE_DISCRIMINATOR = Uint8Array.from([205, 189, 35, 255, 214, 116, 25, 107]);
|
|
97
|
+
export const SET_NAMESPACE_STATUS_DISCRIMINATOR = Uint8Array.from([41, 135, 103, 92, 151, 13, 61, 158]);
|
|
98
|
+
export const NAMESPACE_MAX_LEN = 16;
|
|
99
|
+
const NAMESPACE_STATUS_DISCRIMINANT = {
|
|
100
|
+
Active: 0,
|
|
101
|
+
Paused: 1,
|
|
102
|
+
Retired: 2,
|
|
103
|
+
};
|
|
104
|
+
function borshString(s) {
|
|
105
|
+
const bytes = new TextEncoder().encode(s);
|
|
106
|
+
return concat([u32le(bytes.length), bytes]);
|
|
107
|
+
}
|
|
108
|
+
/** Build `create_namespace` — label is a borsh String arg. */
|
|
109
|
+
export function buildCreateNamespaceIx(p) {
|
|
110
|
+
if (p.label.length < 1 || p.label.length > NAMESPACE_MAX_LEN) {
|
|
111
|
+
throw new Error(`label must be 1..=${NAMESPACE_MAX_LEN} chars`);
|
|
112
|
+
}
|
|
113
|
+
const data = concat([CREATE_NAMESPACE_DISCRIMINATOR, borshString(p.label)]);
|
|
114
|
+
const keys = [
|
|
115
|
+
{ pubkey: toBase58(p.admin, "admin"), isSigner: true, isWritable: true },
|
|
116
|
+
{ pubkey: toBase58(p.config, "config"), isSigner: false, isWritable: false },
|
|
117
|
+
{ pubkey: toBase58(p.namespace, "namespace"), isSigner: false, isWritable: true },
|
|
118
|
+
{ pubkey: toBase58(p.systemProgram ?? SYSTEM_PROGRAM_ID, "systemProgram"), isSigner: false, isWritable: false },
|
|
119
|
+
];
|
|
120
|
+
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
121
|
+
}
|
|
122
|
+
/** Build `set_namespace_status` — status enum as a single-byte discriminant. */
|
|
123
|
+
export function buildSetNamespaceStatusIx(p) {
|
|
124
|
+
const disc = NAMESPACE_STATUS_DISCRIMINANT[p.status];
|
|
125
|
+
if (disc === undefined)
|
|
126
|
+
throw new Error(`unknown namespace status: ${p.status}`);
|
|
127
|
+
const data = concat([SET_NAMESPACE_STATUS_DISCRIMINATOR, Uint8Array.from([disc])]);
|
|
128
|
+
const keys = [
|
|
129
|
+
{ pubkey: toBase58(p.admin, "admin"), isSigner: true, isWritable: false },
|
|
130
|
+
{ pubkey: toBase58(p.config, "config"), isSigner: false, isWritable: false },
|
|
131
|
+
{ pubkey: toBase58(p.namespace, "namespace"), isSigner: false, isWritable: true },
|
|
132
|
+
];
|
|
133
|
+
return { programId: toBase58(p.programId, "programId"), keys, data };
|
|
134
|
+
}
|
package/dist/attestation.d.ts
CHANGED
|
@@ -91,6 +91,14 @@ export declare const ATTESTATION_KIND_TELEGRAM = 5;
|
|
|
91
91
|
* `>=` this on-chain; the SDK's builder enforces the same bound. Mirrors
|
|
92
92
|
* `Attestation::KIND_COUNT` (programs/x1-handles/src/state.rs). */
|
|
93
93
|
export declare const ATTESTATION_KIND_COUNT = 6;
|
|
94
|
+
/** `Attestation.kind` — validator control proven TRUSTLESSLY on-chain (#8486):
|
|
95
|
+
* the vote account's `authorized_withdrawer` co-signed `attest_validator`, or
|
|
96
|
+
* signed the challenge that `attest_validator_signed` verifies via the Ed25519
|
|
97
|
+
* precompile. Value 6 — equal to {@link ATTESTATION_KIND_COUNT}, i.e. OUTSIDE
|
|
98
|
+
* the attestor-mintable range (`create_attestation` refuses `>= KIND_COUNT`),
|
|
99
|
+
* so only the cryptographic validator path can mint it. `evidenceHash` holds
|
|
100
|
+
* the vote account pubkey; surfaced as a gold shield, not the blue tick. */
|
|
101
|
+
export declare const ATTESTATION_KIND_VALIDATOR = 6;
|
|
94
102
|
/** Anchor account discriminator: `sha256("account:Attestation")[0..8]`.
|
|
95
103
|
* Pinned (this SDK is zero-dependency and cannot assume WebCrypto SHA-256
|
|
96
104
|
* everywhere it runs); asserted against a re-derivation in the test suite
|
|
@@ -104,6 +112,18 @@ export declare const SET_ATTESTOR_DISCRIMINATOR: Uint8Array;
|
|
|
104
112
|
export declare const CREATE_ATTESTATION_DISCRIMINATOR: Uint8Array;
|
|
105
113
|
/** Anchor instruction discriminator: `sha256("global:close_attestation")[0..8]`. */
|
|
106
114
|
export declare const CLOSE_ATTESTATION_DISCRIMINATOR: Uint8Array;
|
|
115
|
+
/** Anchor instruction discriminator: `sha256("global:attest_validator")[0..8]` — the co-sign path. */
|
|
116
|
+
export declare const ATTEST_VALIDATOR_DISCRIMINATOR: Uint8Array;
|
|
117
|
+
/** Anchor instruction discriminator: `sha256("global:attest_validator_signed")[0..8]` — the detached path. */
|
|
118
|
+
export declare const ATTEST_VALIDATOR_SIGNED_DISCRIMINATOR: Uint8Array;
|
|
119
|
+
/** The SVM Ed25519 signature-verification precompile — carries the withdraw
|
|
120
|
+
* authority's detached signature for `attest_validator_signed`. */
|
|
121
|
+
export declare const ED25519_PROGRAM_ID = "Ed25519SigVerify111111111111111111111111111";
|
|
122
|
+
/** The Instructions sysvar — `attest_validator_signed` introspects it. */
|
|
123
|
+
export declare const SYSVAR_INSTRUCTIONS_ID = "Sysvar1nstructions1111111111111111111111111";
|
|
124
|
+
/** Domain-separator prefix of the validator-attestation challenge. MUST byte-
|
|
125
|
+
* match `VALIDATOR_ATTEST_CHALLENGE_PREFIX` in programs/x1-handles/src/lib.rs. */
|
|
126
|
+
export declare const VALIDATOR_ATTEST_CHALLENGE_PREFIX: Uint8Array;
|
|
107
127
|
/** `Attestation` account size — every field is fixed-width, so unlike a
|
|
108
128
|
* `Handle` the account is exactly this long:
|
|
109
129
|
* disc(8) + handle(32) + kind(1) + evidence_hash(32) + attested_at(8)
|
|
@@ -112,7 +132,7 @@ export declare const ATTESTATION_LEN = 114;
|
|
|
112
132
|
/** `AttestorConfig` account size: disc(8) + attestor(32) + bump(1). */
|
|
113
133
|
export declare const ATTESTOR_CONFIG_LEN = 41;
|
|
114
134
|
/** Human name an attestation `kind` byte carries. */
|
|
115
|
-
export type AttestationKindName = "dns" | "social" | "x" | "discord" | "github" | "telegram";
|
|
135
|
+
export type AttestationKindName = "dns" | "social" | "x" | "discord" | "github" | "telegram" | "validator";
|
|
116
136
|
/** Which verification signal an attestation `kind` byte names, or null for a
|
|
117
137
|
* kind this SDK does not know (future program versions may add kinds). For the
|
|
118
138
|
* per-platform kinds this returns the platform slug; the two legacy kinds keep
|
|
@@ -272,6 +292,88 @@ export interface CloseAttestationParams {
|
|
|
272
292
|
* a rotated-away key's output).
|
|
273
293
|
*/
|
|
274
294
|
export declare function buildCloseAttestationIx(p: CloseAttestationParams): BuiltInstruction;
|
|
295
|
+
export interface AttestValidatorParams {
|
|
296
|
+
/** The registry program id. */
|
|
297
|
+
readonly programId: AddressLike;
|
|
298
|
+
/** The handle's authority (owner, or NFT holder if tokenized); signs + pays rent. */
|
|
299
|
+
readonly owner: AddressLike;
|
|
300
|
+
/** The vote account's withdraw authority; co-signs (MAY equal `owner`). */
|
|
301
|
+
readonly withdrawAuthority: AddressLike;
|
|
302
|
+
/** The `["handle", name]` PDA. */
|
|
303
|
+
readonly handle: AddressLike;
|
|
304
|
+
/** The validator's vote account (owned by the Vote program on-chain). */
|
|
305
|
+
readonly voteAccount: AddressLike;
|
|
306
|
+
/** The `["attestation", handle, [KIND_VALIDATOR]]` PDA. */
|
|
307
|
+
readonly attestation: AddressLike;
|
|
308
|
+
/** ONLY for a tokenized handle: the caller's associated token account for the
|
|
309
|
+
* handle's NFT mint (the holder-proof `require_current_authority` reads). */
|
|
310
|
+
readonly holderTokenAccount?: AddressLike;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Build `attest_validator` (co-sign path). Two signers — `owner` (authorizes
|
|
314
|
+
* the link) and `withdrawAuthority` (the proof) — which MAY be the same key. No
|
|
315
|
+
* instruction args: the co-signature IS the proof.
|
|
316
|
+
*/
|
|
317
|
+
export declare function buildAttestValidatorIx(p: AttestValidatorParams): BuiltInstruction;
|
|
318
|
+
/**
|
|
319
|
+
* The exact 96-byte challenge the withdraw authority signs for the DETACHED
|
|
320
|
+
* path: `PREFIX(24) ‖ handle(32) ‖ voteAccount(32) ‖ registeredAt i64 LE(8)`.
|
|
321
|
+
* MUST byte-match the program. `registeredAt` is the handle's on-chain
|
|
322
|
+
* `registered_at` (seconds) — pass the exact value from the Handle account.
|
|
323
|
+
*/
|
|
324
|
+
export declare function validatorAttestChallenge(handle: AddressLike, voteAccount: AddressLike, registeredAt: bigint | number): Uint8Array;
|
|
325
|
+
export interface Ed25519VerifyParams {
|
|
326
|
+
/** The 32-byte ed25519 public key (the withdraw authority). */
|
|
327
|
+
readonly publicKey: AddressLike;
|
|
328
|
+
/** The signed message (the validator challenge). */
|
|
329
|
+
readonly message: Uint8Array;
|
|
330
|
+
/** The 64-byte ed25519 signature over `message` by `publicKey`. */
|
|
331
|
+
readonly signature: Uint8Array;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Build the Ed25519 precompile instruction (no accounts) proving `signature` is
|
|
335
|
+
* `publicKey`'s over `message`. SELF-CONTAINED single signature — all three
|
|
336
|
+
* instruction-index fields are `0xFFFF` — matching the exact layout
|
|
337
|
+
* `attest_validator_signed` requires. Place it IMMEDIATELY BEFORE the attest ix
|
|
338
|
+
* (use {@link buildAttestValidatorSignedIxs}).
|
|
339
|
+
*/
|
|
340
|
+
export declare function buildEd25519VerifyIx(p: Ed25519VerifyParams): BuiltInstruction;
|
|
341
|
+
export interface AttestValidatorSignedParams {
|
|
342
|
+
/** The registry program id. */
|
|
343
|
+
readonly programId: AddressLike;
|
|
344
|
+
/** The handle's authority (owner / NFT holder); the SOLE tx signer, pays rent. */
|
|
345
|
+
readonly owner: AddressLike;
|
|
346
|
+
readonly handle: AddressLike;
|
|
347
|
+
readonly voteAccount: AddressLike;
|
|
348
|
+
/** The `["attestation", handle, [KIND_VALIDATOR]]` PDA. */
|
|
349
|
+
readonly attestation: AddressLike;
|
|
350
|
+
/** ONLY for a tokenized handle: the caller's ATA for the handle's NFT mint. */
|
|
351
|
+
readonly holderTokenAccount?: AddressLike;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Build the `attest_validator_signed` ix ALONE. The withdraw authority's proof
|
|
355
|
+
* is NOT here — it rides in the Ed25519 precompile ix that MUST immediately
|
|
356
|
+
* precede this one. Prefer {@link buildAttestValidatorSignedIxs}, which returns
|
|
357
|
+
* both, in order. No instruction args.
|
|
358
|
+
*/
|
|
359
|
+
export declare function buildAttestValidatorSignedIx(p: AttestValidatorSignedParams): BuiltInstruction;
|
|
360
|
+
export interface AttestValidatorSignedTxParams extends AttestValidatorSignedParams {
|
|
361
|
+
/** The vote account's `authorized_withdrawer` (32-byte ed25519 pubkey) whose
|
|
362
|
+
* offline signature over the challenge this carries. */
|
|
363
|
+
readonly withdrawAuthority: AddressLike;
|
|
364
|
+
/** The 64-byte ed25519 signature over {@link validatorAttestChallenge},
|
|
365
|
+
* produced offline by the withdraw authority. */
|
|
366
|
+
readonly signature: Uint8Array;
|
|
367
|
+
/** The handle's on-chain `registered_at` (seconds). */
|
|
368
|
+
readonly registeredAt: bigint | number;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Build BOTH instructions for the detached path, IN ORDER:
|
|
372
|
+
* `[ed25519VerifyIx, attestValidatorSignedIx]`. Submit them as ONE transaction
|
|
373
|
+
* in this order — the program loads the ed25519 ix at `current_index - 1`.
|
|
374
|
+
* `owner` is the only signer.
|
|
375
|
+
*/
|
|
376
|
+
export declare function buildAttestValidatorSignedIxs(p: AttestValidatorSignedTxParams): BuiltInstruction[];
|
|
275
377
|
/** The minimal shape the verification helpers read — any {@link Resolved}
|
|
276
378
|
* satisfies it, as does a bare `{ verifications }` an integrator assembles
|
|
277
379
|
* from a raw REST payload. */
|