@thru/programs 0.2.22

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 (52) hide show
  1. package/README.md +168 -0
  2. package/dist/passkey-manager/index.cjs +7364 -0
  3. package/dist/passkey-manager/index.cjs.map +1 -0
  4. package/dist/passkey-manager/index.d.cts +319 -0
  5. package/dist/passkey-manager/index.d.ts +319 -0
  6. package/dist/passkey-manager/index.js +7303 -0
  7. package/dist/passkey-manager/index.js.map +1 -0
  8. package/dist/token/index.cjs +7130 -0
  9. package/dist/token/index.cjs.map +1 -0
  10. package/dist/token/index.d.cts +1264 -0
  11. package/dist/token/index.d.ts +1264 -0
  12. package/dist/token/index.js +7102 -0
  13. package/dist/token/index.js.map +1 -0
  14. package/package.json +29 -0
  15. package/src/passkey-manager/abi/thru/blockchain/state_proof/types.ts +1667 -0
  16. package/src/passkey-manager/abi/thru/common/primitives/types.ts +2191 -0
  17. package/src/passkey-manager/abi/thru/program/passkey_manager/types.ts +4977 -0
  18. package/src/passkey-manager/accounts.ts +142 -0
  19. package/src/passkey-manager/authority.ts +148 -0
  20. package/src/passkey-manager/challenge.ts +39 -0
  21. package/src/passkey-manager/constants.ts +15 -0
  22. package/src/passkey-manager/context.ts +112 -0
  23. package/src/passkey-manager/crypto.ts +80 -0
  24. package/src/passkey-manager/encoding.ts +85 -0
  25. package/src/passkey-manager/index.ts +99 -0
  26. package/src/passkey-manager/instructions/add-authority.ts +21 -0
  27. package/src/passkey-manager/instructions/create.ts +54 -0
  28. package/src/passkey-manager/instructions/invoke.ts +25 -0
  29. package/src/passkey-manager/instructions/register-credential.ts +33 -0
  30. package/src/passkey-manager/instructions/remove-authority.ts +20 -0
  31. package/src/passkey-manager/instructions/shared.ts +12 -0
  32. package/src/passkey-manager/instructions/transfer.ts +30 -0
  33. package/src/passkey-manager/instructions/validate.ts +33 -0
  34. package/src/passkey-manager/seeds.ts +73 -0
  35. package/src/passkey-manager/types.ts +112 -0
  36. package/src/token/abi/thru/blockchain/state_proof/types.ts +1667 -0
  37. package/src/token/abi/thru/common/primitives/types.ts +1141 -0
  38. package/src/token/abi/thru/program/token/types.ts +6303 -0
  39. package/src/token/accounts.ts +72 -0
  40. package/src/token/constants.ts +3 -0
  41. package/src/token/derivation.ts +78 -0
  42. package/src/token/format.ts +24 -0
  43. package/src/token/index.ts +46 -0
  44. package/src/token/instructions/index.ts +5 -0
  45. package/src/token/instructions/initialize-account.ts +27 -0
  46. package/src/token/instructions/initialize-mint.ts +76 -0
  47. package/src/token/instructions/mint-to.ts +26 -0
  48. package/src/token/instructions/shared.ts +20 -0
  49. package/src/token/instructions/transfer.ts +24 -0
  50. package/src/token/types.ts +54 -0
  51. package/tsconfig.json +9 -0
  52. package/tsup.config.ts +13 -0
@@ -0,0 +1,99 @@
1
+ // Constants
2
+ export {
3
+ PASSKEY_MANAGER_PROGRAM_ADDRESS,
4
+ INSTRUCTION_CREATE,
5
+ INSTRUCTION_VALIDATE,
6
+ INSTRUCTION_TRANSFER,
7
+ INSTRUCTION_INVOKE,
8
+ INSTRUCTION_ADD_AUTHORITY,
9
+ INSTRUCTION_REMOVE_AUTHORITY,
10
+ INSTRUCTION_REGISTER_CREDENTIAL,
11
+ AUTHORITY_TAG_PASSKEY,
12
+ AUTHORITY_TAG_PUBKEY,
13
+ } from './constants';
14
+
15
+ // Types
16
+ export type {
17
+ Authority,
18
+ CreateInstructionParams,
19
+ TransferInstructionParams,
20
+ ValidateInstructionParams,
21
+ RegisterCredentialInstructionParams,
22
+ AccountContext,
23
+ WalletSigner,
24
+ TransactionExecutionSummary,
25
+ PasskeyMetadata,
26
+ PasskeyRegistrationResult,
27
+ PasskeySigningResult,
28
+ PasskeyDiscoverableSigningResult,
29
+ } from './types';
30
+
31
+ // Instructions
32
+ export { encodeCreateInstruction } from './instructions/create';
33
+ export { encodeValidateInstruction } from './instructions/validate';
34
+ export { encodeTransferInstruction } from './instructions/transfer';
35
+ export { encodeInvokeInstruction } from './instructions/invoke';
36
+ export { encodeAddAuthorityInstruction } from './instructions/add-authority';
37
+ export { encodeRemoveAuthorityInstruction } from './instructions/remove-authority';
38
+ export { encodeRegisterCredentialInstruction } from './instructions/register-credential';
39
+ export { concatenateInstructions } from './instructions/shared';
40
+
41
+ // Challenge
42
+ export { createValidateChallenge } from './challenge';
43
+
44
+ // Seeds & derivation
45
+ export { createWalletSeed, deriveWalletAddress, createCredentialLookupSeed, deriveCredentialLookupAddress } from './seeds';
46
+
47
+ // Account context building
48
+ export { buildAccountContext, buildPasskeyReadWriteAccounts, FEE_PAYER_ADDRESS } from './context';
49
+ export { decodeAddress, encodeAddress } from '@thru/sdk/helpers';
50
+
51
+ // Account parsing
52
+ export {
53
+ parseWalletNonce,
54
+ fetchWalletNonce,
55
+ parseCredentialLookupWallet,
56
+ parseWalletAuthorities,
57
+ formatAuthorityPubkey,
58
+ } from './accounts';
59
+ export type { ParsedAuthority, WalletAuthorities } from './accounts';
60
+
61
+ // Authority matching
62
+ export {
63
+ findPasskeyAuthorityIndexForIdentity,
64
+ findPasskeyAuthorityIndexInWalletData,
65
+ isPasskeyAuthorityCheckable,
66
+ preparePasskeyAuthorityTargets,
67
+ resolvePasskeyAuthorityIndex,
68
+ } from './authority';
69
+ export type {
70
+ CheckablePasskeyAuthorityIdentity,
71
+ PasskeyAuthorityIdentity,
72
+ PasskeyAuthorityTarget,
73
+ PreparePasskeyAuthorityTargetsOptions,
74
+ } from './authority';
75
+
76
+ // Crypto (platform-agnostic P-256 / DER utilities)
77
+ export {
78
+ parseDerSignature,
79
+ normalizeLowS,
80
+ normalizeSignatureComponent,
81
+ P256_N,
82
+ P256_HALF_N,
83
+ bytesToBigIntBE,
84
+ bigIntToBytesBE,
85
+ } from './crypto';
86
+
87
+ // Encoding (platform-agnostic byte/base64/hex utilities)
88
+ export {
89
+ arrayBufferToBase64Url,
90
+ base64UrlToArrayBuffer,
91
+ bytesToBase64,
92
+ bytesToBase64Url,
93
+ base64UrlToBytes,
94
+ bytesToHex,
95
+ hexToBytes,
96
+ bytesEqual,
97
+ compareBytes,
98
+ uniqueAccounts,
99
+ } from './encoding';
@@ -0,0 +1,21 @@
1
+ import type { Authority } from '../types';
2
+ import {
3
+ AddAuthorityArgsBuilder,
4
+ PasskeyInstructionBuilder,
5
+ } from '../abi/thru/program/passkey_manager/types';
6
+ import { buildAuthority } from './create';
7
+
8
+ export function encodeAddAuthorityInstruction(params: { authority: Authority }): Uint8Array {
9
+ const authorityBytes = buildAuthority(params.authority);
10
+
11
+ const argsPayload = new AddAuthorityArgsBuilder()
12
+ .set_authority(authorityBytes)
13
+ .build();
14
+
15
+ return new PasskeyInstructionBuilder()
16
+ .payload()
17
+ .select('add_authority')
18
+ .writePayload(argsPayload)
19
+ .finish()
20
+ .build();
21
+ }
@@ -0,0 +1,54 @@
1
+ import type { Authority, CreateInstructionParams } from '../types';
2
+ import {
3
+ AuthorityBuilder,
4
+ CreateArgsBuilder,
5
+ PasskeyInstructionBuilder,
6
+ } from '../abi/thru/program/passkey_manager/types';
7
+
8
+ function buildAuthority(authority: Authority): Uint8Array {
9
+ const data = new Array<number>(64).fill(0);
10
+
11
+ if (authority.tag === 1) {
12
+ if (authority.pubkeyX.length !== 32) throw new Error('pubkeyX must be 32 bytes');
13
+ if (authority.pubkeyY.length !== 32) throw new Error('pubkeyY must be 32 bytes');
14
+ for (let i = 0; i < 32; i++) data[i] = authority.pubkeyX[i];
15
+ for (let i = 0; i < 32; i++) data[32 + i] = authority.pubkeyY[i];
16
+ } else if (authority.tag === 2) {
17
+ if (authority.pubkey.length !== 32) throw new Error('pubkey must be 32 bytes');
18
+ for (let i = 0; i < 32; i++) data[i] = authority.pubkey[i];
19
+ } else {
20
+ throw new Error('Invalid authority tag');
21
+ }
22
+
23
+ return new AuthorityBuilder()
24
+ .set_tag(authority.tag)
25
+ .set_data(data)
26
+ .build();
27
+ }
28
+
29
+ export { buildAuthority };
30
+
31
+ export function encodeCreateInstruction(params: CreateInstructionParams): Uint8Array {
32
+ const { walletAccountIdx, authority, seed, stateProof } = params;
33
+
34
+ if (seed.length !== 32) throw new Error('seed must be 32 bytes');
35
+ if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
36
+ throw new Error('walletAccountIdx must be 0-65535');
37
+ }
38
+
39
+ const authorityBytes = buildAuthority(authority);
40
+
41
+ const argsPayload = new CreateArgsBuilder()
42
+ .set_wallet_account_idx(walletAccountIdx)
43
+ .set_authority(authorityBytes)
44
+ .set_seed(seed)
45
+ .set_state_proof(stateProof)
46
+ .build();
47
+
48
+ return new PasskeyInstructionBuilder()
49
+ .payload()
50
+ .select('create')
51
+ .writePayload(argsPayload)
52
+ .finish()
53
+ .build();
54
+ }
@@ -0,0 +1,25 @@
1
+ import {
2
+ InvokeArgsBuilder,
3
+ PasskeyInstructionBuilder,
4
+ } from '../abi/thru/program/passkey_manager/types';
5
+
6
+ export function encodeInvokeInstruction(
7
+ programPubkey: Uint8Array,
8
+ instruction: Uint8Array
9
+ ): Uint8Array {
10
+ if (programPubkey.length !== 32) {
11
+ throw new Error('Program pubkey must be 32 bytes');
12
+ }
13
+
14
+ const argsPayload = new InvokeArgsBuilder()
15
+ .set_program_pubkey(programPubkey)
16
+ .instr().write(instruction).finish()
17
+ .build();
18
+
19
+ return new PasskeyInstructionBuilder()
20
+ .payload()
21
+ .select('invoke')
22
+ .writePayload(argsPayload)
23
+ .finish()
24
+ .build();
25
+ }
@@ -0,0 +1,33 @@
1
+ import type { RegisterCredentialInstructionParams } from '../types';
2
+ import {
3
+ RegisterCredentialArgsBuilder,
4
+ PasskeyInstructionBuilder,
5
+ } from '../abi/thru/program/passkey_manager/types';
6
+
7
+ export function encodeRegisterCredentialInstruction(
8
+ params: RegisterCredentialInstructionParams
9
+ ): Uint8Array {
10
+ const { walletAccountIdx, lookupAccountIdx, seed, stateProof } = params;
11
+
12
+ if (seed.length !== 32) throw new Error('seed must be 32 bytes');
13
+ if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
14
+ throw new Error('walletAccountIdx must be 0-65535');
15
+ }
16
+ if (lookupAccountIdx < 0 || lookupAccountIdx > 0xffff) {
17
+ throw new Error('lookupAccountIdx must be 0-65535');
18
+ }
19
+
20
+ const argsPayload = new RegisterCredentialArgsBuilder()
21
+ .set_wallet_account_idx(walletAccountIdx)
22
+ .set_lookup_account_idx(lookupAccountIdx)
23
+ .set_seed(seed)
24
+ .set_state_proof(stateProof)
25
+ .build();
26
+
27
+ return new PasskeyInstructionBuilder()
28
+ .payload()
29
+ .select('register_credential')
30
+ .writePayload(argsPayload)
31
+ .finish()
32
+ .build();
33
+ }
@@ -0,0 +1,20 @@
1
+ import {
2
+ RemoveAuthorityArgsBuilder,
3
+ PasskeyInstructionBuilder,
4
+ } from '../abi/thru/program/passkey_manager/types';
5
+
6
+ export function encodeRemoveAuthorityInstruction(params: { authIdx: number }): Uint8Array {
7
+ const { authIdx } = params;
8
+ if (authIdx < 0 || authIdx > 0xff) throw new Error('authIdx must be 0-255');
9
+
10
+ const argsPayload = new RemoveAuthorityArgsBuilder()
11
+ .set_auth_idx(authIdx)
12
+ .build();
13
+
14
+ return new PasskeyInstructionBuilder()
15
+ .payload()
16
+ .select('remove_authority')
17
+ .writePayload(argsPayload)
18
+ .finish()
19
+ .build();
20
+ }
@@ -0,0 +1,12 @@
1
+ export function concatenateInstructions(instructions: Uint8Array[]): Uint8Array {
2
+ const totalLength = instructions.reduce((sum, instr) => sum + instr.length, 0);
3
+ const result = new Uint8Array(totalLength);
4
+
5
+ let offset = 0;
6
+ for (const instr of instructions) {
7
+ result.set(instr, offset);
8
+ offset += instr.length;
9
+ }
10
+
11
+ return result;
12
+ }
@@ -0,0 +1,30 @@
1
+ import type { TransferInstructionParams } from '../types';
2
+ import {
3
+ TransferArgsBuilder,
4
+ PasskeyInstructionBuilder,
5
+ } from '../abi/thru/program/passkey_manager/types';
6
+
7
+ export function encodeTransferInstruction(params: TransferInstructionParams): Uint8Array {
8
+ const { walletAccountIdx, toAccountIdx, amount } = params;
9
+
10
+ if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
11
+ throw new Error('walletAccountIdx must be 0-65535');
12
+ }
13
+ if (toAccountIdx < 0 || toAccountIdx > 0xffff) {
14
+ throw new Error('toAccountIdx must be 0-65535');
15
+ }
16
+ if (amount < 0n) throw new Error('amount must be non-negative');
17
+
18
+ const argsPayload = new TransferArgsBuilder()
19
+ .set_wallet_account_idx(walletAccountIdx)
20
+ .set_to_account_idx(toAccountIdx)
21
+ .set_amount(amount as unknown as number)
22
+ .build();
23
+
24
+ return new PasskeyInstructionBuilder()
25
+ .payload()
26
+ .select('transfer')
27
+ .writePayload(argsPayload)
28
+ .finish()
29
+ .build();
30
+ }
@@ -0,0 +1,33 @@
1
+ import type { ValidateInstructionParams } from '../types';
2
+ import {
3
+ ValidateArgsBuilder,
4
+ PasskeyInstructionBuilder,
5
+ } from '../abi/thru/program/passkey_manager/types';
6
+
7
+ export function encodeValidateInstruction(params: ValidateInstructionParams): Uint8Array {
8
+ const { walletAccountIdx, authIdx, signatureR, signatureS, authenticatorData, clientDataJSON } =
9
+ params;
10
+
11
+ if (walletAccountIdx < 0 || walletAccountIdx > 0xffff) {
12
+ throw new Error('walletAccountIdx must be 0-65535');
13
+ }
14
+ if (authIdx < 0 || authIdx > 0xff) throw new Error('authIdx must be 0-255');
15
+ if (signatureR.length !== 32) throw new Error('signatureR must be 32 bytes');
16
+ if (signatureS.length !== 32) throw new Error('signatureS must be 32 bytes');
17
+
18
+ const argsPayload = new ValidateArgsBuilder()
19
+ .set_wallet_account_idx(walletAccountIdx)
20
+ .set_auth_idx(authIdx)
21
+ .set_signature_r(signatureR)
22
+ .set_signature_s(signatureS)
23
+ .authenticator_data().write(authenticatorData).finish()
24
+ .client_data().write(clientDataJSON).finish()
25
+ .build();
26
+
27
+ return new PasskeyInstructionBuilder()
28
+ .payload()
29
+ .select('validate')
30
+ .writePayload(argsPayload)
31
+ .finish()
32
+ .build();
33
+ }
@@ -0,0 +1,73 @@
1
+ import { decodeAddress } from '@thru/sdk/helpers';
2
+
3
+ /**
4
+ * Create a 32-byte seed from wallet name and passkey coordinates.
5
+ * SHA-256(walletName || pubkey_x || pubkey_y)
6
+ */
7
+ export async function createWalletSeed(
8
+ walletName: string,
9
+ pubkeyX: Uint8Array,
10
+ pubkeyY: Uint8Array,
11
+ ): Promise<Uint8Array> {
12
+ if (pubkeyX.length !== 32) throw new Error("pubkeyX must be 32 bytes");
13
+ if (pubkeyY.length !== 32) throw new Error("pubkeyY must be 32 bytes");
14
+
15
+ const nameBytes = new TextEncoder().encode(walletName);
16
+ const data = new Uint8Array(nameBytes.length + 32 + 32);
17
+ data.set(nameBytes, 0);
18
+ data.set(pubkeyX, nameBytes.length);
19
+ data.set(pubkeyY, nameBytes.length + 32);
20
+
21
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
22
+ return new Uint8Array(hashBuffer);
23
+ }
24
+
25
+ /**
26
+ * Derive wallet account address from seed using proper PDA derivation.
27
+ * SHA256(program_address || is_ephemeral || seed)
28
+ */
29
+ export async function deriveWalletAddress(
30
+ seed: Uint8Array,
31
+ programAddress: string,
32
+ ): Promise<Uint8Array> {
33
+ if (seed.length !== 32) {
34
+ throw new Error("seed must be 32 bytes");
35
+ }
36
+
37
+ const programBytes = decodeAddress(programAddress);
38
+ const isEphemeral = new Uint8Array([0]);
39
+
40
+ const preimage = new Uint8Array(32 + 1 + 32);
41
+ preimage.set(programBytes, 0);
42
+ preimage.set(isEphemeral, 32);
43
+ preimage.set(seed, 33);
44
+
45
+ const hashBuffer = await crypto.subtle.digest("SHA-256", preimage);
46
+ return new Uint8Array(hashBuffer);
47
+ }
48
+
49
+ /**
50
+ * Create a 32-byte seed for a credential lookup PDA.
51
+ * SHA-256(credentialId)
52
+ */
53
+ export async function createCredentialLookupSeed(
54
+ credentialId: Uint8Array,
55
+ ): Promise<Uint8Array> {
56
+ const data = new Uint8Array(credentialId.length);
57
+ data.set(credentialId);
58
+
59
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
60
+ return new Uint8Array(hashBuffer);
61
+ }
62
+
63
+ /**
64
+ * Derive credential lookup PDA address from a credential ID.
65
+ * Convenience wrapper: deriveWalletAddress(SHA-256(credentialId), programAddress)
66
+ */
67
+ export async function deriveCredentialLookupAddress(
68
+ credentialId: Uint8Array,
69
+ programAddress: string,
70
+ ): Promise<Uint8Array> {
71
+ const seed = await createCredentialLookupSeed(credentialId);
72
+ return deriveWalletAddress(seed, programAddress);
73
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Result of passkey registration (credential creation).
3
+ */
4
+ export interface PasskeyRegistrationResult {
5
+ credentialId: string; // base64url-encoded
6
+ publicKeyX: string; // hex-encoded (32 bytes)
7
+ publicKeyY: string; // hex-encoded (32 bytes)
8
+ rpId: string;
9
+ authenticatorAttachment?: 'platform' | 'cross-platform' | null;
10
+ }
11
+
12
+ /**
13
+ * Result of passkey signing (assertion).
14
+ */
15
+ export interface PasskeySigningResult {
16
+ signature: Uint8Array; // Raw P-256 signature (r || s, 64 bytes)
17
+ authenticatorData: Uint8Array;
18
+ clientDataJSON: Uint8Array;
19
+ signatureR: Uint8Array; // 32 bytes
20
+ signatureS: Uint8Array; // 32 bytes
21
+ /** WebAuthn authenticator attachment, if surfaced by the browser:
22
+ * - 'platform': built-in / passkey on this device
23
+ * - 'cross-platform': e.g. signed in via QR using another device
24
+ * Used by the wallet to decide whether to offer "add this device". */
25
+ authenticatorAttachment?: 'platform' | 'cross-platform' | null;
26
+ }
27
+
28
+ /**
29
+ * Signing result with discoverable credential info.
30
+ */
31
+ export interface PasskeyDiscoverableSigningResult extends PasskeySigningResult {
32
+ credentialId: string; // base64url-encoded
33
+ rpId: string;
34
+ }
35
+
36
+ /**
37
+ * Passkey metadata stored locally (the actual private key lives in the device's secure enclave).
38
+ */
39
+ export interface PasskeyMetadata {
40
+ credentialId: string;
41
+ publicKeyX: string;
42
+ publicKeyY: string;
43
+ rpId: string;
44
+ /** On-chain passkey authority index for this wallet account.
45
+ * Omitted for the primary authority, which defaults to index 0. */
46
+ authIdx?: number;
47
+ label?: string;
48
+ deviceName?: string;
49
+ devicePlatform?: string;
50
+ browserName?: string;
51
+ authenticatorAttachment?: 'platform' | 'cross-platform' | null;
52
+ createdAt: string;
53
+ lastUsedAt: string;
54
+ }
55
+
56
+ export type Authority =
57
+ | {
58
+ tag: 1; // passkey
59
+ pubkeyX: Uint8Array; // 32 bytes
60
+ pubkeyY: Uint8Array; // 32 bytes
61
+ }
62
+ | {
63
+ tag: 2; // pubkey
64
+ pubkey: Uint8Array; // 32 bytes
65
+ };
66
+
67
+ export interface CreateInstructionParams {
68
+ walletAccountIdx: number;
69
+ authority: Authority;
70
+ seed: Uint8Array;
71
+ stateProof: Uint8Array;
72
+ }
73
+
74
+ export interface TransferInstructionParams {
75
+ walletAccountIdx: number;
76
+ toAccountIdx: number;
77
+ amount: bigint;
78
+ }
79
+
80
+ export interface ValidateInstructionParams {
81
+ walletAccountIdx: number;
82
+ authIdx: number;
83
+ signatureR: Uint8Array;
84
+ signatureS: Uint8Array;
85
+ authenticatorData: Uint8Array;
86
+ clientDataJSON: Uint8Array;
87
+ }
88
+
89
+ export interface AccountContext {
90
+ readWriteAddresses: string[];
91
+ readOnlyAddresses: string[];
92
+ accountAddresses: string[];
93
+ walletAccountIdx: number;
94
+ getAccountIndex: (pubkey: Uint8Array) => number;
95
+ }
96
+
97
+ export interface RegisterCredentialInstructionParams {
98
+ walletAccountIdx: number;
99
+ lookupAccountIdx: number;
100
+ seed: Uint8Array; // SHA-256(credentialId), 32 bytes
101
+ stateProof: Uint8Array;
102
+ }
103
+
104
+ export type WalletSigner = {
105
+ signTransaction: (payloadBase64: string) => Promise<string>;
106
+ };
107
+
108
+ export type TransactionExecutionSummary = {
109
+ executionResult?: bigint | number | null;
110
+ userErrorCode?: bigint | number | null;
111
+ vmError?: number | string | bigint | null;
112
+ };