@ar.io/sdk 3.24.0 → 4.0.0-alpha.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 (169) hide show
  1. package/README.md +682 -600
  2. package/lib/esm/cli/cli.js +188 -152
  3. package/lib/esm/cli/commands/antCommands.js +23 -58
  4. package/lib/esm/cli/commands/arnsPurchaseCommands.js +48 -30
  5. package/lib/esm/cli/commands/escrowCommands.js +221 -0
  6. package/lib/esm/cli/commands/gatewayWriteCommands.js +142 -23
  7. package/lib/esm/cli/commands/pruneCommands.js +150 -0
  8. package/lib/esm/cli/commands/readCommands.js +22 -3
  9. package/lib/esm/cli/commands/transfer.js +6 -6
  10. package/lib/esm/cli/options.js +124 -58
  11. package/lib/esm/cli/utils.js +280 -174
  12. package/lib/esm/common/ant-registry.js +17 -143
  13. package/lib/esm/common/ant.js +44 -1167
  14. package/lib/esm/common/faucet.js +11 -6
  15. package/lib/esm/common/index.js +0 -4
  16. package/lib/esm/common/io.js +25 -1412
  17. package/lib/esm/constants.js +13 -19
  18. package/lib/esm/solana/ant-readable.js +724 -0
  19. package/lib/esm/solana/ant-registry-readable.js +133 -0
  20. package/lib/esm/solana/ant-registry-writeable.js +472 -0
  21. package/lib/esm/solana/ant-writeable.js +384 -0
  22. package/lib/esm/solana/ata.js +70 -0
  23. package/lib/esm/solana/canonical-message.js +128 -0
  24. package/lib/esm/solana/clusters.js +111 -0
  25. package/lib/esm/solana/constants.js +146 -0
  26. package/lib/esm/solana/delegation-math.js +112 -0
  27. package/lib/esm/solana/deserialize.js +711 -0
  28. package/lib/esm/solana/escrow.js +839 -0
  29. package/lib/{cjs/utils/json.js → esm/solana/events.js} +15 -10
  30. package/lib/esm/solana/funding-plan.js +699 -0
  31. package/lib/esm/solana/index.js +126 -0
  32. package/lib/esm/solana/instruction.js +39 -0
  33. package/lib/esm/solana/io-readable.js +2182 -0
  34. package/lib/esm/solana/io-writeable.js +3196 -0
  35. package/lib/esm/solana/json-rpc.js +90 -0
  36. package/lib/esm/solana/metadata.js +81 -0
  37. package/lib/esm/solana/mpl-core.js +192 -0
  38. package/lib/esm/solana/pda.js +332 -0
  39. package/lib/esm/solana/predict-prescribed-observers.js +110 -0
  40. package/lib/esm/solana/retry.js +117 -0
  41. package/lib/esm/solana/rpc-circuit-breaker.js +258 -0
  42. package/lib/esm/solana/send.js +372 -0
  43. package/lib/esm/solana/spawn-ant.js +224 -0
  44. package/lib/esm/solana/types.js +1 -0
  45. package/lib/esm/types/ant.js +27 -15
  46. package/lib/esm/types/io.js +8 -11
  47. package/lib/esm/utils/ant.js +0 -63
  48. package/lib/esm/utils/index.js +0 -3
  49. package/lib/esm/version.js +1 -1
  50. package/lib/types/cli/commands/antCommands.d.ts +5 -13
  51. package/lib/types/cli/commands/arnsPurchaseCommands.d.ts +33 -7
  52. package/lib/types/cli/commands/escrowCommands.d.ts +68 -0
  53. package/lib/types/cli/commands/gatewayWriteCommands.d.ts +12 -11
  54. package/lib/types/cli/commands/pruneCommands.d.ts +31 -0
  55. package/lib/types/cli/commands/readCommands.d.ts +27 -22
  56. package/lib/types/cli/commands/transfer.d.ts +9 -9
  57. package/lib/types/cli/options.d.ts +76 -21
  58. package/lib/types/cli/types.d.ts +11 -13
  59. package/lib/types/cli/utils.d.ts +71 -31
  60. package/lib/types/common/ant-registry.d.ts +49 -47
  61. package/lib/types/common/ant.d.ts +54 -539
  62. package/lib/types/common/faucet.d.ts +20 -8
  63. package/lib/types/common/index.d.ts +0 -3
  64. package/lib/types/common/io.d.ts +51 -263
  65. package/lib/types/constants.d.ts +11 -18
  66. package/lib/types/solana/ant-readable.d.ts +180 -0
  67. package/lib/types/solana/ant-registry-readable.d.ts +105 -0
  68. package/lib/types/solana/ant-registry-writeable.d.ts +249 -0
  69. package/lib/types/solana/ant-writeable.d.ts +177 -0
  70. package/lib/types/solana/ata.d.ts +44 -0
  71. package/lib/types/solana/canonical-message.d.ts +121 -0
  72. package/lib/types/solana/clusters.d.ts +109 -0
  73. package/lib/types/solana/constants.d.ts +119 -0
  74. package/lib/types/solana/delegation-math.d.ts +45 -0
  75. package/lib/types/solana/deserialize.d.ts +262 -0
  76. package/lib/types/solana/escrow.d.ts +480 -0
  77. package/lib/types/solana/events.d.ts +38 -0
  78. package/lib/types/solana/funding-plan.d.ts +225 -0
  79. package/lib/types/solana/index.d.ts +87 -0
  80. package/lib/types/solana/instruction.d.ts +39 -0
  81. package/lib/types/solana/io-readable.d.ts +499 -0
  82. package/lib/types/solana/io-writeable.d.ts +893 -0
  83. package/lib/types/solana/json-rpc.d.ts +47 -0
  84. package/lib/types/solana/metadata.d.ts +84 -0
  85. package/lib/types/solana/mpl-core.d.ts +120 -0
  86. package/lib/types/solana/pda.d.ts +95 -0
  87. package/lib/types/solana/predict-prescribed-observers.d.ts +28 -0
  88. package/lib/types/solana/retry.d.ts +62 -0
  89. package/lib/types/solana/rpc-circuit-breaker.d.ts +78 -0
  90. package/lib/types/solana/send.d.ts +94 -0
  91. package/lib/types/solana/spawn-ant.d.ts +145 -0
  92. package/lib/types/solana/types.d.ts +82 -0
  93. package/lib/types/types/ant-registry.d.ts +43 -4
  94. package/lib/types/types/ant.d.ts +114 -96
  95. package/lib/types/types/common.d.ts +18 -74
  96. package/lib/types/types/faucet.d.ts +2 -2
  97. package/lib/types/types/io.d.ts +244 -158
  98. package/lib/types/types/token.d.ts +0 -12
  99. package/lib/types/utils/ant.d.ts +1 -12
  100. package/lib/types/utils/index.d.ts +0 -3
  101. package/lib/types/version.d.ts +1 -1
  102. package/package.json +36 -33
  103. package/lib/cjs/cli/cli.js +0 -822
  104. package/lib/cjs/cli/commands/antCommands.js +0 -113
  105. package/lib/cjs/cli/commands/arnsPurchaseCommands.js +0 -212
  106. package/lib/cjs/cli/commands/gatewayWriteCommands.js +0 -210
  107. package/lib/cjs/cli/commands/readCommands.js +0 -215
  108. package/lib/cjs/cli/commands/transfer.js +0 -159
  109. package/lib/cjs/cli/options.js +0 -470
  110. package/lib/cjs/cli/types.js +0 -2
  111. package/lib/cjs/cli/utils.js +0 -639
  112. package/lib/cjs/common/ant-registry.js +0 -155
  113. package/lib/cjs/common/ant-versions.js +0 -93
  114. package/lib/cjs/common/ant.js +0 -1182
  115. package/lib/cjs/common/arweave.js +0 -27
  116. package/lib/cjs/common/contracts/ao-process.js +0 -224
  117. package/lib/cjs/common/error.js +0 -64
  118. package/lib/cjs/common/faucet.js +0 -150
  119. package/lib/cjs/common/hyperbeam/hb.js +0 -173
  120. package/lib/cjs/common/index.js +0 -42
  121. package/lib/cjs/common/io.js +0 -1423
  122. package/lib/cjs/common/logger.js +0 -83
  123. package/lib/cjs/common/loggers/winston.js +0 -68
  124. package/lib/cjs/common/marketplace.js +0 -731
  125. package/lib/cjs/common/turbo.js +0 -223
  126. package/lib/cjs/constants.js +0 -41
  127. package/lib/cjs/node/index.js +0 -39
  128. package/lib/cjs/package.json +0 -1
  129. package/lib/cjs/types/ant-registry.js +0 -2
  130. package/lib/cjs/types/ant.js +0 -168
  131. package/lib/cjs/types/common.js +0 -2
  132. package/lib/cjs/types/faucet.js +0 -2
  133. package/lib/cjs/types/index.js +0 -37
  134. package/lib/cjs/types/io.js +0 -51
  135. package/lib/cjs/types/token.js +0 -116
  136. package/lib/cjs/utils/ant.js +0 -108
  137. package/lib/cjs/utils/ao.js +0 -432
  138. package/lib/cjs/utils/arweave.js +0 -285
  139. package/lib/cjs/utils/base64.js +0 -62
  140. package/lib/cjs/utils/hash.js +0 -56
  141. package/lib/cjs/utils/index.js +0 -38
  142. package/lib/cjs/utils/processes.js +0 -173
  143. package/lib/cjs/utils/random.js +0 -30
  144. package/lib/cjs/utils/schema.js +0 -15
  145. package/lib/cjs/utils/url.js +0 -37
  146. package/lib/cjs/version.js +0 -20
  147. package/lib/cjs/web/index.js +0 -41
  148. package/lib/esm/common/ant-versions.js +0 -87
  149. package/lib/esm/common/arweave.js +0 -21
  150. package/lib/esm/common/contracts/ao-process.js +0 -220
  151. package/lib/esm/common/hyperbeam/hb.js +0 -169
  152. package/lib/esm/common/marketplace.js +0 -724
  153. package/lib/esm/common/turbo.js +0 -215
  154. package/lib/esm/node/index.js +0 -20
  155. package/lib/esm/utils/ao.js +0 -420
  156. package/lib/esm/utils/arweave.js +0 -271
  157. package/lib/esm/utils/processes.js +0 -167
  158. package/lib/esm/web/index.js +0 -20
  159. package/lib/types/common/ant-versions.d.ts +0 -39
  160. package/lib/types/common/arweave.d.ts +0 -17
  161. package/lib/types/common/contracts/ao-process.d.ts +0 -47
  162. package/lib/types/common/hyperbeam/hb.d.ts +0 -88
  163. package/lib/types/common/marketplace.d.ts +0 -568
  164. package/lib/types/common/turbo.d.ts +0 -61
  165. package/lib/types/node/index.d.ts +0 -20
  166. package/lib/types/utils/ao.d.ts +0 -80
  167. package/lib/types/utils/arweave.d.ts +0 -79
  168. package/lib/types/utils/processes.d.ts +0 -39
  169. package/lib/types/web/index.d.ts +0 -20
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Helpers for JSON-RPC reads against {@link SolanaRpc} that return a
18
+ * web3.js-shaped `AccountInfo` (Buffer-backed `data`, plain Address strings).
19
+ * Used by the ACL/AntRegistry path so the deserializers can stay agnostic of
20
+ * the RPC client's response shape.
21
+ */
22
+ import { address } from '@solana/kit';
23
+ import { withRetry } from './retry.js';
24
+ /**
25
+ * Map an arbitrary commitment string to one of kit's three supported tiers.
26
+ * Anything we don't recognise (or `undefined`) falls back to `confirmed`,
27
+ * which is the project-wide default for read paths.
28
+ */
29
+ function toKitCommitment(commitment) {
30
+ if (commitment === 'finalized' ||
31
+ commitment === 'confirmed' ||
32
+ commitment === 'processed') {
33
+ return commitment;
34
+ }
35
+ return 'confirmed';
36
+ }
37
+ /**
38
+ * Fetch a single account and decode its data into a Buffer-backed shape that
39
+ * looks like the legacy `web3.js` `AccountInfo`. Returns `null` if the account
40
+ * doesn't exist (so callers can handle "missing PDA" without try/catch).
41
+ */
42
+ export async function getAccountInfoLegacy(rpc, pda, commitment) {
43
+ const res = await withRetry(() => rpc
44
+ .getAccountInfo(pda, {
45
+ encoding: 'base64',
46
+ commitment: toKitCommitment(commitment),
47
+ })
48
+ .send());
49
+ if (!res.value)
50
+ return null;
51
+ const [dataB64] = res.value.data;
52
+ return {
53
+ data: Buffer.from(dataB64, 'base64'),
54
+ owner: address(res.value.owner),
55
+ lamports: Number(res.value.lamports),
56
+ executable: res.value.executable,
57
+ rentEpoch: 0,
58
+ };
59
+ }
60
+ /**
61
+ * Fetch multiple accounts in a single RPC round-trip and decode each into
62
+ * the legacy `AccountInfo` shape. Missing accounts come back as `null`,
63
+ * preserving 1:1 alignment with the input `pdas` array.
64
+ *
65
+ * Used by paginated readers (ACL pages, etc.) to load all sibling pages
66
+ * via `getMultipleAccountsInfo` rather than firing N parallel
67
+ * `getAccountInfo` calls.
68
+ */
69
+ export async function getMultipleAccountsInfoLegacy(rpc, pdas, commitment) {
70
+ if (pdas.length === 0)
71
+ return [];
72
+ const res = await withRetry(() => rpc
73
+ .getMultipleAccounts(pdas, {
74
+ encoding: 'base64',
75
+ commitment: toKitCommitment(commitment),
76
+ })
77
+ .send());
78
+ return res.value.map((acct) => {
79
+ if (!acct)
80
+ return null;
81
+ const [dataB64] = acct.data;
82
+ return {
83
+ data: Buffer.from(dataB64, 'base64'),
84
+ owner: address(acct.owner),
85
+ lamports: Number(acct.lamports),
86
+ executable: acct.executable,
87
+ rentEpoch: 0,
88
+ };
89
+ });
90
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Metaplex-standard JSON metadata builder for AR.IO ANT NFTs.
18
+ *
19
+ * The Core asset's `uri` field on chain points at a JSON file with this
20
+ * shape; marketplaces and DAS providers fetch + parse it for their
21
+ * inline name/image/description display. The 3 ArNS traits (`ArNS Name`,
22
+ * `Type`, `Undername Limit`) live in the on-chain Attributes plugin, NOT
23
+ * in this JSON — see ADR-012.
24
+ *
25
+ * This helper produces the exact same JSON shape as the migration import
26
+ * (`migration/import/src/metadata.ts::buildAntMetadata`); the two paths
27
+ * MUST stay in lock-step or migrated and freshly-spawned ANTs will
28
+ * render differently in marketplace UIs. A regression test in
29
+ * `spawn-ant.test.ts` asserts byte-equality between the two for matching
30
+ * inputs.
31
+ *
32
+ * Pure function. No network, no Turbo, no dependencies. Caller handles
33
+ * uploading the resulting JSON to Arweave (e.g. via `@ardrive/turbo-sdk`
34
+ * with a `HexSolanaSigner` — free for files under 100 KiB) and passes the
35
+ * resulting `ar://${txid}` to `spawnSolanaANT`'s `state.uri`.
36
+ */
37
+ // Re-export the SDK-canonical AR.IO logo TX ID + ar:// protocol from the
38
+ // shared constants module so this metadata builder stays in lock-step with
39
+ // the rest of the SDK + the migration import package's JSON output.
40
+ export { ARIO_LOGO_TX_ID, AR_IO_PROTOCOL as AR_PROTOCOL, } from '../constants.js';
41
+ import { ARIO_LOGO_TX_ID, AR_IO_PROTOCOL as AR_PROTOCOL, } from '../constants.js';
42
+ function makeUri(txId, gateway) {
43
+ return gateway ? `https://${gateway}/raw/${txId}` : `${AR_PROTOCOL}${txId}`;
44
+ }
45
+ /**
46
+ * Build ANT NFT JSON metadata.
47
+ *
48
+ * Output is byte-identical to the migration import's `buildAntMetadata`
49
+ * for matching inputs. Defaults to `ar://` URLs (ADR-012 canonical); pass
50
+ * `gateway` to opt into https URLs.
51
+ */
52
+ export function buildAntMetadata(params) {
53
+ const logoTxId = params.logoTxId || ARIO_LOGO_TX_ID;
54
+ const ticker = params.ticker || 'ANT';
55
+ const arnsName = params.arnsName;
56
+ const gateway = params.gateway;
57
+ const description = params.description ||
58
+ (arnsName
59
+ ? `Arweave Name Token for ${arnsName}.ar.io`
60
+ : 'Arweave Name Token');
61
+ const logoUri = makeUri(logoTxId, gateway);
62
+ const metadata = {
63
+ name: arnsName || params.name,
64
+ symbol: ticker,
65
+ description,
66
+ image: logoUri,
67
+ properties: {
68
+ files: [{ uri: logoUri, type: 'image/png' }],
69
+ // Metaplex standard categories are image|video|audio|vr|html. The
70
+ // semantic "this is an ANT for an ArNS domain" is conveyed by the
71
+ // on-chain Attributes plugin (Type=lease/permabuy), not this JSON.
72
+ category: 'image',
73
+ },
74
+ };
75
+ if (arnsName) {
76
+ metadata.external_url = gateway
77
+ ? `https://${arnsName}.ar.io`
78
+ : `${AR_PROTOCOL}${arnsName}`;
79
+ }
80
+ return metadata;
81
+ }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Reader for the on-chain Metaplex Core asset (`AssetV1` + plugin chain).
18
+ *
19
+ * The codama-generated decoders in `generated/mpl-core` only cover the
20
+ * fixed-shape header section (`AssetV1`, `PluginHeaderV1`, etc.) — they
21
+ * don't know how to follow the variable-offset registry chain to a
22
+ * specific plugin payload. This module fills that gap with a small
23
+ * walker that:
24
+ *
25
+ * 1. decodes the `AssetV1` prefix (key + owner + update authority +
26
+ * name + uri + seq);
27
+ * 2. follows the `PluginHeaderV1.pluginRegistryOffset` to the
28
+ * `PluginRegistryV1`;
29
+ * 3. iterates registry records to find the requested plugin variant;
30
+ * 4. decodes the `Plugin` enum at the registry record's offset.
31
+ *
32
+ * The same walk lives on-chain in `programs/ario-arns/src/state/mod.rs`
33
+ * (`read_mpl_core_attribute`) and `programs/ario-core/src/mpl_core.rs`
34
+ * (`read_ant_program`). The three implementations are pinned against
35
+ * each other by the migration import's edge-case fixtures and unit
36
+ * tests at all three layers.
37
+ *
38
+ * Reading is best-effort: any parse failure returns `null` rather than
39
+ * throwing, so callers can fall back to canonical defaults
40
+ * (e.g. `ARIO_ANT_PROGRAM_ID`) when an asset was minted without the
41
+ * `ANT Program` attribute or has a layout the walker doesn't recognise.
42
+ */
43
+ import { fetchEncodedAccount, } from '@solana/kit';
44
+ import { PluginType, getAssetV1Decoder, getPluginDecoder, getPluginHeaderV1Decoder, getPluginRegistryV1Decoder, } from '@ar.io/solana-contracts/mpl-core';
45
+ import { ARIO_ANT_PROGRAM_ID } from './constants.js';
46
+ /**
47
+ * On-chain trait keys. Marketplaces and DAS indexers query these by
48
+ * exact string match — keep in lock-step with:
49
+ * - `migration/import/src/phases/phase2-ants.ts`
50
+ * - `programs/ario-arns/src/mpl_core_cpi.rs::TRAIT_KEY_*`
51
+ * - `programs/ario-core/src/mpl_core.rs::TRAIT_KEY_ANT_PROGRAM`
52
+ */
53
+ export const TRAIT_KEY_ARNS_NAME = 'ArNS Name';
54
+ export const TRAIT_KEY_TYPE = 'Type';
55
+ export const TRAIT_KEY_UNDERNAME_LIMIT = 'Undername Limit';
56
+ export const TRAIT_KEY_ANT_PROGRAM = 'ANT Program';
57
+ /**
58
+ * Read a single attribute value from a Metaplex Core asset's Attributes
59
+ * plugin. Returns `null` when the asset has no plugin section, has no
60
+ * Attributes plugin, the requested key is absent, or any layer of the
61
+ * walk fails to decode. This is a best-effort lookup — callers should
62
+ * use a canonical default rather than treating absence as an error.
63
+ *
64
+ * `data` is the raw account data (post-discriminator? no — MPL Core
65
+ * doesn't use the 8-byte Anchor discriminator, the asset is the
66
+ * account's full data starting from the `Key` enum byte).
67
+ */
68
+ export function readAttribute(data, key) {
69
+ try {
70
+ // ── 1. Asset header (variable size — name and uri are length-prefixed).
71
+ const [, afterAsset] = getAssetV1Decoder().read(data, 0);
72
+ // No plugin section → no attributes.
73
+ if (afterAsset >= data.length)
74
+ return null;
75
+ // ── 2. PluginHeaderV1: 9 bytes (1-byte key + u64 registry offset).
76
+ const [pluginHeader] = getPluginHeaderV1Decoder().read(data, afterAsset);
77
+ const registryOffset = Number(pluginHeader.pluginRegistryOffset);
78
+ if (registryOffset >= data.length)
79
+ return null;
80
+ // ── 3. PluginRegistryV1: list of (pluginType, authority, offset).
81
+ const [registry] = getPluginRegistryV1Decoder().read(data, registryOffset);
82
+ for (const record of registry.registry) {
83
+ // `pluginType` is the kit-decoded numeric `PluginType` enum value
84
+ // (e.g. `PluginType.Attributes === 6`). The matching `Plugin`
85
+ // payload at `record.offset` is a discriminated union whose
86
+ // `__kind` is the string variant name — so we use the numeric
87
+ // enum here and the string tag below.
88
+ if (record.pluginType !== PluginType.Attributes)
89
+ continue;
90
+ const [plugin] = getPluginDecoder().read(data, Number(record.offset));
91
+ if (plugin.__kind !== 'Attributes')
92
+ continue;
93
+ const attrs = plugin.fields[0].attributeList;
94
+ const found = attrs.find((a) => a.key === key);
95
+ return found ? found.value : null;
96
+ }
97
+ return null;
98
+ }
99
+ catch {
100
+ // Any decode failure (truncated buffer, unknown plugin variant, etc.)
101
+ // — treat as "no override" and let the caller fall back.
102
+ return null;
103
+ }
104
+ }
105
+ /**
106
+ * Convenience wrapper: fetch the asset account and parse its
107
+ * `ANT Program` attribute. Returns `null` when the account doesn't
108
+ * exist, has no `ANT Program` trait, or the value can't be parsed —
109
+ * callers should fall back to the canonical `ARIO_ANT_PROGRAM_ID`.
110
+ *
111
+ * Importing this here (rather than wiring it directly into the resolver
112
+ * paths) lets `ant-readable.ts` keep its constructor synchronous and
113
+ * have a separate async `fromAsset(rpc, mint)` factory that does the
114
+ * lookup once and caches the result.
115
+ */
116
+ export async function fetchAntProgramFromAsset(rpc, mint, config) {
117
+ const account = await fetchEncodedAccount(rpc, mint, config);
118
+ if (!account.exists)
119
+ return null;
120
+ const value = readAttribute(account.data, TRAIT_KEY_ANT_PROGRAM);
121
+ if (value === null)
122
+ return null;
123
+ // The ANT Program attribute is a base58-encoded program address.
124
+ // We don't validate length here — the kit `Address` brand is
125
+ // structural and downstream `getProgramDerivedAddress` will reject
126
+ // malformed values. Returning `null` on missing keeps the call site
127
+ // simple ("found a value or didn't"); a malformed value is a holder
128
+ // self-grief that surfaces at the next PDA derivation.
129
+ return value;
130
+ }
131
+ /**
132
+ * Decide which ANT program id to trust for a SIGNING (write) transaction.
133
+ *
134
+ * The `ANT Program` trait returned by {@link fetchAntProgramFromAsset} is read
135
+ * from Metaplex Core asset / RPC data and is NOT authenticated — a malicious
136
+ * asset owner, or a spoofed/compromised RPC response, can set it to an
137
+ * attacker-controlled program. Write instructions use this value as the
138
+ * instruction `programAddress` while including the caller as a signer, so
139
+ * silently trusting a non-canonical detected value would let an attacker route
140
+ * a victim's signed transaction to their own program and inherit signer /
141
+ * writable privileges over the included accounts.
142
+ *
143
+ * Trust rules — BYO-ANT (ADR-016 / BD-100) stays supported, but only via
144
+ * explicit opt-in:
145
+ * - An `explicit` program id (the caller passed `antProgramId`) is always
146
+ * honored — the caller has taken responsibility for it.
147
+ * - Otherwise a detected value is honored only when it is `null` (no trait)
148
+ * or equals the canonical {@link ARIO_ANT_PROGRAM_ID}.
149
+ * - A detected NON-canonical value with no explicit opt-in throws, rather
150
+ * than silently signing against an untrusted program.
151
+ *
152
+ * Read-only paths never sign, so they may auto-detect freely; this guard is
153
+ * only for the write path.
154
+ */
155
+ export function resolveWriteAntProgram(args) {
156
+ const canonical = args.canonical ?? ARIO_ANT_PROGRAM_ID;
157
+ if (args.explicit !== undefined)
158
+ return args.explicit;
159
+ if (args.detected === null || args.detected === canonical)
160
+ return canonical;
161
+ throw new Error(`ANT.init auto-detected a non-canonical ANT program (${args.detected}) ` +
162
+ `from the asset's "${TRAIT_KEY_ANT_PROGRAM}" trait. That value is read ` +
163
+ `from asset/RPC data and is not authenticated, so the SDK refuses to ` +
164
+ `build a *signed* transaction against it implicitly (doing so could ` +
165
+ `route your signature to an attacker-controlled program). To use a ` +
166
+ `third-party (BYO-ANT) program for writes, pass it explicitly: ` +
167
+ `ANT.init({ ..., antProgramId }).`);
168
+ }
169
+ /**
170
+ * Fetch the current owner of an MPL Core asset. Returns `null` when the
171
+ * account doesn't exist or the AssetV1 layout can't be decoded.
172
+ *
173
+ * Used by `SolanaARIOWriteable` to decide whether to bundle
174
+ * `ant.sync_attributes` into a buy / manage tx. The Attributes plugin's
175
+ * `BasePluginAuthority` is `Owner`, so only the current asset holder
176
+ * can sign the inner CPI; if the caller isn't the holder, bundling
177
+ * would abort the whole tx (BD-095 — non-holder ArNS lease management
178
+ * must continue to succeed; the actual ANT owner can call the public
179
+ * `syncAttributes` later to converge state).
180
+ */
181
+ export async function fetchMplCoreOwner(rpc, mint, config) {
182
+ const account = await fetchEncodedAccount(rpc, mint, config);
183
+ if (!account.exists)
184
+ return null;
185
+ try {
186
+ const [asset] = getAssetV1Decoder().read(account.data, 0);
187
+ return asset.owner;
188
+ }
189
+ catch {
190
+ return null;
191
+ }
192
+ }