@x1id/resolve 0.23.0 → 0.43.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 +71 -0
- package/dist/accounts.d.ts +6 -0
- package/dist/accounts.js +6 -1
- package/dist/agent.d.ts +184 -8
- package/dist/agent.js +351 -3
- package/dist/agentPolicy.d.ts +238 -0
- package/dist/agentPolicy.js +364 -0
- package/dist/attestation.d.ts +25 -0
- package/dist/attestation.js +25 -0
- package/dist/checkout.d.ts +216 -0
- package/dist/checkout.js +327 -0
- package/dist/credentials.d.ts +466 -0
- package/dist/credentials.js +669 -0
- package/dist/gate.d.ts +94 -4
- package/dist/gate.js +206 -7
- package/dist/gateClient.d.ts +12 -0
- package/dist/giftLink.d.ts +272 -0
- package/dist/giftLink.js +452 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +32 -0
- package/dist/loginButton.d.ts +69 -0
- package/dist/loginButton.js +207 -0
- package/dist/logo.d.ts +1 -0
- package/dist/logo.js +8 -0
- package/dist/messaging.d.ts +439 -0
- package/dist/messaging.js +979 -0
- package/dist/nsGate.d.ts +98 -0
- package/dist/nsGate.js +172 -0
- package/dist/oidc.d.ts +272 -0
- package/dist/oidc.js +641 -0
- package/dist/pay.d.ts +513 -0
- package/dist/pay.js +756 -0
- package/dist/payment.d.ts +9 -2
- package/dist/payment.js +9 -2
- package/dist/recovery.d.ts +186 -0
- package/dist/recovery.js +276 -0
- package/dist/recoveryNft.d.ts +183 -0
- package/dist/recoveryNft.js +291 -0
- package/dist/shield.d.ts +373 -0
- package/dist/shield.js +695 -0
- package/dist/subscription.d.ts +439 -0
- package/dist/subscription.js +642 -0
- package/dist/textRecords.d.ts +52 -6
- package/dist/textRecords.js +80 -8
- package/dist/types.d.ts +3 -0
- package/dist/x402Receipt.d.ts +246 -0
- package/dist/x402Receipt.js +374 -0
- package/package.json +18 -1
- package/schema/agent-manifest.json +91 -8
package/dist/gate.d.ts
CHANGED
|
@@ -13,17 +13,50 @@
|
|
|
13
13
|
* {@link markHolderMismatch} onto the fetched set never admits an inherited
|
|
14
14
|
* badge. Nothing here trusts an off-chain claim: every input is an on-chain,
|
|
15
15
|
* attestor-signed `Attestation` account.
|
|
16
|
+
*
|
|
17
|
+
* # Third-party credentials (upgrade 6, docs/specs/x1id-credentials.md)
|
|
18
|
+
*
|
|
19
|
+
* A gate may also require an issuer-signed credential:
|
|
20
|
+
* `{ credential: { schema, issuers, minRemainingSecs? } }`, combined with
|
|
21
|
+
* `{ allOf: Gate[] }` / `{ anyOf: Gate[] }`. `issuers` is an explicit, non-empty
|
|
22
|
+
* list of Issuer PDAs, or the alias `"x1id-recommended"` (X1ID's ADVISORY
|
|
23
|
+
* list, which an app must choose; {@link resolveRecommendedIssuers} snapshots
|
|
24
|
+
* it into a fixed list). `"any-verified"`, `{ kind }` and `{ anyOf: kinds }`
|
|
25
|
+
* keep reading ONLY attestations: a credential never satisfies the blue tick.
|
|
16
26
|
*/
|
|
17
27
|
import { type HandleAttestation } from "./attestation.js";
|
|
18
28
|
import type { RpcFn } from "./accounts.js";
|
|
29
|
+
import type { PdaFinder } from "./namespacePricing.js";
|
|
30
|
+
import { type HandleCredential } from "./credentials.js";
|
|
31
|
+
/** The alias for X1ID's advisory recommended-issuer list. */
|
|
32
|
+
export declare const RECOMMENDED_ISSUERS_ALIAS = "x1id-recommended";
|
|
33
|
+
/** Opt-in to follow the live list instead of a snapshot (dev-api policies). */
|
|
34
|
+
export declare const RECOMMENDED_ISSUERS_LIVE_ALIAS = "x1id-recommended:live";
|
|
35
|
+
/** A third-party credential requirement. */
|
|
36
|
+
export interface CredentialClause {
|
|
37
|
+
/** The issuer-defined schema id (u32). */
|
|
38
|
+
readonly schema: number;
|
|
39
|
+
/** Issuer PDAs (base58, 1-32), or the advisory-list alias. */
|
|
40
|
+
readonly issuers: readonly string[] | typeof RECOMMENDED_ISSUERS_ALIAS | typeof RECOMMENDED_ISSUERS_LIVE_ALIAS;
|
|
41
|
+
/** Demand at least this much validity left (seconds, >= 0). */
|
|
42
|
+
readonly minRemainingSecs?: number;
|
|
43
|
+
}
|
|
19
44
|
/** What a handle must prove to pass the gate:
|
|
20
45
|
* - `"any-verified"` — at least one non-stale attestation of any kind.
|
|
21
46
|
* - `{ kind }` — a non-stale attestation of exactly that kind.
|
|
22
|
-
* - `{ anyOf }` — a non-stale attestation of any listed kind (e.g. X OR GitHub).
|
|
47
|
+
* - `{ anyOf: kinds }` — a non-stale attestation of any listed kind (e.g. X OR GitHub).
|
|
48
|
+
* - `{ credential }` — a valid third-party credential (see {@link CredentialClause}).
|
|
49
|
+
* - `{ allOf: Gate[] }` / `{ anyOf: Gate[] }` — every / any sub-gate. */
|
|
23
50
|
export type Gate = "any-verified" | {
|
|
24
51
|
readonly kind: number;
|
|
25
52
|
} | {
|
|
26
53
|
readonly anyOf: readonly number[];
|
|
54
|
+
} | {
|
|
55
|
+
readonly credential: CredentialClause;
|
|
56
|
+
} | {
|
|
57
|
+
readonly allOf: readonly Gate[];
|
|
58
|
+
} | {
|
|
59
|
+
readonly anyOf: readonly Gate[];
|
|
27
60
|
};
|
|
28
61
|
/** Named platform kinds, re-exported so callers gate without magic numbers. */
|
|
29
62
|
export declare const GateKind: {
|
|
@@ -34,17 +67,74 @@ export declare const GateKind: {
|
|
|
34
67
|
readonly github: 4;
|
|
35
68
|
readonly telegram: 5;
|
|
36
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Validate a gate's shape (throws a typed `ResolveError("invalid-input")`).
|
|
72
|
+
* Credential clauses need a u32 `schema`, a non-negative integer
|
|
73
|
+
* `minRemainingSecs`, and `issuers` that is the alias or 1-32 distinct
|
|
74
|
+
* base58 addresses. Nesting is bounded (depth 4, 16 clauses).
|
|
75
|
+
*/
|
|
76
|
+
export declare function validateGate(gate: Gate): void;
|
|
77
|
+
/** Every credential clause in `gate` (depth-first). */
|
|
78
|
+
export declare function credentialClauses(gate: Gate): CredentialClause[];
|
|
79
|
+
/**
|
|
80
|
+
* Replace the `"x1id-recommended"` alias with a fixed copy of `list` (a
|
|
81
|
+
* snapshot): a later change of the advisory list, or a compromised admin key
|
|
82
|
+
* adding an issuer, then cannot change this gate silently. The
|
|
83
|
+
* `"x1id-recommended:live"` alias is kept unless `resolveLive` is set.
|
|
84
|
+
* Throws if the list is empty (a gate must name at least one issuer).
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveRecommendedIssuers(gate: Gate, list: readonly string[], opts?: {
|
|
87
|
+
readonly resolveLive?: boolean;
|
|
88
|
+
}): Gate;
|
|
89
|
+
/** Inputs for evaluating credential clauses. */
|
|
90
|
+
export interface CredentialGateInputs {
|
|
91
|
+
/** `{ schema, issuers }` → the credentials found (any validity). */
|
|
92
|
+
readonly credentialsFor: (clause: CredentialClause) => readonly HandleCredential[];
|
|
93
|
+
}
|
|
94
|
+
/** Which clauses passed, for display. */
|
|
95
|
+
export interface GateEvaluation {
|
|
96
|
+
readonly passed: boolean;
|
|
97
|
+
/** Human-readable ids of the satisfied leaf clauses (`kind:4`,
|
|
98
|
+
* `credential:<issuer>:<schema>`, `any-verified`). */
|
|
99
|
+
readonly matched: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Pure evaluation of any gate. Attestation clauses read `attestations` only;
|
|
103
|
+
* credential clauses read `credentials` (required when the gate has any).
|
|
104
|
+
* Stale and holder-mismatched attestations never count; a credential counts
|
|
105
|
+
* only when `validity.valid` (credentials.ts `credentialValidity`).
|
|
106
|
+
*/
|
|
107
|
+
export declare function evaluateGate(gate: Gate, attestations: readonly HandleAttestation[], credentials?: CredentialGateInputs): GateEvaluation;
|
|
37
108
|
/** Pure check: do these (already-fetched) attestations satisfy the gate?
|
|
38
|
-
* Stale and holder-mismatched (H5) attestations never count.
|
|
109
|
+
* Stale and holder-mismatched (H5) attestations never count. A gate with a
|
|
110
|
+
* credential clause throws here: use {@link evaluateGate} with credentials. */
|
|
39
111
|
export declare function attestationsPassGate(attestations: readonly HandleAttestation[], gate: Gate): boolean;
|
|
112
|
+
/** Extra inputs `handlePassesGate` needs for credential clauses. */
|
|
113
|
+
export interface CredentialGateOptions {
|
|
114
|
+
/** `find_program_address` (see namespacePricing.ts `PdaFinder`). */
|
|
115
|
+
readonly find: PdaFinder;
|
|
116
|
+
/** The handle's CURRENT authority: `Handle.owner` while untokenized, the
|
|
117
|
+
* pNFT holder once tokenized. */
|
|
118
|
+
readonly currentHolder: string | null;
|
|
119
|
+
/** Unix seconds (default: now). */
|
|
120
|
+
readonly nowSecs?: bigint | number;
|
|
121
|
+
/** A pre-fetched advisory list for the alias (default: read from chain). */
|
|
122
|
+
readonly recommendedIssuers?: readonly string[];
|
|
123
|
+
}
|
|
40
124
|
/** Fetch a handle's attestations and test the gate in one call. `handleAccount`,
|
|
41
125
|
* `registeredAt`, `recordsClearedAt` and `holderEpoch` come from the handle you
|
|
42
126
|
* resolved (name → `deriveHandleAccount` → decode). `holderEpoch` (H5 / PR
|
|
43
127
|
* #466, 0 if absent) folds into the staleness epoch so the gate matches the
|
|
44
128
|
* on-chain rule `attested_at >= max(registered_at, holder_epoch)`; it defaults
|
|
45
129
|
* to `0n` for backward compatibility. Returns the pass/fail plus the
|
|
46
|
-
* attestations so a caller can also render WHICH signals matched.
|
|
47
|
-
|
|
130
|
+
* attestations so a caller can also render WHICH signals matched.
|
|
131
|
+
*
|
|
132
|
+
* A gate with credential clauses also needs `credentialOpts` (the PDA
|
|
133
|
+
* finder and the current holder); its credentials are read from the chain
|
|
134
|
+
* (derived PDAs, one `getMultipleAccounts` per clause) and returned too. */
|
|
135
|
+
export declare function handlePassesGate(rpc: RpcFn, programId: string, handleAccount: string, registeredAt: bigint, recordsClearedAt: bigint, gate: Gate, holderEpoch?: bigint, credentialOpts?: CredentialGateOptions): Promise<{
|
|
48
136
|
readonly passed: boolean;
|
|
49
137
|
readonly attestations: HandleAttestation[];
|
|
138
|
+
readonly credentials?: readonly HandleCredential[];
|
|
139
|
+
readonly matched?: readonly string[];
|
|
50
140
|
}>;
|
package/dist/gate.js
CHANGED
|
@@ -13,9 +13,25 @@
|
|
|
13
13
|
* {@link markHolderMismatch} onto the fetched set never admits an inherited
|
|
14
14
|
* badge. Nothing here trusts an off-chain claim: every input is an on-chain,
|
|
15
15
|
* attestor-signed `Attestation` account.
|
|
16
|
+
*
|
|
17
|
+
* # Third-party credentials (upgrade 6, docs/specs/x1id-credentials.md)
|
|
18
|
+
*
|
|
19
|
+
* A gate may also require an issuer-signed credential:
|
|
20
|
+
* `{ credential: { schema, issuers, minRemainingSecs? } }`, combined with
|
|
21
|
+
* `{ allOf: Gate[] }` / `{ anyOf: Gate[] }`. `issuers` is an explicit, non-empty
|
|
22
|
+
* list of Issuer PDAs, or the alias `"x1id-recommended"` (X1ID's ADVISORY
|
|
23
|
+
* list, which an app must choose; {@link resolveRecommendedIssuers} snapshots
|
|
24
|
+
* it into a fixed list). `"any-verified"`, `{ kind }` and `{ anyOf: kinds }`
|
|
25
|
+
* keep reading ONLY attestations: a credential never satisfies the blue tick.
|
|
16
26
|
*/
|
|
17
27
|
import { fetchAttestations, isHandleVerified, ATTESTATION_KIND_DNS, ATTESTATION_KIND_SOCIAL, ATTESTATION_KIND_X, ATTESTATION_KIND_DISCORD, ATTESTATION_KIND_GITHUB, ATTESTATION_KIND_TELEGRAM, } from "./attestation.js";
|
|
18
28
|
import { ResolveError } from "./types.js";
|
|
29
|
+
import { decodeBase58_32 } from "./base58.js";
|
|
30
|
+
import { fetchHandleCredentials, fetchRecommendedIssuers, MAX_RECOMMENDED_ISSUERS, } from "./credentials.js";
|
|
31
|
+
/** The alias for X1ID's advisory recommended-issuer list. */
|
|
32
|
+
export const RECOMMENDED_ISSUERS_ALIAS = "x1id-recommended";
|
|
33
|
+
/** Opt-in to follow the live list instead of a snapshot (dev-api policies). */
|
|
34
|
+
export const RECOMMENDED_ISSUERS_LIVE_ALIAS = "x1id-recommended:live";
|
|
19
35
|
/** Named platform kinds, re-exported so callers gate without magic numbers. */
|
|
20
36
|
export const GateKind = {
|
|
21
37
|
dns: ATTESTATION_KIND_DNS,
|
|
@@ -25,8 +41,166 @@ export const GateKind = {
|
|
|
25
41
|
github: ATTESTATION_KIND_GITHUB,
|
|
26
42
|
telegram: ATTESTATION_KIND_TELEGRAM,
|
|
27
43
|
};
|
|
44
|
+
const MAX_GATE_DEPTH = 4;
|
|
45
|
+
const MAX_GATE_NODES = 16;
|
|
46
|
+
function bad(msg, detail) {
|
|
47
|
+
throw new ResolveError("invalid-input", msg, typeof detail === "string" ? detail : JSON.stringify(detail));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate a gate's shape (throws a typed `ResolveError("invalid-input")`).
|
|
51
|
+
* Credential clauses need a u32 `schema`, a non-negative integer
|
|
52
|
+
* `minRemainingSecs`, and `issuers` that is the alias or 1-32 distinct
|
|
53
|
+
* base58 addresses. Nesting is bounded (depth 4, 16 clauses).
|
|
54
|
+
*/
|
|
55
|
+
export function validateGate(gate) {
|
|
56
|
+
let nodes = 0;
|
|
57
|
+
const walk = (g, depth) => {
|
|
58
|
+
if (++nodes > MAX_GATE_NODES)
|
|
59
|
+
bad("gate has too many clauses (max 16)", g);
|
|
60
|
+
if (depth > MAX_GATE_DEPTH)
|
|
61
|
+
bad("gate is nested too deeply (max 4)", g);
|
|
62
|
+
if (g === "any-verified")
|
|
63
|
+
return;
|
|
64
|
+
if (g === null || typeof g !== "object" || Array.isArray(g)) {
|
|
65
|
+
bad('gate must be "any-verified", { kind }, { anyOf }, { allOf } or { credential }', String(g));
|
|
66
|
+
}
|
|
67
|
+
const o = g;
|
|
68
|
+
if ("kind" in o) {
|
|
69
|
+
if (typeof o.kind !== "number")
|
|
70
|
+
bad("kind must be a number", g);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if ("anyOf" in o || "allOf" in o) {
|
|
74
|
+
const list = ("anyOf" in o ? o.anyOf : o.allOf);
|
|
75
|
+
if (!Array.isArray(list))
|
|
76
|
+
bad("anyOf / allOf needs an array", g);
|
|
77
|
+
// `{ anyOf: kinds }` keeps its pre-credentials meaning (an empty list
|
|
78
|
+
// simply never passes).
|
|
79
|
+
if ("anyOf" in o && list.every((x) => typeof x === "number"))
|
|
80
|
+
return;
|
|
81
|
+
if (list.length === 0)
|
|
82
|
+
bad("allOf / anyOf of gates needs at least one gate", g);
|
|
83
|
+
for (const sub of list)
|
|
84
|
+
walk(sub, depth + 1);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if ("credential" in o) {
|
|
88
|
+
const c = o.credential;
|
|
89
|
+
if (c === null || typeof c !== "object")
|
|
90
|
+
bad("credential clause must be an object", g);
|
|
91
|
+
if (!Number.isInteger(c.schema) || c.schema < 0 || c.schema > 0xffff_ffff)
|
|
92
|
+
bad("credential.schema must be a u32", g);
|
|
93
|
+
if (c.minRemainingSecs !== undefined && (!Number.isSafeInteger(c.minRemainingSecs) || c.minRemainingSecs < 0)) {
|
|
94
|
+
bad("credential.minRemainingSecs must be a non-negative integer", g);
|
|
95
|
+
}
|
|
96
|
+
const iss = c.issuers;
|
|
97
|
+
if (iss === RECOMMENDED_ISSUERS_ALIAS || iss === RECOMMENDED_ISSUERS_LIVE_ALIAS)
|
|
98
|
+
return;
|
|
99
|
+
if (!Array.isArray(iss) || iss.length === 0)
|
|
100
|
+
bad("credential.issuers must be a non-empty list or \"x1id-recommended\"", g);
|
|
101
|
+
if (iss.length > MAX_RECOMMENDED_ISSUERS)
|
|
102
|
+
bad("credential.issuers has more than 32 entries", g);
|
|
103
|
+
if (new Set(iss).size !== iss.length)
|
|
104
|
+
bad("credential.issuers has duplicates", g);
|
|
105
|
+
for (const a of iss)
|
|
106
|
+
if (typeof a !== "string" || !decodeBase58_32(a))
|
|
107
|
+
bad("credential.issuers entries must be base58 addresses", a);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
bad("gate object needs a `kind`, `anyOf`, `allOf` or `credential`", g);
|
|
111
|
+
};
|
|
112
|
+
walk(gate, 0);
|
|
113
|
+
}
|
|
114
|
+
/** Every credential clause in `gate` (depth-first). */
|
|
115
|
+
export function credentialClauses(gate) {
|
|
116
|
+
const out = [];
|
|
117
|
+
const walk = (g) => {
|
|
118
|
+
if (g === "any-verified" || typeof g !== "object" || g === null)
|
|
119
|
+
return;
|
|
120
|
+
if ("credential" in g)
|
|
121
|
+
out.push(g.credential);
|
|
122
|
+
else if ("allOf" in g)
|
|
123
|
+
g.allOf.forEach(walk);
|
|
124
|
+
else if ("anyOf" in g && !g.anyOf.every((x) => typeof x === "number"))
|
|
125
|
+
g.anyOf.forEach(walk);
|
|
126
|
+
};
|
|
127
|
+
walk(gate);
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Replace the `"x1id-recommended"` alias with a fixed copy of `list` (a
|
|
132
|
+
* snapshot): a later change of the advisory list, or a compromised admin key
|
|
133
|
+
* adding an issuer, then cannot change this gate silently. The
|
|
134
|
+
* `"x1id-recommended:live"` alias is kept unless `resolveLive` is set.
|
|
135
|
+
* Throws if the list is empty (a gate must name at least one issuer).
|
|
136
|
+
*/
|
|
137
|
+
export function resolveRecommendedIssuers(gate, list, opts = {}) {
|
|
138
|
+
const map = (g) => {
|
|
139
|
+
if (g === "any-verified" || typeof g !== "object" || g === null)
|
|
140
|
+
return g;
|
|
141
|
+
if ("credential" in g) {
|
|
142
|
+
const iss = g.credential.issuers;
|
|
143
|
+
const alias = iss === RECOMMENDED_ISSUERS_ALIAS || (opts.resolveLive === true && iss === RECOMMENDED_ISSUERS_LIVE_ALIAS);
|
|
144
|
+
if (!alias)
|
|
145
|
+
return g;
|
|
146
|
+
if (list.length === 0)
|
|
147
|
+
bad("the recommended issuer list is empty", g);
|
|
148
|
+
return { credential: { ...g.credential, issuers: [...list] } };
|
|
149
|
+
}
|
|
150
|
+
if ("allOf" in g)
|
|
151
|
+
return { allOf: g.allOf.map(map) };
|
|
152
|
+
if ("anyOf" in g && !g.anyOf.every((x) => typeof x === "number"))
|
|
153
|
+
return { anyOf: g.anyOf.map(map) };
|
|
154
|
+
return g;
|
|
155
|
+
};
|
|
156
|
+
return map(gate);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Pure evaluation of any gate. Attestation clauses read `attestations` only;
|
|
160
|
+
* credential clauses read `credentials` (required when the gate has any).
|
|
161
|
+
* Stale and holder-mismatched attestations never count; a credential counts
|
|
162
|
+
* only when `validity.valid` (credentials.ts `credentialValidity`).
|
|
163
|
+
*/
|
|
164
|
+
export function evaluateGate(gate, attestations, credentials) {
|
|
165
|
+
validateGate(gate);
|
|
166
|
+
const matched = [];
|
|
167
|
+
const evalNode = (g) => {
|
|
168
|
+
if (g === "any-verified") {
|
|
169
|
+
const ok = isHandleVerified(attestations);
|
|
170
|
+
if (ok)
|
|
171
|
+
matched.push("any-verified");
|
|
172
|
+
return ok;
|
|
173
|
+
}
|
|
174
|
+
if ("kind" in g)
|
|
175
|
+
return kinds([g.kind]);
|
|
176
|
+
if ("credential" in g) {
|
|
177
|
+
if (!credentials)
|
|
178
|
+
bad("a credential gate needs credential inputs (use handlePassesGate with opts, or evaluateGate with credentials)", g);
|
|
179
|
+
const c = g.credential;
|
|
180
|
+
if (!Array.isArray(c.issuers))
|
|
181
|
+
bad("resolve the \"x1id-recommended\" alias first (resolveRecommendedIssuers)", g);
|
|
182
|
+
const hit = credentials.credentialsFor(c).find((h) => h.validity.valid && c.issuers.includes(h.credential.issuer));
|
|
183
|
+
if (hit)
|
|
184
|
+
matched.push(`credential:${hit.credential.issuer}:${c.schema}`);
|
|
185
|
+
return hit !== undefined;
|
|
186
|
+
}
|
|
187
|
+
if ("allOf" in g)
|
|
188
|
+
return g.allOf.map(evalNode).every(Boolean);
|
|
189
|
+
if (g.anyOf.every((x) => typeof x === "number"))
|
|
190
|
+
return kinds(g.anyOf);
|
|
191
|
+
return g.anyOf.map(evalNode).some(Boolean);
|
|
192
|
+
};
|
|
193
|
+
const kinds = (ks) => {
|
|
194
|
+
const hit = attestations.find((a) => !a.stale && !a.holderMismatch && ks.includes(a.kind));
|
|
195
|
+
if (hit)
|
|
196
|
+
matched.push(`kind:${hit.kind}`);
|
|
197
|
+
return hit !== undefined;
|
|
198
|
+
};
|
|
199
|
+
return { passed: evalNode(gate), matched };
|
|
200
|
+
}
|
|
28
201
|
/** Pure check: do these (already-fetched) attestations satisfy the gate?
|
|
29
|
-
* Stale and holder-mismatched (H5) attestations never count.
|
|
202
|
+
* Stale and holder-mismatched (H5) attestations never count. A gate with a
|
|
203
|
+
* credential clause throws here: use {@link evaluateGate} with credentials. */
|
|
30
204
|
export function attestationsPassGate(attestations, gate) {
|
|
31
205
|
if (gate === "any-verified")
|
|
32
206
|
return isHandleVerified(attestations);
|
|
@@ -36,11 +210,10 @@ export function attestationsPassGate(attestations, gate) {
|
|
|
36
210
|
if (gate === null || typeof gate !== "object") {
|
|
37
211
|
throw new ResolveError("invalid-input", 'gate must be "any-verified", { kind } or { anyOf: [...] }', String(gate));
|
|
38
212
|
}
|
|
39
|
-
|
|
40
|
-
if (kinds === null) {
|
|
213
|
+
if (!("kind" in gate) && !("anyOf" in gate) && !("allOf" in gate) && !("credential" in gate)) {
|
|
41
214
|
throw new ResolveError("invalid-input", "gate object needs a `kind` or `anyOf`", JSON.stringify(gate));
|
|
42
215
|
}
|
|
43
|
-
return attestations
|
|
216
|
+
return evaluateGate(gate, attestations).passed;
|
|
44
217
|
}
|
|
45
218
|
/** Fetch a handle's attestations and test the gate in one call. `handleAccount`,
|
|
46
219
|
* `registeredAt`, `recordsClearedAt` and `holderEpoch` come from the handle you
|
|
@@ -48,8 +221,34 @@ export function attestationsPassGate(attestations, gate) {
|
|
|
48
221
|
* #466, 0 if absent) folds into the staleness epoch so the gate matches the
|
|
49
222
|
* on-chain rule `attested_at >= max(registered_at, holder_epoch)`; it defaults
|
|
50
223
|
* to `0n` for backward compatibility. Returns the pass/fail plus the
|
|
51
|
-
* attestations so a caller can also render WHICH signals matched.
|
|
52
|
-
|
|
224
|
+
* attestations so a caller can also render WHICH signals matched.
|
|
225
|
+
*
|
|
226
|
+
* A gate with credential clauses also needs `credentialOpts` (the PDA
|
|
227
|
+
* finder and the current holder); its credentials are read from the chain
|
|
228
|
+
* (derived PDAs, one `getMultipleAccounts` per clause) and returned too. */
|
|
229
|
+
export async function handlePassesGate(rpc, programId, handleAccount, registeredAt, recordsClearedAt, gate, holderEpoch = 0n, credentialOpts) {
|
|
230
|
+
validateGate(gate);
|
|
53
231
|
const attestations = await fetchAttestations(rpc, programId, handleAccount, registeredAt, recordsClearedAt, holderEpoch);
|
|
54
|
-
|
|
232
|
+
const clauses = credentialClauses(gate);
|
|
233
|
+
if (clauses.length === 0)
|
|
234
|
+
return { passed: attestationsPassGate(attestations, gate), attestations };
|
|
235
|
+
if (!credentialOpts) {
|
|
236
|
+
throw new ResolveError("invalid-input", "a credential gate needs credentialOpts { find, currentHolder }", JSON.stringify(gate));
|
|
237
|
+
}
|
|
238
|
+
const needsList = clauses.some((c) => !Array.isArray(c.issuers));
|
|
239
|
+
const list = needsList ? (credentialOpts.recommendedIssuers ?? (await fetchRecommendedIssuers(rpc, credentialOpts.find, programId))) : [];
|
|
240
|
+
const resolved = needsList ? resolveRecommendedIssuers(gate, list, { resolveLive: true }) : gate;
|
|
241
|
+
const now = credentialOpts.nowSecs ?? BigInt(Math.floor(Date.now() / 1000));
|
|
242
|
+
const ctx = {
|
|
243
|
+
handle: handleAccount,
|
|
244
|
+
registeredAt,
|
|
245
|
+
holderEpoch,
|
|
246
|
+
currentHolder: credentialOpts.currentHolder,
|
|
247
|
+
};
|
|
248
|
+
const found = new Map();
|
|
249
|
+
for (const c of credentialClauses(resolved)) {
|
|
250
|
+
found.set(c, await fetchHandleCredentials(rpc, credentialOpts.find, programId, ctx, c.schema, c.issuers, now, c.minRemainingSecs ?? 0));
|
|
251
|
+
}
|
|
252
|
+
const ev = evaluateGate(resolved, attestations, { credentialsFor: (c) => found.get(c) ?? [] });
|
|
253
|
+
return { passed: ev.passed, attestations, credentials: [...found.values()].flat(), matched: ev.matched };
|
|
55
254
|
}
|
package/dist/gateClient.d.ts
CHANGED
|
@@ -41,6 +41,16 @@ export interface GateAttestationView {
|
|
|
41
41
|
readonly kind: number;
|
|
42
42
|
readonly attested_at: number;
|
|
43
43
|
}
|
|
44
|
+
/** One third-party credential the decision looked at. */
|
|
45
|
+
export interface GateCredentialView {
|
|
46
|
+
readonly issuer: string;
|
|
47
|
+
readonly schema: number;
|
|
48
|
+
readonly subject: string;
|
|
49
|
+
readonly issued_at: number;
|
|
50
|
+
readonly expires_at: number;
|
|
51
|
+
readonly valid: boolean;
|
|
52
|
+
readonly invalid_reasons: readonly string[];
|
|
53
|
+
}
|
|
44
54
|
/** The decision the service returned. */
|
|
45
55
|
export interface GateCheckResult {
|
|
46
56
|
readonly passed: boolean;
|
|
@@ -50,6 +60,8 @@ export interface GateCheckResult {
|
|
|
50
60
|
};
|
|
51
61
|
readonly policy: Gate;
|
|
52
62
|
readonly attestations: readonly GateAttestationView[];
|
|
63
|
+
/** Credentials read for a policy with `{ credential }` clauses (upgrade 6). */
|
|
64
|
+
readonly credentials?: readonly GateCredentialView[];
|
|
53
65
|
readonly reason?: "no-primary-handle" | "handle-not-registered";
|
|
54
66
|
}
|
|
55
67
|
/** Thrown when the decision could not be obtained (network, auth, 5xx, bad
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open gift links (docs/specs/gift-links.md): send XNT or a prepaid `@name` to
|
|
3
|
+
* whoever opens a link. Instruction builders, the `GiftLink` decoder, the PDA
|
|
4
|
+
* finder and the client helpers that make / parse the link itself.
|
|
5
|
+
*
|
|
6
|
+
* # How it works
|
|
7
|
+
*
|
|
8
|
+
* 1. The sender's client generates a fresh EPHEMERAL ed25519 keypair
|
|
9
|
+
* ({@link newGiftLinkKey}). Its public key is the `gift_key`; its secret
|
|
10
|
+
* goes ONLY into the link's URL fragment ({@link giftLinkUrl}):
|
|
11
|
+
* `https://app.x1id.io/gift/link#k=<base58 64-byte secret key>`. A fragment
|
|
12
|
+
* is never sent to a server.
|
|
13
|
+
* 2. `create_gift_link` (sender + gift key sign) escrows the value under
|
|
14
|
+
* `["gift", gift_key]` ({@link findGiftLinkPda}).
|
|
15
|
+
* 3. The recipient opens the link ({@link parseGiftLinkUrl}) and submits
|
|
16
|
+
* `claim_gift_link` (XNT) or `claim_gift_link_name` (a name, minted as a
|
|
17
|
+
* pNFT) SIGNED BY THE GIFT KEY, naming their own wallet as destination.
|
|
18
|
+
* Any wallet may pay the fee (a relayer works). Because the destination is
|
|
19
|
+
* part of the gift-key-signed message, nobody who sees the claim in flight
|
|
20
|
+
* can redirect it (unlike the removed open vouchers, audit S6).
|
|
21
|
+
* 4. Unclaimed: the sender may cancel ({@link buildRefundGiftLinkIx}) any time;
|
|
22
|
+
* after `expiresAt` anyone may return it to the sender.
|
|
23
|
+
*
|
|
24
|
+
* Whoever holds the link can claim the gift: treat it like cash. Never reuse a
|
|
25
|
+
* gift key (generate one per link).
|
|
26
|
+
*
|
|
27
|
+
* Routed through the program's `fallback` (`extra_ix`): `sha256("global:<name>")
|
|
28
|
+
* [..8]` + raw Borsh, accounts exactly in the order of the program's
|
|
29
|
+
* `Accounts` structs. Hand-rolled, no web3.js. Key generation uses WebCrypto
|
|
30
|
+
* Ed25519 (Node 20+, current browsers); pass your own key if unavailable.
|
|
31
|
+
*/
|
|
32
|
+
import type { AddressLike, BuiltInstruction, InstructionKey } from "./delegate.js";
|
|
33
|
+
import type { RpcFn } from "./accounts.js";
|
|
34
|
+
import type { PdaFinder } from "./namespacePricing.js";
|
|
35
|
+
import { type TokenizedTailAccounts } from "./mintNft.js";
|
|
36
|
+
import { type HandleTypeValue } from "./voucher.js";
|
|
37
|
+
/** Seed prefix of the escrow PDA: `["gift", gift_key]`. */
|
|
38
|
+
export declare const GIFT_LINK_SEED = "gift";
|
|
39
|
+
/** Allocated size of a `GiftLink` (8-byte discriminator + `INIT_SPACE`). */
|
|
40
|
+
export declare const GIFT_LINK_ACCOUNT_LEN: number;
|
|
41
|
+
/** Longest a gift link may stay open (same cap as vouchers: 366 days). */
|
|
42
|
+
export declare const MAX_GIFT_LINK_DURATION_SECS: number;
|
|
43
|
+
/** Where the app opens gift links. The secret goes after `#k=`. */
|
|
44
|
+
export declare const GIFT_LINK_BASE_URL = "https://app.x1id.io/gift/link";
|
|
45
|
+
/** A sensible client default for `expiresAt`: 30 days. */
|
|
46
|
+
export declare const DEFAULT_GIFT_LINK_TTL_SECS: number;
|
|
47
|
+
/** Compute-unit limit to request for `claim_gift_link_name` (measured
|
|
48
|
+
* ~307k on litesvm with the real Metaplex program; same headroom as
|
|
49
|
+
* `REGISTER_TOKENIZED_CU_LIMIT`). */
|
|
50
|
+
export declare const CLAIM_GIFT_LINK_NAME_CU_LIMIT = 420000;
|
|
51
|
+
/** `GiftLink.kind` (Borsh enum index). */
|
|
52
|
+
export declare const GIFT_KIND: {
|
|
53
|
+
readonly Xnt: 0;
|
|
54
|
+
readonly Name: 1;
|
|
55
|
+
};
|
|
56
|
+
export type GiftKindName = "xnt" | "name";
|
|
57
|
+
/** `sha256("global:create_gift_link")[..8]`. */
|
|
58
|
+
export declare const CREATE_GIFT_LINK_DISCRIMINATOR: Uint8Array;
|
|
59
|
+
/** `sha256("global:claim_gift_link")[..8]`. */
|
|
60
|
+
export declare const CLAIM_GIFT_LINK_DISCRIMINATOR: Uint8Array;
|
|
61
|
+
/** `sha256("global:claim_gift_link_name")[..8]`. */
|
|
62
|
+
export declare const CLAIM_GIFT_LINK_NAME_DISCRIMINATOR: Uint8Array;
|
|
63
|
+
/** `sha256("global:refund_gift_link")[..8]`. */
|
|
64
|
+
export declare const REFUND_GIFT_LINK_DISCRIMINATOR: Uint8Array;
|
|
65
|
+
/** `sha256("account:GiftLink")[..8]`. */
|
|
66
|
+
export declare const GIFT_LINK_ACCOUNT_DISCRIMINATOR: Uint8Array;
|
|
67
|
+
/** Byte offsets inside a raw `GiftLink` (fixed up to `integrator`), for
|
|
68
|
+
* `getProgramAccounts` `memcmp` filters (e.g. a sender's open links). */
|
|
69
|
+
export declare const GIFT_LINK_OFFSETS: {
|
|
70
|
+
readonly version: 8;
|
|
71
|
+
readonly sender: 9;
|
|
72
|
+
readonly giftKey: 41;
|
|
73
|
+
readonly kind: 73;
|
|
74
|
+
readonly amount: 74;
|
|
75
|
+
readonly name: 82;
|
|
76
|
+
readonly nameLen: 114;
|
|
77
|
+
readonly handleType: 115;
|
|
78
|
+
readonly integrator: 116;
|
|
79
|
+
};
|
|
80
|
+
/** Program error codes added for gift links (`RegistryError`). Gift links
|
|
81
|
+
* also reuse `VoucherNameRegistered` (6057), `BadVoucherExpiry` (6058),
|
|
82
|
+
* `PriceBelowRent` (6086), `ProtocolLockedDown` (6102) and
|
|
83
|
+
* `VoucherExpiryTooFar` (6112). */
|
|
84
|
+
export declare const GIFT_LINK_ERRORS: {
|
|
85
|
+
readonly GiftAmountInvalid: 6151;
|
|
86
|
+
readonly GiftLinkExpired: 6152;
|
|
87
|
+
readonly GiftLinkWrongKind: 6153;
|
|
88
|
+
readonly GiftLinkBadDestination: 6154;
|
|
89
|
+
readonly GiftLinkNotRefundable: 6155;
|
|
90
|
+
readonly GiftLinkNameReserved: 6156;
|
|
91
|
+
/** `gift_key == sender` (Sentinel run-011; 6158-6229 are upgrade 6's). */
|
|
92
|
+
readonly GiftLinkKeyIsSender: 6231;
|
|
93
|
+
};
|
|
94
|
+
/** An ephemeral gift key: `secretKey` is the 64-byte Solana form (32-byte
|
|
95
|
+
* seed ‖ 32-byte public key), so `Keypair.fromSecretKey(secretKey)` (web3.js)
|
|
96
|
+
* signs the claim directly. */
|
|
97
|
+
export interface GiftLinkKey {
|
|
98
|
+
/** base58 public key = the `gift_key`. */
|
|
99
|
+
readonly giftKey: string;
|
|
100
|
+
readonly secretKey: Uint8Array;
|
|
101
|
+
}
|
|
102
|
+
/** Derive the ed25519 public key of a 32-byte seed (WebCrypto). */
|
|
103
|
+
export declare function giftKeyFromSeed(seed: Uint8Array): Promise<GiftLinkKey>;
|
|
104
|
+
/**
|
|
105
|
+
* Generate a fresh ephemeral gift key (CSPRNG seed, WebCrypto Ed25519). One
|
|
106
|
+
* per link; never reuse it.
|
|
107
|
+
*/
|
|
108
|
+
export declare function newGiftLinkKey(): Promise<GiftLinkKey>;
|
|
109
|
+
/** The shareable link: `<base>#k=<base58 64-byte secret key>`. The secret is
|
|
110
|
+
* in the FRAGMENT so it never reaches a server log. */
|
|
111
|
+
export declare function giftLinkUrl(key: Pick<GiftLinkKey, "secretKey">, base?: string): string;
|
|
112
|
+
/**
|
|
113
|
+
* Read the gift key back out of a link (or a bare `#k=...` fragment). Accepts
|
|
114
|
+
* the 64-byte secret key (what {@link giftLinkUrl} writes) or a 32-byte seed.
|
|
115
|
+
* Re-derives the public key (WebCrypto) and, for the 64-byte form, refuses a
|
|
116
|
+
* secret whose embedded public key does not match its seed. Null when the
|
|
117
|
+
* link has no well-formed key.
|
|
118
|
+
*/
|
|
119
|
+
export declare function parseGiftLinkUrl(link: string): Promise<GiftLinkKey | null>;
|
|
120
|
+
/** The escrow: `["gift", gift_key]`. */
|
|
121
|
+
export declare function findGiftLinkPda(find: PdaFinder, programId: AddressLike, giftKey: AddressLike): Promise<string>;
|
|
122
|
+
/** Decoded `GiftLink`. Addresses are base58. */
|
|
123
|
+
export interface GiftLink {
|
|
124
|
+
readonly version: number;
|
|
125
|
+
readonly sender: string;
|
|
126
|
+
readonly giftKey: string;
|
|
127
|
+
readonly kind: GiftKindName;
|
|
128
|
+
/** XNT: lamports paid out. Name: the escrowed price snapshot. */
|
|
129
|
+
readonly amount: bigint;
|
|
130
|
+
/** Name gifts only; "" for XNT. */
|
|
131
|
+
readonly name: string;
|
|
132
|
+
readonly handleType: number;
|
|
133
|
+
readonly integrator: string | null;
|
|
134
|
+
readonly integratorRateBps: number;
|
|
135
|
+
readonly expiresAt: bigint;
|
|
136
|
+
readonly createdAt: bigint;
|
|
137
|
+
readonly bump: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Decode a raw `GiftLink` (discriminator included) in the Borsh order of
|
|
141
|
+
* state.rs: version u8 | sender | gift_key | kind u8 | amount u64 |
|
|
142
|
+
* name [u8;32] | name_len u8 | handle_type u8 | integrator Option<Pubkey> |
|
|
143
|
+
* integrator_rate_bps u16 | expires_at i64 | created_at i64 | bump u8.
|
|
144
|
+
* Null when the bytes are not a `GiftLink`.
|
|
145
|
+
*/
|
|
146
|
+
export declare function decodeGiftLink(data: Uint8Array): GiftLink | null;
|
|
147
|
+
/** Fetch + decode a gift link by its escrow address (null if absent: never
|
|
148
|
+
* created, or already claimed / refunded). */
|
|
149
|
+
export declare function fetchGiftLink(rpc: RpcFn, address: AddressLike, opts?: {
|
|
150
|
+
readonly programId?: AddressLike;
|
|
151
|
+
readonly commitment?: string;
|
|
152
|
+
}): Promise<{
|
|
153
|
+
readonly address: string;
|
|
154
|
+
readonly gift: GiftLink;
|
|
155
|
+
readonly lamports: bigint;
|
|
156
|
+
} | null>;
|
|
157
|
+
/** `now >= expiresAt`: claims fail, anyone may refund to the sender. */
|
|
158
|
+
export declare function isGiftLinkExpired(g: Pick<GiftLink, "expiresAt">, nowSecs: bigint | number): boolean;
|
|
159
|
+
/** The Borsh arguments of `create_gift_link` (after the discriminator):
|
|
160
|
+
* `kind u8, amount u64, name String, handle_type u8, expires_at i64`. */
|
|
161
|
+
export declare function encodeCreateGiftLinkArgs(a: {
|
|
162
|
+
readonly kind: GiftKindName;
|
|
163
|
+
readonly amount: bigint;
|
|
164
|
+
readonly name: string;
|
|
165
|
+
readonly handleType: number;
|
|
166
|
+
readonly expiresAt: bigint;
|
|
167
|
+
}): Uint8Array;
|
|
168
|
+
interface CreateGiftLinkBase {
|
|
169
|
+
readonly programId: AddressLike;
|
|
170
|
+
/** Signer; funds the escrow + rent and receives refunds. */
|
|
171
|
+
readonly sender: AddressLike;
|
|
172
|
+
/** Signer; the ephemeral gift key's PUBLIC key ({@link newGiftLinkKey}). */
|
|
173
|
+
readonly giftKey: AddressLike;
|
|
174
|
+
/** `["config"]`. */
|
|
175
|
+
readonly config: AddressLike;
|
|
176
|
+
/** {@link findGiftLinkPda}(giftKey). */
|
|
177
|
+
readonly gift: AddressLike;
|
|
178
|
+
/** Unix seconds; in the future and at most {@link MAX_GIFT_LINK_DURATION_SECS} ahead. */
|
|
179
|
+
readonly expiresAt: bigint;
|
|
180
|
+
}
|
|
181
|
+
export interface CreateXntGiftLinkParams extends CreateGiftLinkBase {
|
|
182
|
+
readonly kind: "xnt";
|
|
183
|
+
/** Lamports; at least the rent-exempt minimum of an empty account
|
|
184
|
+
* (890 880 on X1), else `GiftAmountInvalid` (6151). */
|
|
185
|
+
readonly amount: bigint;
|
|
186
|
+
}
|
|
187
|
+
export interface CreateNameGiftLinkParams extends CreateGiftLinkBase {
|
|
188
|
+
readonly kind: "name";
|
|
189
|
+
/** Canonical bare name (no `@`), unregistered, no pending voucher. */
|
|
190
|
+
readonly name: string;
|
|
191
|
+
readonly handleType: HandleTypeValue;
|
|
192
|
+
/** `["handle", name]`. */
|
|
193
|
+
readonly handle: AddressLike;
|
|
194
|
+
/** `["voucher", name]`. */
|
|
195
|
+
readonly voucher: AddressLike;
|
|
196
|
+
/** Optional integrator pair (integrator.ts `integratorAccountsForCreateVoucher`). */
|
|
197
|
+
readonly integratorAccounts?: readonly InstructionKey[];
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* `create_gift_link(kind, amount, name, handle_type, expires_at)`. Accounts
|
|
201
|
+
* (`CreateGiftLink`): sender(s,w), gift_key(s), config, gift(w),
|
|
202
|
+
* system_program, then (name gifts) handle, voucher and the optional
|
|
203
|
+
* integrator pair. A name gift's escrow is priced by the program (the live
|
|
204
|
+
* price snapshot); `amount` is sent as 0.
|
|
205
|
+
*/
|
|
206
|
+
export declare function buildCreateGiftLinkIx(p: CreateXntGiftLinkParams | CreateNameGiftLinkParams): BuiltInstruction;
|
|
207
|
+
export interface ClaimGiftLinkParams {
|
|
208
|
+
readonly programId: AddressLike;
|
|
209
|
+
/** Signer: the gift key from the link. */
|
|
210
|
+
readonly giftKey: AddressLike;
|
|
211
|
+
/** `["config"]`. */
|
|
212
|
+
readonly config: AddressLike;
|
|
213
|
+
/** {@link findGiftLinkPda}(giftKey). */
|
|
214
|
+
readonly gift: AddressLike;
|
|
215
|
+
/** `GiftLink.sender` (receives the escrow's rent). */
|
|
216
|
+
readonly sender: AddressLike;
|
|
217
|
+
/** The recipient's wallet: gets exactly `GiftLink.amount` lamports. */
|
|
218
|
+
readonly destination: AddressLike;
|
|
219
|
+
}
|
|
220
|
+
/** `claim_gift_link()` (XNT gifts). Accounts (`ClaimGiftLink`): gift_key(s),
|
|
221
|
+
* config, gift(w), sender(w), destination(w). The fee payer is whoever
|
|
222
|
+
* submits (not an account of this instruction). */
|
|
223
|
+
export declare function buildClaimGiftLinkIx(p: ClaimGiftLinkParams): BuiltInstruction;
|
|
224
|
+
export interface ClaimGiftLinkNameParams extends TokenizedTailAccounts {
|
|
225
|
+
readonly programId: AddressLike;
|
|
226
|
+
/** Signer; fronts the tx fee and every new account's rent (the rent is
|
|
227
|
+
* reimbursed from the escrow). May be a relayer. */
|
|
228
|
+
readonly claimer: AddressLike;
|
|
229
|
+
/** Signer: the gift key from the link. */
|
|
230
|
+
readonly giftKey: AddressLike;
|
|
231
|
+
/** `["config"]`. */
|
|
232
|
+
readonly config: AddressLike;
|
|
233
|
+
/** `Config.treasury`. */
|
|
234
|
+
readonly treasury: AddressLike;
|
|
235
|
+
/** {@link findGiftLinkPda}(giftKey). */
|
|
236
|
+
readonly gift: AddressLike;
|
|
237
|
+
/** `GiftLink.sender`. */
|
|
238
|
+
readonly sender: AddressLike;
|
|
239
|
+
/** The destination wallet: owns the name and its pNFT. The tail's
|
|
240
|
+
* `ownerTokenAccount` / `tokenRecord` derive against THIS address
|
|
241
|
+
* (`deriveTokenizedNftAccounts(find, { programId, owner, handle })`). */
|
|
242
|
+
readonly owner: AddressLike;
|
|
243
|
+
/** `["handle", name]`. */
|
|
244
|
+
readonly handle: AddressLike;
|
|
245
|
+
/** `GiftLink.name`. */
|
|
246
|
+
readonly name: string;
|
|
247
|
+
/** REQUIRED iff `GiftLink.integrator` is set (must equal it). */
|
|
248
|
+
readonly integrator?: AddressLike;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* `claim_gift_link_name(name)` (name gifts): registers the name to `owner` as
|
|
252
|
+
* a tokenized pNFT, exactly like `claim_voucher_tokenized`. Accounts
|
|
253
|
+
* (`ClaimGiftLinkName`): claimer(s,w), gift_key(s), config(w), treasury(w),
|
|
254
|
+
* gift(w), sender(w), owner, handle(w), then the 14-account pNFT tail, then
|
|
255
|
+
* the optional integrator(w). Prepend a ComputeBudget
|
|
256
|
+
* `SetComputeUnitLimit(CLAIM_GIFT_LINK_NAME_CU_LIMIT)`.
|
|
257
|
+
*/
|
|
258
|
+
export declare function buildClaimGiftLinkNameIx(p: ClaimGiftLinkNameParams): BuiltInstruction;
|
|
259
|
+
export interface RefundGiftLinkParams {
|
|
260
|
+
readonly programId: AddressLike;
|
|
261
|
+
/** Signer: the sender (any time) or anyone (at/after `expiresAt`). */
|
|
262
|
+
readonly caller: AddressLike;
|
|
263
|
+
readonly gift: AddressLike;
|
|
264
|
+
/** `GiftLink.sender`: receives escrow + rent. */
|
|
265
|
+
readonly sender: AddressLike;
|
|
266
|
+
}
|
|
267
|
+
/** `refund_gift_link()`. Accounts (`RefundGiftLink`): caller(s), gift(w),
|
|
268
|
+
* sender(w). */
|
|
269
|
+
export declare function buildRefundGiftLinkIx(p: RefundGiftLinkParams): BuiltInstruction;
|
|
270
|
+
/** Plain-language sentence for a gift-link error code (6151-6156, 6231), or null. */
|
|
271
|
+
export declare function giftLinkErrorMessage(code: number): string | null;
|
|
272
|
+
export {};
|