@thru/abi-utils 0.1.38 → 0.2.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.
package/dist/index.d.ts CHANGED
@@ -1,39 +1,27 @@
1
1
  /**
2
- * Derives the ABI seed bytes from a program account pubkey.
3
- *
4
- * Algorithm:
5
- * 1. Get program account bytes (32 bytes)
6
- * 2. Append "_abi_account" suffix (12 bytes)
7
- * 3. SHA256 hash the combined 44 bytes
8
- * 4. Return the 32-byte hash as the seed
9
- *
10
- * @param programAccountBytes - The 32-byte program account public key
11
- * @returns 32-byte seed for PDA derivation
2
+ * Builds the ABI meta body for an official ABI (program account).
12
3
  */
13
- declare function deriveAbiSeed(programAccountBytes: Uint8Array): Promise<Uint8Array>;
4
+ declare function abiMetaBodyForProgram(programBytes: Uint8Array): Uint8Array;
14
5
  /**
15
- * Derives a program address (PDA) from a seed and program ID.
16
- *
17
- * This implements the Thru PDA derivation algorithm:
18
- * 1. Combine seed + program ID bytes
19
- * 2. SHA256 hash the combined bytes
20
- * 3. Return as the derived address
21
- *
22
- * @param seed - The 32-byte seed
23
- * @param programId - The program ID bytes (32 bytes)
24
- * @param ephemeral - Whether to derive an ephemeral address (affects prefix byte)
25
- * @returns The derived 32-byte address
6
+ * Derives the ABI meta seed from ABI meta kind + body.
7
+ */
8
+ declare function deriveAbiMetaSeed(kind: number, body: Uint8Array): Promise<Uint8Array>;
9
+ /**
10
+ * Derives the ABI account seed from ABI meta kind + body.
11
+ */
12
+ declare function deriveAbiAccountSeed(kind: number, body: Uint8Array): Promise<Uint8Array>;
13
+ /**
14
+ * Derives a program-defined account address (owner || ephemeral || seed).
26
15
  */
27
16
  declare function deriveProgramAddress(seed: Uint8Array, programId: Uint8Array, ephemeral?: boolean): Promise<Uint8Array>;
28
17
  /**
29
- * Derives the ABI account address for a given program account.
30
- *
31
- * @param programAccount - The program account address (ta-prefixed string or 32-byte array)
32
- * @param abiManagerProgramId - The ABI manager program ID (ta-prefixed string or 32-byte array)
33
- * @param ephemeral - Whether to derive an ephemeral address
34
- * @returns The derived ABI account address as a ta-prefixed string
18
+ * Derives the ABI meta account address (as a ta-prefixed string).
19
+ */
20
+ declare function deriveAbiMetaAddress(kind: number, body: Uint8Array, abiManagerProgramId: string | Uint8Array, ephemeral?: boolean): Promise<string>;
21
+ /**
22
+ * Derives the ABI account address (as a ta-prefixed string).
35
23
  */
36
- declare function deriveAbiAddress(programAccount: string | Uint8Array, abiManagerProgramId: string | Uint8Array, ephemeral?: boolean): Promise<string>;
24
+ declare function deriveAbiAddress(kind: number, body: Uint8Array, abiManagerProgramId: string | Uint8Array, ephemeral?: boolean): Promise<string>;
37
25
 
38
26
  /**
39
27
  * ABI account state values
@@ -47,8 +35,8 @@ type AbiAccountState = (typeof ABI_STATE)[keyof typeof ABI_STATE];
47
35
  * Parsed header from an ABI account's on-chain data
48
36
  */
49
37
  interface AbiAccountHeader {
50
- /** The program meta account this ABI is associated with */
51
- programMetaAccount: Uint8Array;
38
+ /** The ABI meta account this ABI is associated with */
39
+ abiMetaAccount: Uint8Array;
52
40
  /** Revision number (incremented on each upgrade) */
53
41
  revision: bigint;
54
42
  /** Account state: OPEN (0) or FINALIZED (1) */
@@ -68,7 +56,7 @@ interface AbiAccountData extends AbiAccountHeader {
68
56
 
69
57
  /**
70
58
  * Size of the ABI account header in bytes:
71
- * - 32 bytes: program_meta_acc (pubkey)
59
+ * - 32 bytes: abi_meta_acc (pubkey)
72
60
  * - 8 bytes: revision (u64)
73
61
  * - 1 byte: state (u8)
74
62
  * - 4 bytes: content_sz (u32)
@@ -92,4 +80,4 @@ declare function parseAbiAccountHeader(data: Uint8Array): AbiAccountHeader;
92
80
  */
93
81
  declare function parseAbiAccountData(data: Uint8Array): AbiAccountData;
94
82
 
95
- export { ABI_ACCOUNT_HEADER_SIZE, ABI_STATE, type AbiAccountData, type AbiAccountHeader, type AbiAccountState, deriveAbiAddress, deriveAbiSeed, deriveProgramAddress, parseAbiAccountData, parseAbiAccountHeader };
83
+ export { ABI_ACCOUNT_HEADER_SIZE, ABI_STATE, type AbiAccountData, type AbiAccountHeader, type AbiAccountState, abiMetaBodyForProgram, deriveAbiAccountSeed, deriveAbiAddress, deriveAbiMetaAddress, deriveAbiMetaSeed, deriveProgramAddress, parseAbiAccountData, parseAbiAccountHeader };
package/dist/index.js CHANGED
@@ -1,17 +1,42 @@
1
1
  // src/derivation.ts
2
2
  import { decodeAddress, encodeAddress } from "@thru/helpers";
3
- var ABI_SEED_SUFFIX = "_abi_account";
4
- async function deriveAbiSeed(programAccountBytes) {
5
- if (programAccountBytes.length !== 32) {
6
- throw new Error(`Expected 32-byte program account, got ${programAccountBytes.length} bytes`);
3
+ var ABI_META_BODY_SIZE = 96;
4
+ var ABI_ACCOUNT_SUFFIX = "_abi_account";
5
+ var ABI_ACCOUNT_SUFFIX_BYTES = new TextEncoder().encode(ABI_ACCOUNT_SUFFIX);
6
+ function concatBytes(...chunks) {
7
+ const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
8
+ const out = new Uint8Array(total);
9
+ let offset = 0;
10
+ for (const chunk of chunks) {
11
+ out.set(chunk, offset);
12
+ offset += chunk.length;
7
13
  }
8
- const suffixBytes = new TextEncoder().encode(ABI_SEED_SUFFIX);
9
- const combined = new Uint8Array(programAccountBytes.length + suffixBytes.length);
10
- combined.set(programAccountBytes, 0);
11
- combined.set(suffixBytes, programAccountBytes.length);
12
- const hashBuffer = await crypto.subtle.digest("SHA-256", combined);
14
+ return out;
15
+ }
16
+ async function sha256Bytes(data) {
17
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
13
18
  return new Uint8Array(hashBuffer);
14
19
  }
20
+ function abiMetaBodyForProgram(programBytes) {
21
+ if (programBytes.length !== 32) {
22
+ throw new Error(`Expected 32-byte program account, got ${programBytes.length} bytes`);
23
+ }
24
+ const body = new Uint8Array(ABI_META_BODY_SIZE);
25
+ body.set(programBytes, 0);
26
+ return body;
27
+ }
28
+ async function deriveAbiMetaSeed(kind, body) {
29
+ if (body.length !== ABI_META_BODY_SIZE) {
30
+ throw new Error(`Expected ${ABI_META_BODY_SIZE}-byte ABI meta body, got ${body.length} bytes`);
31
+ }
32
+ return sha256Bytes(concatBytes(new Uint8Array([kind]), body));
33
+ }
34
+ async function deriveAbiAccountSeed(kind, body) {
35
+ if (body.length !== ABI_META_BODY_SIZE) {
36
+ throw new Error(`Expected ${ABI_META_BODY_SIZE}-byte ABI meta body, got ${body.length} bytes`);
37
+ }
38
+ return sha256Bytes(concatBytes(new Uint8Array([kind]), body, ABI_ACCOUNT_SUFFIX_BYTES));
39
+ }
15
40
  async function deriveProgramAddress(seed, programId, ephemeral = false) {
16
41
  if (seed.length !== 32) {
17
42
  throw new Error(`Expected 32-byte seed, got ${seed.length} bytes`);
@@ -19,24 +44,20 @@ async function deriveProgramAddress(seed, programId, ephemeral = false) {
19
44
  if (programId.length !== 32) {
20
45
  throw new Error(`Expected 32-byte program ID, got ${programId.length} bytes`);
21
46
  }
22
- const combined = new Uint8Array(seed.length + programId.length);
23
- combined.set(seed, 0);
24
- combined.set(programId, seed.length);
25
- const hashBuffer = await crypto.subtle.digest("SHA-256", combined);
26
- const result = new Uint8Array(hashBuffer);
27
- if (ephemeral) {
28
- result[0] = result[0] | 128;
29
- } else {
30
- result[0] = result[0] & 127;
31
- }
32
- return result;
47
+ const flag = new Uint8Array([ephemeral ? 1 : 0]);
48
+ return sha256Bytes(concatBytes(programId, flag, seed));
49
+ }
50
+ async function deriveAbiMetaAddress(kind, body, abiManagerProgramId, ephemeral = false) {
51
+ const abiManagerBytes = typeof abiManagerProgramId === "string" ? decodeAddress(abiManagerProgramId) : abiManagerProgramId;
52
+ const seed = await deriveAbiMetaSeed(kind, body);
53
+ const addressBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);
54
+ return encodeAddress(addressBytes);
33
55
  }
34
- async function deriveAbiAddress(programAccount, abiManagerProgramId, ephemeral = false) {
35
- const programAccountBytes = typeof programAccount === "string" ? decodeAddress(programAccount) : programAccount;
56
+ async function deriveAbiAddress(kind, body, abiManagerProgramId, ephemeral = false) {
36
57
  const abiManagerBytes = typeof abiManagerProgramId === "string" ? decodeAddress(abiManagerProgramId) : abiManagerProgramId;
37
- const seed = await deriveAbiSeed(programAccountBytes);
38
- const abiAccountBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);
39
- return encodeAddress(abiAccountBytes);
58
+ const seed = await deriveAbiAccountSeed(kind, body);
59
+ const addressBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);
60
+ return encodeAddress(addressBytes);
40
61
  }
41
62
 
42
63
  // src/types.ts
@@ -54,13 +75,13 @@ function parseAbiAccountHeader(data) {
54
75
  );
55
76
  }
56
77
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
57
- const programMetaAccount = data.slice(0, 32);
78
+ const abiMetaAccount = data.slice(0, 32);
58
79
  const revision = view.getBigUint64(32, true);
59
80
  const stateRaw = data[40];
60
81
  const state = stateRaw === ABI_STATE.FINALIZED ? ABI_STATE.FINALIZED : ABI_STATE.OPEN;
61
82
  const contentSize = view.getUint32(41, true);
62
83
  return {
63
- programMetaAccount,
84
+ abiMetaAccount,
64
85
  revision,
65
86
  state,
66
87
  contentSize
@@ -85,8 +106,11 @@ function parseAbiAccountData(data) {
85
106
  export {
86
107
  ABI_ACCOUNT_HEADER_SIZE,
87
108
  ABI_STATE,
109
+ abiMetaBodyForProgram,
110
+ deriveAbiAccountSeed,
88
111
  deriveAbiAddress,
89
- deriveAbiSeed,
112
+ deriveAbiMetaAddress,
113
+ deriveAbiMetaSeed,
90
114
  deriveProgramAddress,
91
115
  parseAbiAccountData,
92
116
  parseAbiAccountHeader
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/derivation.ts","../src/types.ts","../src/parser.ts"],"sourcesContent":["import { decodeAddress, encodeAddress } from \"@thru/helpers\";\n\n/**\n * Suffix appended to program account bytes for ABI seed derivation\n */\nconst ABI_SEED_SUFFIX = \"_abi_account\";\n\n/**\n * Derives the ABI seed bytes from a program account pubkey.\n *\n * Algorithm:\n * 1. Get program account bytes (32 bytes)\n * 2. Append \"_abi_account\" suffix (12 bytes)\n * 3. SHA256 hash the combined 44 bytes\n * 4. Return the 32-byte hash as the seed\n *\n * @param programAccountBytes - The 32-byte program account public key\n * @returns 32-byte seed for PDA derivation\n */\nexport async function deriveAbiSeed(programAccountBytes: Uint8Array): Promise<Uint8Array> {\n if (programAccountBytes.length !== 32) {\n throw new Error(`Expected 32-byte program account, got ${programAccountBytes.length} bytes`);\n }\n\n // Combine program account bytes with suffix\n const suffixBytes = new TextEncoder().encode(ABI_SEED_SUFFIX);\n const combined = new Uint8Array(programAccountBytes.length + suffixBytes.length);\n combined.set(programAccountBytes, 0);\n combined.set(suffixBytes, programAccountBytes.length);\n\n // SHA256 hash\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", combined);\n return new Uint8Array(hashBuffer);\n}\n\n/**\n * Derives a program address (PDA) from a seed and program ID.\n *\n * This implements the Thru PDA derivation algorithm:\n * 1. Combine seed + program ID bytes\n * 2. SHA256 hash the combined bytes\n * 3. Return as the derived address\n *\n * @param seed - The 32-byte seed\n * @param programId - The program ID bytes (32 bytes)\n * @param ephemeral - Whether to derive an ephemeral address (affects prefix byte)\n * @returns The derived 32-byte address\n */\nexport async function deriveProgramAddress(\n seed: Uint8Array,\n programId: Uint8Array,\n ephemeral: boolean = false\n): Promise<Uint8Array> {\n if (seed.length !== 32) {\n throw new Error(`Expected 32-byte seed, got ${seed.length} bytes`);\n }\n if (programId.length !== 32) {\n throw new Error(`Expected 32-byte program ID, got ${programId.length} bytes`);\n }\n\n // Combine seed + program ID\n const combined = new Uint8Array(seed.length + programId.length);\n combined.set(seed, 0);\n combined.set(programId, seed.length);\n\n // SHA256 hash\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", combined);\n const result = new Uint8Array(hashBuffer);\n\n // Set the ephemeral bit in the first byte if needed\n // Ephemeral addresses have bit 0x80 set in the first byte\n if (ephemeral) {\n result[0] = result[0] | 0x80;\n } else {\n result[0] = result[0] & 0x7f;\n }\n\n return result;\n}\n\n/**\n * Derives the ABI account address for a given program account.\n *\n * @param programAccount - The program account address (ta-prefixed string or 32-byte array)\n * @param abiManagerProgramId - The ABI manager program ID (ta-prefixed string or 32-byte array)\n * @param ephemeral - Whether to derive an ephemeral address\n * @returns The derived ABI account address as a ta-prefixed string\n */\nexport async function deriveAbiAddress(\n programAccount: string | Uint8Array,\n abiManagerProgramId: string | Uint8Array,\n ephemeral: boolean = false\n): Promise<string> {\n // Convert string addresses to bytes\n const programAccountBytes = typeof programAccount === \"string\"\n ? decodeAddress(programAccount)\n : programAccount;\n\n const abiManagerBytes = typeof abiManagerProgramId === \"string\"\n ? decodeAddress(abiManagerProgramId)\n : abiManagerProgramId;\n\n // Derive the seed\n const seed = await deriveAbiSeed(programAccountBytes);\n\n // Derive the PDA\n const abiAccountBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);\n\n // Encode as ta-prefixed address\n return encodeAddress(abiAccountBytes);\n}\n","/**\n * ABI account state values\n */\nexport const ABI_STATE = {\n OPEN: 0x00,\n FINALIZED: 0x01,\n} as const;\n\nexport type AbiAccountState = (typeof ABI_STATE)[keyof typeof ABI_STATE];\n\n/**\n * Parsed header from an ABI account's on-chain data\n */\nexport interface AbiAccountHeader {\n /** The program meta account this ABI is associated with */\n programMetaAccount: Uint8Array;\n /** Revision number (incremented on each upgrade) */\n revision: bigint;\n /** Account state: OPEN (0) or FINALIZED (1) */\n state: AbiAccountState;\n /** Size of the ABI content in bytes */\n contentSize: number;\n}\n\n/**\n * Full ABI account data including parsed YAML content\n */\nexport interface AbiAccountData extends AbiAccountHeader {\n /** Raw ABI YAML content bytes */\n contentBytes: Uint8Array;\n /** ABI YAML content as string */\n content: string;\n}\n","import type { AbiAccountHeader, AbiAccountData, AbiAccountState } from \"./types\";\nimport { ABI_STATE } from \"./types\";\n\n/**\n * Size of the ABI account header in bytes:\n * - 32 bytes: program_meta_acc (pubkey)\n * - 8 bytes: revision (u64)\n * - 1 byte: state (u8)\n * - 4 bytes: content_sz (u32)\n * Total: 45 bytes\n */\nexport const ABI_ACCOUNT_HEADER_SIZE = 32 + 8 + 1 + 4;\n\n/**\n * Parses the header from ABI account data.\n *\n * @param data - Raw account data bytes\n * @returns Parsed header\n * @throws If data is too small for the header\n */\nexport function parseAbiAccountHeader(data: Uint8Array): AbiAccountHeader {\n if (data.length < ABI_ACCOUNT_HEADER_SIZE) {\n throw new Error(\n `ABI account data too small: ${data.length} bytes, expected at least ${ABI_ACCOUNT_HEADER_SIZE}`\n );\n }\n\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n // program_meta_acc: bytes 0-31 (32 bytes)\n const programMetaAccount = data.slice(0, 32);\n\n // revision: bytes 32-39 (8 bytes, little-endian u64)\n const revision = view.getBigUint64(32, true);\n\n // state: byte 40 (1 byte)\n const stateRaw = data[40];\n const state: AbiAccountState = stateRaw === ABI_STATE.FINALIZED\n ? ABI_STATE.FINALIZED\n : ABI_STATE.OPEN;\n\n // content_sz: bytes 41-44 (4 bytes, little-endian u32)\n const contentSize = view.getUint32(41, true);\n\n return {\n programMetaAccount,\n revision,\n state,\n contentSize,\n };\n}\n\n/**\n * Parses the full ABI account data including content.\n *\n * @param data - Raw account data bytes\n * @returns Parsed header and content\n * @throws If data is too small or content size exceeds available data\n */\nexport function parseAbiAccountData(data: Uint8Array): AbiAccountData {\n const header = parseAbiAccountHeader(data);\n\n const expectedSize = ABI_ACCOUNT_HEADER_SIZE + header.contentSize;\n if (data.length < expectedSize) {\n throw new Error(\n `ABI account data incomplete: ${data.length} bytes, expected ${expectedSize} (header + ${header.contentSize} content bytes)`\n );\n }\n\n const contentBytes = data.slice(ABI_ACCOUNT_HEADER_SIZE, ABI_ACCOUNT_HEADER_SIZE + header.contentSize);\n const content = new TextDecoder().decode(contentBytes);\n\n return {\n ...header,\n contentBytes,\n content,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/derivation.ts","../src/types.ts","../src/parser.ts"],"sourcesContent":["import { decodeAddress, encodeAddress } from \"@thru/helpers\";\n\nconst ABI_META_BODY_SIZE = 96;\nconst ABI_ACCOUNT_SUFFIX = \"_abi_account\";\nconst ABI_ACCOUNT_SUFFIX_BYTES = new TextEncoder().encode(ABI_ACCOUNT_SUFFIX);\n\nfunction concatBytes(...chunks: Uint8Array[]): Uint8Array {\n const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n}\n\nasync function sha256Bytes(data: Uint8Array): Promise<Uint8Array> {\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data as BufferSource);\n return new Uint8Array(hashBuffer);\n}\n\n/**\n * Builds the ABI meta body for an official ABI (program account).\n */\nexport function abiMetaBodyForProgram(programBytes: Uint8Array): Uint8Array {\n if (programBytes.length !== 32) {\n throw new Error(`Expected 32-byte program account, got ${programBytes.length} bytes`);\n }\n const body = new Uint8Array(ABI_META_BODY_SIZE);\n body.set(programBytes, 0);\n return body;\n}\n\n/**\n * Derives the ABI meta seed from ABI meta kind + body.\n */\nexport async function deriveAbiMetaSeed(kind: number, body: Uint8Array): Promise<Uint8Array> {\n if (body.length !== ABI_META_BODY_SIZE) {\n throw new Error(`Expected ${ABI_META_BODY_SIZE}-byte ABI meta body, got ${body.length} bytes`);\n }\n return sha256Bytes(concatBytes(new Uint8Array([kind]), body));\n}\n\n/**\n * Derives the ABI account seed from ABI meta kind + body.\n */\nexport async function deriveAbiAccountSeed(kind: number, body: Uint8Array): Promise<Uint8Array> {\n if (body.length !== ABI_META_BODY_SIZE) {\n throw new Error(`Expected ${ABI_META_BODY_SIZE}-byte ABI meta body, got ${body.length} bytes`);\n }\n return sha256Bytes(concatBytes(new Uint8Array([kind]), body, ABI_ACCOUNT_SUFFIX_BYTES));\n}\n\n/**\n * Derives a program-defined account address (owner || ephemeral || seed).\n */\nexport async function deriveProgramAddress(\n seed: Uint8Array,\n programId: Uint8Array,\n ephemeral: boolean = false\n): Promise<Uint8Array> {\n if (seed.length !== 32) {\n throw new Error(`Expected 32-byte seed, got ${seed.length} bytes`);\n }\n if (programId.length !== 32) {\n throw new Error(`Expected 32-byte program ID, got ${programId.length} bytes`);\n }\n\n const flag = new Uint8Array([ephemeral ? 1 : 0]);\n return sha256Bytes(concatBytes(programId, flag, seed));\n}\n\n/**\n * Derives the ABI meta account address (as a ta-prefixed string).\n */\nexport async function deriveAbiMetaAddress(\n kind: number,\n body: Uint8Array,\n abiManagerProgramId: string | Uint8Array,\n ephemeral: boolean = false\n): Promise<string> {\n const abiManagerBytes = typeof abiManagerProgramId === \"string\"\n ? decodeAddress(abiManagerProgramId)\n : abiManagerProgramId;\n const seed = await deriveAbiMetaSeed(kind, body);\n const addressBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);\n return encodeAddress(addressBytes);\n}\n\n/**\n * Derives the ABI account address (as a ta-prefixed string).\n */\nexport async function deriveAbiAddress(\n kind: number,\n body: Uint8Array,\n abiManagerProgramId: string | Uint8Array,\n ephemeral: boolean = false\n): Promise<string> {\n const abiManagerBytes = typeof abiManagerProgramId === \"string\"\n ? decodeAddress(abiManagerProgramId)\n : abiManagerProgramId;\n const seed = await deriveAbiAccountSeed(kind, body);\n const addressBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);\n return encodeAddress(addressBytes);\n}\n","/**\n * ABI account state values\n */\nexport const ABI_STATE = {\n OPEN: 0x00,\n FINALIZED: 0x01,\n} as const;\n\nexport type AbiAccountState = (typeof ABI_STATE)[keyof typeof ABI_STATE];\n\n/**\n * Parsed header from an ABI account's on-chain data\n */\nexport interface AbiAccountHeader {\n /** The ABI meta account this ABI is associated with */\n abiMetaAccount: Uint8Array;\n /** Revision number (incremented on each upgrade) */\n revision: bigint;\n /** Account state: OPEN (0) or FINALIZED (1) */\n state: AbiAccountState;\n /** Size of the ABI content in bytes */\n contentSize: number;\n}\n\n/**\n * Full ABI account data including parsed YAML content\n */\nexport interface AbiAccountData extends AbiAccountHeader {\n /** Raw ABI YAML content bytes */\n contentBytes: Uint8Array;\n /** ABI YAML content as string */\n content: string;\n}\n","import type { AbiAccountHeader, AbiAccountData, AbiAccountState } from \"./types\";\nimport { ABI_STATE } from \"./types\";\n\n/**\n * Size of the ABI account header in bytes:\n * - 32 bytes: abi_meta_acc (pubkey)\n * - 8 bytes: revision (u64)\n * - 1 byte: state (u8)\n * - 4 bytes: content_sz (u32)\n * Total: 45 bytes\n */\nexport const ABI_ACCOUNT_HEADER_SIZE = 32 + 8 + 1 + 4;\n\n/**\n * Parses the header from ABI account data.\n *\n * @param data - Raw account data bytes\n * @returns Parsed header\n * @throws If data is too small for the header\n */\nexport function parseAbiAccountHeader(data: Uint8Array): AbiAccountHeader {\n if (data.length < ABI_ACCOUNT_HEADER_SIZE) {\n throw new Error(\n `ABI account data too small: ${data.length} bytes, expected at least ${ABI_ACCOUNT_HEADER_SIZE}`\n );\n }\n\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n // abi_meta_acc: bytes 0-31 (32 bytes)\n const abiMetaAccount = data.slice(0, 32);\n\n // revision: bytes 32-39 (8 bytes, little-endian u64)\n const revision = view.getBigUint64(32, true);\n\n // state: byte 40 (1 byte)\n const stateRaw = data[40];\n const state: AbiAccountState = stateRaw === ABI_STATE.FINALIZED\n ? ABI_STATE.FINALIZED\n : ABI_STATE.OPEN;\n\n // content_sz: bytes 41-44 (4 bytes, little-endian u32)\n const contentSize = view.getUint32(41, true);\n\n return {\n abiMetaAccount,\n revision,\n state,\n contentSize,\n };\n}\n\n/**\n * Parses the full ABI account data including content.\n *\n * @param data - Raw account data bytes\n * @returns Parsed header and content\n * @throws If data is too small or content size exceeds available data\n */\nexport function parseAbiAccountData(data: Uint8Array): AbiAccountData {\n const header = parseAbiAccountHeader(data);\n\n const expectedSize = ABI_ACCOUNT_HEADER_SIZE + header.contentSize;\n if (data.length < expectedSize) {\n throw new Error(\n `ABI account data incomplete: ${data.length} bytes, expected ${expectedSize} (header + ${header.contentSize} content bytes)`\n );\n }\n\n const contentBytes = data.slice(ABI_ACCOUNT_HEADER_SIZE, ABI_ACCOUNT_HEADER_SIZE + header.contentSize);\n const content = new TextDecoder().decode(contentBytes);\n\n return {\n ...header,\n contentBytes,\n content,\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thru/abi-utils",
3
- "version": "0.1.38",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -11,7 +11,7 @@
11
11
  }
12
12
  },
13
13
  "dependencies": {
14
- "@thru/helpers": "0.1.38"
14
+ "@thru/helpers": "0.2.1"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/node": "^24.10.1",
@@ -23,6 +23,7 @@
23
23
  "build": "tsup",
24
24
  "dev": "tsup --watch",
25
25
  "test": "vitest run",
26
+ "test:run": "vitest run",
26
27
  "test:watch": "vitest watch",
27
28
  "clean": "rm -rf dist"
28
29
  }
package/src/derivation.ts CHANGED
@@ -1,50 +1,59 @@
1
1
  import { decodeAddress, encodeAddress } from "@thru/helpers";
2
2
 
3
+ const ABI_META_BODY_SIZE = 96;
4
+ const ABI_ACCOUNT_SUFFIX = "_abi_account";
5
+ const ABI_ACCOUNT_SUFFIX_BYTES = new TextEncoder().encode(ABI_ACCOUNT_SUFFIX);
6
+
7
+ function concatBytes(...chunks: Uint8Array[]): Uint8Array {
8
+ const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
9
+ const out = new Uint8Array(total);
10
+ let offset = 0;
11
+ for (const chunk of chunks) {
12
+ out.set(chunk, offset);
13
+ offset += chunk.length;
14
+ }
15
+ return out;
16
+ }
17
+
18
+ async function sha256Bytes(data: Uint8Array): Promise<Uint8Array> {
19
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data as BufferSource);
20
+ return new Uint8Array(hashBuffer);
21
+ }
22
+
3
23
  /**
4
- * Suffix appended to program account bytes for ABI seed derivation
24
+ * Builds the ABI meta body for an official ABI (program account).
5
25
  */
6
- const ABI_SEED_SUFFIX = "_abi_account";
26
+ export function abiMetaBodyForProgram(programBytes: Uint8Array): Uint8Array {
27
+ if (programBytes.length !== 32) {
28
+ throw new Error(`Expected 32-byte program account, got ${programBytes.length} bytes`);
29
+ }
30
+ const body = new Uint8Array(ABI_META_BODY_SIZE);
31
+ body.set(programBytes, 0);
32
+ return body;
33
+ }
7
34
 
8
35
  /**
9
- * Derives the ABI seed bytes from a program account pubkey.
10
- *
11
- * Algorithm:
12
- * 1. Get program account bytes (32 bytes)
13
- * 2. Append "_abi_account" suffix (12 bytes)
14
- * 3. SHA256 hash the combined 44 bytes
15
- * 4. Return the 32-byte hash as the seed
16
- *
17
- * @param programAccountBytes - The 32-byte program account public key
18
- * @returns 32-byte seed for PDA derivation
36
+ * Derives the ABI meta seed from ABI meta kind + body.
19
37
  */
20
- export async function deriveAbiSeed(programAccountBytes: Uint8Array): Promise<Uint8Array> {
21
- if (programAccountBytes.length !== 32) {
22
- throw new Error(`Expected 32-byte program account, got ${programAccountBytes.length} bytes`);
38
+ export async function deriveAbiMetaSeed(kind: number, body: Uint8Array): Promise<Uint8Array> {
39
+ if (body.length !== ABI_META_BODY_SIZE) {
40
+ throw new Error(`Expected ${ABI_META_BODY_SIZE}-byte ABI meta body, got ${body.length} bytes`);
23
41
  }
42
+ return sha256Bytes(concatBytes(new Uint8Array([kind]), body));
43
+ }
24
44
 
25
- // Combine program account bytes with suffix
26
- const suffixBytes = new TextEncoder().encode(ABI_SEED_SUFFIX);
27
- const combined = new Uint8Array(programAccountBytes.length + suffixBytes.length);
28
- combined.set(programAccountBytes, 0);
29
- combined.set(suffixBytes, programAccountBytes.length);
30
-
31
- // SHA256 hash
32
- const hashBuffer = await crypto.subtle.digest("SHA-256", combined);
33
- return new Uint8Array(hashBuffer);
45
+ /**
46
+ * Derives the ABI account seed from ABI meta kind + body.
47
+ */
48
+ export async function deriveAbiAccountSeed(kind: number, body: Uint8Array): Promise<Uint8Array> {
49
+ if (body.length !== ABI_META_BODY_SIZE) {
50
+ throw new Error(`Expected ${ABI_META_BODY_SIZE}-byte ABI meta body, got ${body.length} bytes`);
51
+ }
52
+ return sha256Bytes(concatBytes(new Uint8Array([kind]), body, ABI_ACCOUNT_SUFFIX_BYTES));
34
53
  }
35
54
 
36
55
  /**
37
- * Derives a program address (PDA) from a seed and program ID.
38
- *
39
- * This implements the Thru PDA derivation algorithm:
40
- * 1. Combine seed + program ID bytes
41
- * 2. SHA256 hash the combined bytes
42
- * 3. Return as the derived address
43
- *
44
- * @param seed - The 32-byte seed
45
- * @param programId - The program ID bytes (32 bytes)
46
- * @param ephemeral - Whether to derive an ephemeral address (affects prefix byte)
47
- * @returns The derived 32-byte address
56
+ * Derives a program-defined account address (owner || ephemeral || seed).
48
57
  */
49
58
  export async function deriveProgramAddress(
50
59
  seed: Uint8Array,
@@ -58,54 +67,40 @@ export async function deriveProgramAddress(
58
67
  throw new Error(`Expected 32-byte program ID, got ${programId.length} bytes`);
59
68
  }
60
69
 
61
- // Combine seed + program ID
62
- const combined = new Uint8Array(seed.length + programId.length);
63
- combined.set(seed, 0);
64
- combined.set(programId, seed.length);
65
-
66
- // SHA256 hash
67
- const hashBuffer = await crypto.subtle.digest("SHA-256", combined);
68
- const result = new Uint8Array(hashBuffer);
69
-
70
- // Set the ephemeral bit in the first byte if needed
71
- // Ephemeral addresses have bit 0x80 set in the first byte
72
- if (ephemeral) {
73
- result[0] = result[0] | 0x80;
74
- } else {
75
- result[0] = result[0] & 0x7f;
76
- }
70
+ const flag = new Uint8Array([ephemeral ? 1 : 0]);
71
+ return sha256Bytes(concatBytes(programId, flag, seed));
72
+ }
77
73
 
78
- return result;
74
+ /**
75
+ * Derives the ABI meta account address (as a ta-prefixed string).
76
+ */
77
+ export async function deriveAbiMetaAddress(
78
+ kind: number,
79
+ body: Uint8Array,
80
+ abiManagerProgramId: string | Uint8Array,
81
+ ephemeral: boolean = false
82
+ ): Promise<string> {
83
+ const abiManagerBytes = typeof abiManagerProgramId === "string"
84
+ ? decodeAddress(abiManagerProgramId)
85
+ : abiManagerProgramId;
86
+ const seed = await deriveAbiMetaSeed(kind, body);
87
+ const addressBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);
88
+ return encodeAddress(addressBytes);
79
89
  }
80
90
 
81
91
  /**
82
- * Derives the ABI account address for a given program account.
83
- *
84
- * @param programAccount - The program account address (ta-prefixed string or 32-byte array)
85
- * @param abiManagerProgramId - The ABI manager program ID (ta-prefixed string or 32-byte array)
86
- * @param ephemeral - Whether to derive an ephemeral address
87
- * @returns The derived ABI account address as a ta-prefixed string
92
+ * Derives the ABI account address (as a ta-prefixed string).
88
93
  */
89
94
  export async function deriveAbiAddress(
90
- programAccount: string | Uint8Array,
95
+ kind: number,
96
+ body: Uint8Array,
91
97
  abiManagerProgramId: string | Uint8Array,
92
98
  ephemeral: boolean = false
93
99
  ): Promise<string> {
94
- // Convert string addresses to bytes
95
- const programAccountBytes = typeof programAccount === "string"
96
- ? decodeAddress(programAccount)
97
- : programAccount;
98
-
99
100
  const abiManagerBytes = typeof abiManagerProgramId === "string"
100
101
  ? decodeAddress(abiManagerProgramId)
101
102
  : abiManagerProgramId;
102
-
103
- // Derive the seed
104
- const seed = await deriveAbiSeed(programAccountBytes);
105
-
106
- // Derive the PDA
107
- const abiAccountBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);
108
-
109
- // Encode as ta-prefixed address
110
- return encodeAddress(abiAccountBytes);
103
+ const seed = await deriveAbiAccountSeed(kind, body);
104
+ const addressBytes = await deriveProgramAddress(seed, abiManagerBytes, ephemeral);
105
+ return encodeAddress(addressBytes);
111
106
  }
package/src/index.ts CHANGED
@@ -1,4 +1,11 @@
1
- export { deriveAbiAddress, deriveAbiSeed, deriveProgramAddress } from "./derivation";
1
+ export {
2
+ abiMetaBodyForProgram,
3
+ deriveAbiAddress,
4
+ deriveAbiAccountSeed,
5
+ deriveAbiMetaAddress,
6
+ deriveAbiMetaSeed,
7
+ deriveProgramAddress,
8
+ } from "./derivation";
2
9
  export type { AbiAccountHeader, AbiAccountData, AbiAccountState } from "./types";
3
10
  export { ABI_STATE } from "./types";
4
11
  export { parseAbiAccountHeader, parseAbiAccountData, ABI_ACCOUNT_HEADER_SIZE } from "./parser";
package/src/parser.ts CHANGED
@@ -3,7 +3,7 @@ import { ABI_STATE } from "./types";
3
3
 
4
4
  /**
5
5
  * Size of the ABI account header in bytes:
6
- * - 32 bytes: program_meta_acc (pubkey)
6
+ * - 32 bytes: abi_meta_acc (pubkey)
7
7
  * - 8 bytes: revision (u64)
8
8
  * - 1 byte: state (u8)
9
9
  * - 4 bytes: content_sz (u32)
@@ -27,8 +27,8 @@ export function parseAbiAccountHeader(data: Uint8Array): AbiAccountHeader {
27
27
 
28
28
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
29
29
 
30
- // program_meta_acc: bytes 0-31 (32 bytes)
31
- const programMetaAccount = data.slice(0, 32);
30
+ // abi_meta_acc: bytes 0-31 (32 bytes)
31
+ const abiMetaAccount = data.slice(0, 32);
32
32
 
33
33
  // revision: bytes 32-39 (8 bytes, little-endian u64)
34
34
  const revision = view.getBigUint64(32, true);
@@ -43,7 +43,7 @@ export function parseAbiAccountHeader(data: Uint8Array): AbiAccountHeader {
43
43
  const contentSize = view.getUint32(41, true);
44
44
 
45
45
  return {
46
- programMetaAccount,
46
+ abiMetaAccount,
47
47
  revision,
48
48
  state,
49
49
  contentSize,
package/src/types.ts CHANGED
@@ -12,8 +12,8 @@ export type AbiAccountState = (typeof ABI_STATE)[keyof typeof ABI_STATE];
12
12
  * Parsed header from an ABI account's on-chain data
13
13
  */
14
14
  export interface AbiAccountHeader {
15
- /** The program meta account this ABI is associated with */
16
- programMetaAccount: Uint8Array;
15
+ /** The ABI meta account this ABI is associated with */
16
+ abiMetaAccount: Uint8Array;
17
17
  /** Revision number (incremented on each upgrade) */
18
18
  revision: bigint;
19
19
  /** Account state: OPEN (0) or FINALIZED (1) */