phygital-token-mcp 0.1.1

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.
Files changed (40) hide show
  1. package/README.md +59 -0
  2. package/cursor-mcp.example.json +8 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +481 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/docs.d.ts +17 -0
  7. package/dist/lib/docs.js +121 -0
  8. package/dist/lib/docs.js.map +1 -0
  9. package/dist/lib/format.d.ts +13 -0
  10. package/dist/lib/format.js +12 -0
  11. package/dist/lib/format.js.map +1 -0
  12. package/dist/lib/gating-json.d.ts +127 -0
  13. package/dist/lib/gating-json.js +346 -0
  14. package/dist/lib/gating-json.js.map +1 -0
  15. package/dist/lib/graphify.d.ts +2 -0
  16. package/dist/lib/graphify.js +35 -0
  17. package/dist/lib/graphify.js.map +1 -0
  18. package/dist/lib/instructions.d.ts +131 -0
  19. package/dist/lib/instructions.js +232 -0
  20. package/dist/lib/instructions.js.map +1 -0
  21. package/dist/lib/paths.d.ts +14 -0
  22. package/dist/lib/paths.js +77 -0
  23. package/dist/lib/paths.js.map +1 -0
  24. package/dist/lib/rpc.d.ts +3 -0
  25. package/dist/lib/rpc.js +22 -0
  26. package/dist/lib/rpc.js.map +1 -0
  27. package/dist/lib/sdk-surface.d.ts +33 -0
  28. package/dist/lib/sdk-surface.js +101 -0
  29. package/dist/lib/sdk-surface.js.map +1 -0
  30. package/dist/lib/verification.d.ts +43 -0
  31. package/dist/lib/verification.js +166 -0
  32. package/dist/lib/verification.js.map +1 -0
  33. package/docs/building-on-phygital/overview.md +46 -0
  34. package/docs/building-on-phygital/rust-cpi.md +55 -0
  35. package/docs/glossary.md +43 -0
  36. package/docs/sdk/surface-area.md +77 -0
  37. package/docs/verification/methods.md +58 -0
  38. package/docs/verification/overview.md +70 -0
  39. package/docs/verification/verify-asset-composable.md +97 -0
  40. package/package.json +52 -0
@@ -0,0 +1,101 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { pathExists, resolveRustVerifyAssetPath, resolveVerifyAssetTsPath, resolveVerifyTsPath, } from "./paths.js";
3
+ export const SDK_SURFACE = {
4
+ mint: [
5
+ "buildCreateMintInstructions",
6
+ "buildMintTokenInstructions",
7
+ "parseSecp256r1Pubkey",
8
+ "parseCredentialId",
9
+ "validateMetadataFields",
10
+ ],
11
+ transfer: [
12
+ "beginTransfer",
13
+ "authenticatePasskeyForTransfer",
14
+ "completeTransfer",
15
+ ],
16
+ verifyAssetComposable: [
17
+ "beginVerifyAsset",
18
+ "authenticatePasskeyForVerifyAsset",
19
+ "buildVerifyAssetArgs",
20
+ "completeVerifyAsset",
21
+ ],
22
+ verification: [
23
+ "verifyDynamicUrl",
24
+ "verifyDynamicUrlWithoutCounterCheck",
25
+ "verifyWithChallengeResponse",
26
+ "verifyWithChallengeResponseOverNfc",
27
+ ],
28
+ onChainComposition: {
29
+ patternA_inspect: {
30
+ client: ["beginVerifyAsset", "completeVerifyAsset"],
31
+ transaction: ["secp256r1_verify", "verify_asset", "your_program_ix"],
32
+ program: "inspect instructions sysvar for verify_asset message",
33
+ },
34
+ patternB_cpi: {
35
+ client: ["beginVerifyAsset", "buildVerifyAssetArgs"],
36
+ transaction: ["secp256r1_verify", "your_program_ix"],
37
+ program: "CPI verify_asset via VerifyAssetCpiBuilder",
38
+ },
39
+ },
40
+ assetLookup: [
41
+ "findAssetPda",
42
+ "fetchAssetFromCredentialId",
43
+ "fetchAllAssetsFromOwner",
44
+ "fetchAssetDisplayInfo",
45
+ "resolveMedia",
46
+ ],
47
+ gating: [
48
+ "Gating",
49
+ "GatingTraitValue",
50
+ "formatGatingPredicate",
51
+ "summarizeGatingEvaluationFailure",
52
+ "summarizeGatingFailure",
53
+ "summarizeGatingTierFailure",
54
+ "evaluateAssetGating",
55
+ ],
56
+ gatingTypes: [
57
+ "EvaluateAssetGatingOptions",
58
+ "GatingFilter",
59
+ "GatingAssetPredicate",
60
+ "GatingTier",
61
+ "GatingEvaluationResult",
62
+ "GatingFilterResult",
63
+ "GatingTierEvaluationResult",
64
+ "GatingTiersEvaluationResult",
65
+ ],
66
+ generated: [
67
+ "getCreateMintInstructionAsync",
68
+ "getMintTokenInstructionAsync",
69
+ "getExecuteTransferInstructionAsync",
70
+ "getVerifyAssetInstruction",
71
+ "getSetLockStateInstruction",
72
+ "fetchAsset",
73
+ "findProgramAuthorityPda",
74
+ "PHYGITAL_TOKEN_PROGRAM_ADDRESS",
75
+ ],
76
+ rustClient: {
77
+ crate: "phygital-token-client",
78
+ path: "clients/rust/phygital-token",
79
+ features: ["anchor", "fetch"],
80
+ cpi: ["VerifyAssetCpi", "VerifyAssetCpiBuilder", "VerifyAssetInstructionArgs"],
81
+ types: ["Asset", "Secp256r1VerifyArgs", "AssetType"],
82
+ },
83
+ };
84
+ export async function readSourceExcerpt(which, maxLines = 120) {
85
+ const paths = {
86
+ "verify.ts": resolveVerifyTsPath(),
87
+ "verifyAsset.ts": resolveVerifyAssetTsPath(),
88
+ "rust_verify_asset.rs": resolveRustVerifyAssetPath(),
89
+ };
90
+ const filePath = paths[which];
91
+ if (!(await pathExists(filePath))) {
92
+ throw new Error(`Source file not found: ${filePath}. Set PHYGITAL_TOKEN_REPO_ROOT to a cloned phygital-token repo to use read_sdk_source.`);
93
+ }
94
+ const content = await readFile(filePath, "utf8");
95
+ const lines = content.split("\n").slice(0, maxLines);
96
+ return {
97
+ path: filePath,
98
+ excerpt: lines.join("\n") + (content.split("\n").length > maxLines ? "\n// ..." : ""),
99
+ };
100
+ }
101
+ //# sourceMappingURL=sdk-surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-surface.js","sourceRoot":"","sources":["../../src/lib/sdk-surface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ export type VerificationUseCase = "product_page_lookup" | "deep_link_from_prior_scan" | "offline_identification" | "login_ui_only" | "onchain_standalone_verify" | "onchain_inspect_verify_asset" | "onchain_cpi_verify_asset" | "transfer_ownership" | "wallet_holdings_gate" | "native_mobile_app";
2
+ export type OnChainCompositionPattern = "inspect" | "cpi" | "standalone";
3
+ export type VerificationRecommendation = {
4
+ method: string;
5
+ sdkExports: string[];
6
+ requiresTap: boolean;
7
+ onChain: boolean;
8
+ onChainPattern?: OnChainCompositionPattern;
9
+ rationale: string;
10
+ docIds: string[];
11
+ cautions?: string[];
12
+ };
13
+ export declare const ON_CHAIN_PATTERNS: {
14
+ readonly inspect: {
15
+ readonly id: "inspect";
16
+ readonly name: "Pattern A — client posts verify_asset, program inspects";
17
+ readonly clientTransaction: readonly ["secp256r1_verify", "verify_asset", "your_program_ix"];
18
+ readonly clientSdk: readonly ["beginVerifyAsset", "completeVerifyAsset", "getVerifyAssetInstruction"];
19
+ readonly programRust: "Scan instructions sysvar for preceding verify_asset; check message bytes";
20
+ readonly reference: "programs/phygital-spend";
21
+ };
22
+ readonly cpi: {
23
+ readonly id: "cpi";
24
+ readonly name: "Pattern B — client posts secp256r1_verify, program CPIs verify_asset";
25
+ readonly clientTransaction: readonly ["secp256r1_verify", "your_program_ix"];
26
+ readonly clientSdk: readonly ["beginVerifyAsset", "buildVerifyAssetArgs"];
27
+ readonly programRust: "VerifyAssetCpiBuilder from phygital-token-client";
28
+ readonly reference: "clients/rust/phygital-token";
29
+ };
30
+ readonly standalone: {
31
+ readonly id: "standalone";
32
+ readonly name: "Standalone on-chain verify_asset (no custom program)";
33
+ readonly clientTransaction: readonly ["secp256r1_verify", "verify_asset"];
34
+ readonly clientSdk: readonly ["beginVerifyAsset", "completeVerifyAsset"];
35
+ readonly programRust: "N/A";
36
+ };
37
+ };
38
+ export declare function recommendVerification(useCase: VerificationUseCase): VerificationRecommendation;
39
+ export declare function listVerificationUseCases(): Array<{
40
+ id: VerificationUseCase;
41
+ summary: string;
42
+ }>;
43
+ export declare const VERIFICATION_DECISION_TREE: string;
@@ -0,0 +1,166 @@
1
+ export const ON_CHAIN_PATTERNS = {
2
+ inspect: {
3
+ id: "inspect",
4
+ name: "Pattern A — client posts verify_asset, program inspects",
5
+ clientTransaction: ["secp256r1_verify", "verify_asset", "your_program_ix"],
6
+ clientSdk: ["beginVerifyAsset", "completeVerifyAsset", "getVerifyAssetInstruction"],
7
+ programRust: "Scan instructions sysvar for preceding verify_asset; check message bytes",
8
+ reference: "programs/phygital-spend",
9
+ },
10
+ cpi: {
11
+ id: "cpi",
12
+ name: "Pattern B — client posts secp256r1_verify, program CPIs verify_asset",
13
+ clientTransaction: ["secp256r1_verify", "your_program_ix"],
14
+ clientSdk: ["beginVerifyAsset", "buildVerifyAssetArgs"],
15
+ programRust: "VerifyAssetCpiBuilder from phygital-token-client",
16
+ reference: "clients/rust/phygital-token",
17
+ },
18
+ standalone: {
19
+ id: "standalone",
20
+ name: "Standalone on-chain verify_asset (no custom program)",
21
+ clientTransaction: ["secp256r1_verify", "verify_asset"],
22
+ clientSdk: ["beginVerifyAsset", "completeVerifyAsset"],
23
+ programRust: "N/A",
24
+ },
25
+ };
26
+ const RECOMMENDATIONS = {
27
+ product_page_lookup: {
28
+ method: "identification — verifyDynamicUrl",
29
+ sdkExports: ["verifyDynamicUrl"],
30
+ requiresTap: false,
31
+ onChain: false,
32
+ rationale: "User already scanned; signed URL params identify the asset without a second tap.",
33
+ docIds: ["verification:methods", "verification:overview"],
34
+ },
35
+ deep_link_from_prior_scan: {
36
+ method: "identification — verifyDynamicUrl",
37
+ sdkExports: ["verifyDynamicUrl"],
38
+ requiresTap: false,
39
+ onChain: false,
40
+ rationale: "Signed deep-link params from an earlier tap.",
41
+ docIds: ["verification:methods"],
42
+ },
43
+ offline_identification: {
44
+ method: "identification — verifyDynamicUrlWithoutCounterCheck",
45
+ sdkExports: ["verifyDynamicUrlWithoutCounterCheck"],
46
+ requiresTap: false,
47
+ onChain: false,
48
+ rationale: "Local signature check only. Not for authorization.",
49
+ docIds: ["verification:methods"],
50
+ cautions: ["Copied links can be replayed."],
51
+ },
52
+ login_ui_only: {
53
+ method: "authentication off-chain — verifyWithChallengeResponse",
54
+ sdkExports: ["verifyWithChallengeResponse", "verifyWithChallengeResponseOverNfc"],
55
+ requiresTap: true,
56
+ onChain: false,
57
+ rationale: "Live NFC tap verified in the client. Optional message binds the WebAuthn challenge (UTF-8). No on-chain transaction.",
58
+ docIds: ["verification:methods", "verification:overview"],
59
+ },
60
+ onchain_standalone_verify: {
61
+ method: "on-chain verify_asset only",
62
+ sdkExports: ["beginVerifyAsset", "authenticatePasskeyForVerifyAsset", "completeVerifyAsset"],
63
+ requiresTap: true,
64
+ onChain: true,
65
+ onChainPattern: "standalone",
66
+ rationale: "Record passkey proof on-chain without a custom program.",
67
+ docIds: ["verification:verify-asset-composable"],
68
+ },
69
+ onchain_inspect_verify_asset: {
70
+ method: "Pattern A — client posts verify_asset, your program inspects message",
71
+ sdkExports: [
72
+ "beginVerifyAsset",
73
+ "authenticatePasskeyForVerifyAsset",
74
+ "completeVerifyAsset",
75
+ "getVerifyAssetInstruction",
76
+ ],
77
+ requiresTap: true,
78
+ onChain: true,
79
+ onChainPattern: "inspect",
80
+ rationale: "Client includes verify_asset in the tx. Your program scans instructions sysvar for that verify_asset and validates message bytes.",
81
+ docIds: [
82
+ "verification:verify-asset-composable",
83
+ "building-on-phygital:overview",
84
+ "building-on-phygital:rust-cpi",
85
+ ],
86
+ },
87
+ onchain_cpi_verify_asset: {
88
+ method: "Pattern B — buildVerifyAssetArgs, your program CPIs verify_asset",
89
+ sdkExports: [
90
+ "beginVerifyAsset",
91
+ "authenticatePasskeyForVerifyAsset",
92
+ "buildVerifyAssetArgs",
93
+ ],
94
+ requiresTap: true,
95
+ onChain: true,
96
+ onChainPattern: "cpi",
97
+ rationale: "Client includes secp256r1_verify + your ix only. Your program CPIs verify_asset using args from buildVerifyAssetArgs.",
98
+ docIds: [
99
+ "verification:verify-asset-composable",
100
+ "building-on-phygital:rust-cpi",
101
+ "building-on-phygital:overview",
102
+ ],
103
+ },
104
+ transfer_ownership: {
105
+ method: "transfer — beginTransfer / completeTransfer",
106
+ sdkExports: ["beginTransfer", "authenticatePasskeyForTransfer", "completeTransfer"],
107
+ requiresTap: true,
108
+ onChain: true,
109
+ rationale: "Token claim uses execute_transfer, not verify_asset.",
110
+ docIds: ["verification:overview"],
111
+ cautions: ["Do not use verifyDynamicUrl for transfers."],
112
+ },
113
+ wallet_holdings_gate: {
114
+ method: "gating — evaluateAssetGating",
115
+ sdkExports: ["evaluateAssetGating", "Gating", "GatingTraitValue"],
116
+ requiresTap: false,
117
+ onChain: false,
118
+ rationale: "Wallet holdings via DAS. No passkey tap.",
119
+ docIds: ["gating:overview"],
120
+ },
121
+ native_mobile_app: {
122
+ method: "authentication off-chain — verifyWithChallengeResponseOverNfc",
123
+ sdkExports: ["verifyWithChallengeResponseOverNfc"],
124
+ requiresTap: true,
125
+ onChain: false,
126
+ rationale: "Native NFC transceive. Off-chain only; use beginVerifyAsset for on-chain proof.",
127
+ docIds: ["verification:methods"],
128
+ },
129
+ };
130
+ export function recommendVerification(useCase) {
131
+ return RECOMMENDATIONS[useCase];
132
+ }
133
+ export function listVerificationUseCases() {
134
+ return [
135
+ { id: "product_page_lookup", summary: "Product page from prior scan URL" },
136
+ { id: "deep_link_from_prior_scan", summary: "App opens from signed deep link" },
137
+ { id: "offline_identification", summary: "Identify asset offline (weak replay)" },
138
+ { id: "login_ui_only", summary: "Off-chain tap-to-login (no chain tx)" },
139
+ { id: "onchain_standalone_verify", summary: "On-chain verify_asset only" },
140
+ {
141
+ id: "onchain_inspect_verify_asset",
142
+ summary: "Pattern A: client posts verify_asset, your program inspects message",
143
+ },
144
+ {
145
+ id: "onchain_cpi_verify_asset",
146
+ summary: "Pattern B: buildVerifyAssetArgs, your program CPIs verify_asset",
147
+ },
148
+ { id: "transfer_ownership", summary: "Claim/transfer token to new owner" },
149
+ { id: "wallet_holdings_gate", summary: "Gate by wallet NFTs/tokens" },
150
+ { id: "native_mobile_app", summary: "Native app off-chain authentication" },
151
+ ];
152
+ }
153
+ export const VERIFICATION_DECISION_TREE = `
154
+ Identification vs Authentication
155
+ ├── Need holder present NOW?
156
+ │ NO → verifyDynamicUrl / verifyDynamicUrlWithoutCounterCheck
157
+ │ YES → Need on-chain proof?
158
+ │ NO → verifyWithChallengeResponse (web) / OverNfc (native) — off-chain only
159
+ │ YES → beginVerifyAsset composable flow:
160
+ │ Pattern A: [secp256r1_verify, verify_asset, your_ix] — program inspects sysvar
161
+ │ Pattern B: [secp256r1_verify, your_ix] — program CPIs verify_asset
162
+ └── Transfer ownership? → beginTransfer → completeTransfer
163
+
164
+ verifyWithChallengeResponse never submits verify_asset. On-chain proof always uses beginVerifyAsset.
165
+ `.trim();
166
+ //# sourceMappingURL=verification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/lib/verification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ # Building on phygital assets
2
+
3
+ Third-party developers can:
4
+
5
+ - **Gate off-chain** by wallet holdings → `evaluateAssetGating`
6
+ - **Require live passkey presence on-chain** → composable `verify_asset` (two patterns below)
7
+
8
+ ## Two on-chain composition patterns
9
+
10
+ Both start with the same client flow: `beginVerifyAsset` → NFC tap → `buildVerifyAssetArgs`.
11
+
12
+ ### Pattern A — Client posts `verify_asset`, your program inspects
13
+
14
+ | Layer | Responsibility |
15
+ |-------|----------------|
16
+ | **Client** | `[secp256r1_verify, verify_asset, your_ix]` via `completeVerifyAsset` |
17
+ | **Your program** | Read instructions sysvar; find preceding `verify_asset`; verify `message` bytes |
18
+
19
+ Best when your program is a consumer of an already-executed proof. Reference: `phygital-spend`.
20
+
21
+ ### Pattern B — Client posts `secp256r1_verify`, your program CPIs `verify_asset`
22
+
23
+ | Layer | Responsibility |
24
+ |-------|----------------|
25
+ | **Client** | `[secp256r1_verify, your_ix]` — pass `Secp256r1VerifyArgs` + `message` in your ix data |
26
+ | **Your program** | CPI `verify_asset` via `VerifyAssetCpiBuilder` (`phygital-token-client`) |
27
+
28
+ Best when your program orchestrates verification as part of its own instruction.
29
+
30
+ ## Off-chain authentication (no `verify_asset`)
31
+
32
+ `verifyWithChallengeResponse` proves presence in the client only. It does **not** write to chain. Use for UI login when no program needs to inspect `verify_asset`.
33
+
34
+ ## Message design checklist
35
+
36
+ - [ ] Define domain-separated `message` bytes (prefix + action fields)
37
+ - [ ] Same bytes in `beginVerifyAsset({ message })` and your program's check
38
+ - [ ] Never reuse messages across authorization scopes
39
+
40
+ ## Crates
41
+
42
+ **TypeScript:** `phygital-token-sdk` — `buildVerifyAssetArgs`, `completeVerifyAsset`, `getVerifyAssetInstruction`
43
+
44
+ **Rust:** `phygital-token-client` at `clients/rust/phygital-token` — `VerifyAssetCpiBuilder`, `Secp256r1VerifyArgs`
45
+
46
+ See [rust-cpi.md](./rust-cpi.md).
@@ -0,0 +1,55 @@
1
+ # Rust: building on `verify_asset`
2
+
3
+ Crate: `phygital-token-client` (`phygital_token_client`).
4
+
5
+ ## Pattern A — Inspect prior `verify_asset` (phygital-spend)
6
+
7
+ Client sends `secp256r1_verify` + `verify_asset` + your instruction. Your program does **not** CPI.
8
+
9
+ 1. Load `instructions_sysvar`
10
+ 2. Scan instructions **before** your program's index
11
+ 3. Find `phygital_token::verify_asset` for the expected `asset`
12
+ 4. Decode instruction data; verify `message` matches your canonical payload
13
+
14
+ ```rust
15
+ // Pseudocode — see phygital-spend require_matching_verify_asset
16
+ require!(decoded_message == expected_message, MyError::InvalidProof);
17
+ require!(verify_asset_asset == expected_asset, MyError::WrongAsset);
18
+ ```
19
+
20
+ ## Pattern B — CPI `verify_asset` from your program
21
+
22
+ Client sends `secp256r1_verify` + your instruction (no client-side `verify_asset`). Your program CPIs:
23
+
24
+ ```rust
25
+ use phygital_token_client::generated::instructions::VerifyAssetCpiBuilder;
26
+ use phygital_token_client::generated::types::Secp256r1VerifyArgs;
27
+
28
+ VerifyAssetCpiBuilder::new(phygital_token_program)
29
+ .asset(asset_account)
30
+ .slot_hashes(slot_hashes_sysvar)
31
+ .instructions_sysvar(instructions_sysvar)
32
+ .secp256r1_verify_args(secp256r1_verify_args)
33
+ .message(message_bytes)
34
+ .invoke()?;
35
+ ```
36
+
37
+ The client obtains `secp256r1_verify_args` from TypeScript `buildVerifyAssetArgs` and passes them in your instruction data.
38
+
39
+ `secp256r1_verify` must appear earlier in the transaction (client includes it before your ix).
40
+
41
+ ## `Secp256r1VerifyArgs`
42
+
43
+ ```rust
44
+ pub struct Secp256r1VerifyArgs {
45
+ pub signed_message_index: u8,
46
+ pub slot_number: u64,
47
+ pub client_data_json: Vec<u8>,
48
+ }
49
+ ```
50
+
51
+ Mirrors `buildVerifyAssetArgs` output in TypeScript.
52
+
53
+ ## Testing
54
+
55
+ `programs/phygital-token/tests/verify_asset_flow.rs`
@@ -0,0 +1,43 @@
1
+ # Phygital Token — Domain Glossary
2
+
3
+ Shared vocabulary for on-chain accounts, instructions, tests, and the TypeScript client.
4
+
5
+ ## Hierarchy
6
+
7
+ ```
8
+ Collection (group_mint)
9
+ └── Design mint (mint) ← created by `create_mint`
10
+ └── Asset (asset PDA) ← created by `mint_token`, 1:1 with passkey
11
+ └── SPL token unit ← held in program_authority custody until claim
12
+ ```
13
+
14
+ ## Terms
15
+
16
+ | Term | On-chain / IDL name | Description |
17
+ |------|---------------------|-------------|
18
+ | **Collection** | `group_mint` | Token-2022 TokenGroup parent mint. Groups related designs. |
19
+ | **Design** | `mint` (in `create_mint`) | Shared SFT template — one metadata set, many physical instances. |
20
+ | **Asset** | `asset` account | Per-physical-item record keyed by secp256r1 passkey pubkey. |
21
+ | **Owner** | `asset.owner` | Current custodian after a successful `execute_transfer` claim. |
22
+ | **Custody** | `program_authority` | PDA that holds unclaimed tokens and acts as permanent delegate. |
23
+
24
+ ## Instruction map
25
+
26
+ | Instruction | What it does |
27
+ |-------------|--------------|
28
+ | `create_mint` | Creates a **design** mint (member of a collection `group_mint`). |
29
+ | `mint_token` | Mints one SPL token into custody and initializes an **asset** PDA. |
30
+ | `execute_transfer` | Passkey-authorized claim/transfer from current owner to recipient. |
31
+ | `set_lock_state` | Owner toggles transfer lock on a configurable asset. |
32
+ | `create_domain_config` / `update_domain_config` | WebAuthn RP ID and origin allowlist. |
33
+
34
+ ## Client naming
35
+
36
+ | Rust / IDL | TypeScript (hand-written) |
37
+ |------------|---------------------------|
38
+ | `group_mint` | `groupMint` / `collectionMint` (display) |
39
+ | `create_mint` | `buildCreateMintInstructions` |
40
+ | `mint_token` | `buildMintTokenInstructions` |
41
+ | `asset` PDA | `findAssetPda`, `AssetDisplayInfo` |
42
+
43
+ Test helpers mirror on-chain instruction names (`create_mint`, `mint_token`, etc.).
@@ -0,0 +1,77 @@
1
+ # SDK surface area
2
+
3
+ TypeScript package: `phygital-token-sdk` (`clients/js/phygital-token`).
4
+
5
+ ## Mint
6
+
7
+ | Export | Purpose |
8
+ |--------|---------|
9
+ | `buildCreateMintInstructions` | Create design mint in a collection |
10
+ | `buildMintTokenInstructions` | Mint token + initialize asset PDA |
11
+ | `parseSecp256r1Pubkey` | Parse base64url compressed P-256 key |
12
+ | `parseCredentialId` | Parse base64url credential id |
13
+ | `validateMetadataFields` | Name/symbol/uri length checks |
14
+
15
+ ## Transfer
16
+
17
+ | Export | Purpose |
18
+ |--------|---------|
19
+ | `beginTransfer` | Slot-bound transfer challenge |
20
+ | `authenticatePasskeyForTransfer` | WebAuthn NFC tap |
21
+ | `completeTransfer` | `secp256r1_verify` + `execute_transfer` |
22
+
23
+ ## Verify asset (composable)
24
+
25
+ | Export | Purpose |
26
+ |--------|---------|
27
+ | `beginVerifyAsset` | Slot-bound verify challenge for custom `message` |
28
+ | `authenticatePasskeyForVerifyAsset` | WebAuthn NFC tap |
29
+ | `buildVerifyAssetArgs` | Build secp256r1 + resolve asset after tap |
30
+ | `completeVerifyAsset` | Full instruction pair |
31
+
32
+ ## Verification (client helpers — off-chain only)
33
+
34
+ | Export | Purpose |
35
+ |--------|---------|
36
+ | `verifyDynamicUrl` | Identification via signed URL (server) |
37
+ | `verifyDynamicUrlWithoutCounterCheck` | Identification offline |
38
+ | `verifyWithChallengeResponse` | Off-chain authentication (browser); does not submit `verify_asset` |
39
+ | `verifyWithChallengeResponseOverNfc` | Off-chain authentication (native NFC) |
40
+
41
+ On-chain proof always uses `beginVerifyAsset` / `buildVerifyAssetArgs` / `completeVerifyAsset`.
42
+
43
+ ## Asset lookup & metadata
44
+
45
+ | Export | Purpose |
46
+ |--------|---------|
47
+ | `findAssetPda` | Derive asset PDA from secp256r1 pubkey |
48
+ | `fetchAssetFromCredentialId` | Resolve asset + pubkey from credential |
49
+ | `fetchAllAssetsFromOwner` | List assets by wallet owner |
50
+ | `fetchAssetDisplayInfo` | Rich display metadata |
51
+ | `resolveMedia` | Resolve media URLs from token metadata |
52
+
53
+ ## Gating
54
+
55
+ | Export | Purpose |
56
+ |--------|---------|
57
+ | `evaluateAssetGating` | Full tier evaluation for asset owner wallet |
58
+ | `evaluateGatingTiers` / `evaluateGatingFilter` | Lower-level evaluators |
59
+ | `Gating` / `GatingTraitValue` | Filter builders |
60
+ | `summarizeGatingEvaluationFailure` | Human-readable failure reasons |
61
+
62
+ ## Generated (Codama)
63
+
64
+ Re-exported from `./generated/index.js`:
65
+
66
+ - Instructions: `getCreateMintInstructionAsync`, `getMintTokenInstructionAsync`, `getExecuteTransferInstructionAsync`, `getVerifyAssetInstruction`, `getSetLockStateInstruction`, ...
67
+ - Accounts: `fetchAsset`, `Asset`, ...
68
+ - Types: `AssetType`, `Secp256r1VerifyArgs`, `CredentialId`, ...
69
+ - PDAs: `findProgramAuthorityPda`, ...
70
+
71
+ ## Rust client
72
+
73
+ Crate: `phygital-token-client` at `clients/rust/phygital-token`.
74
+
75
+ On-chain: instruction builders, CPI helpers, account layouts, errors.
76
+
77
+ Off-chain (`fetch` feature): RPC account fetching helpers.
@@ -0,0 +1,58 @@
1
+ # Verification methods (`verify.ts`)
2
+
3
+ All exports from `clients/js/phygital-token/src/utils/verify.ts`.
4
+
5
+ ## Identification (no second tap)
6
+
7
+ ### `verifyDynamicUrl(params, callback?)`
8
+
9
+ **Use when:** User already tapped once; you have signed URL query params (`pk`, `s`, `c`, `n`).
10
+
11
+ ### `verifyDynamicUrlWithoutCounterCheck(params)`
12
+
13
+ **Use when:** Offline device, no verification server. Copied links can be replayed.
14
+
15
+ ## Authentication — off-chain only (live tap)
16
+
17
+ ### `verifyWithChallengeResponse({ rpc, message?, fetchPublicKeyFromCredentialIdCallback? })`
18
+
19
+ **Use when:** Browser web app; prove holder is present **without** an on-chain transaction.
20
+
21
+ Optional `message` sets the WebAuthn challenge (UTF-8 encoded). When omitted, a random 32-byte challenge is used. This lets you bind the tap to app-specific context (e.g. session id, action label) without going on-chain.
22
+
23
+ ```ts
24
+ // Random challenge
25
+ await verifyWithChallengeResponse({ rpc });
26
+
27
+ // Bound challenge (still off-chain)
28
+ await verifyWithChallengeResponse({
29
+ rpc,
30
+ message: `login:${sessionId}`,
31
+ });
32
+ ```
33
+
34
+ Returns `{ publicKey, isVerified }`. Does **not** submit `verify_asset`.
35
+
36
+ For on-chain proof with a bound message, use `beginVerifyAsset({ message: Uint8Array })` instead.
37
+
38
+ ### `verifyWithChallengeResponseOverNfc({ rpc, message?, transceive, ... })`
39
+
40
+ Same as above for React Native / native NFC apps. Optional `message` binds the challenge the same way.
41
+
42
+ ## Off-chain auth vs on-chain composable
43
+
44
+ | Need | Use |
45
+ |------|-----|
46
+ | UI login, bound or random challenge, no tx | `verifyWithChallengeResponse({ message? })` |
47
+ | On-chain proof — Pattern A | `completeVerifyAsset` + your ix |
48
+ | On-chain proof — Pattern B | `buildVerifyAssetArgs` + your ix |
49
+ | Transfer ownership | `beginTransfer` → `completeTransfer` |
50
+
51
+ ## Message: off-chain vs on-chain
52
+
53
+ | Context | `message` type | Effect |
54
+ |---------|----------------|--------|
55
+ | `verifyWithChallengeResponse` | optional `string` | WebAuthn challenge bytes (UTF-8) |
56
+ | `beginVerifyAsset` | `Uint8Array` | Hashed into slot-bound on-chain challenge |
57
+
58
+ An off-chain `message` in `verifyWithChallengeResponse` does **not** produce an on-chain `verify_asset` record. Use the composable flow when your program must inspect or CPI `verify_asset`.