@ar.io/sdk 3.24.0 → 4.0.0-alpha.2

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 +757 -589
  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 +227 -0
  6. package/lib/esm/cli/commands/gatewayWriteCommands.js +140 -23
  7. package/lib/esm/cli/commands/pruneCommands.js +154 -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 +303 -175
  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 +17 -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 +66 -258
  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,249 @@
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
+ * Solana implementation of the ANT Registry write interface.
18
+ *
19
+ * This class owns the per-user paginated ACL surface (ADR-012). After
20
+ * the on-chain hardening pass, the *primary* contract handlers
21
+ * (`add_controller`, `remove_controller`, `transfer`) write the ACL
22
+ * inline as part of their own instruction — Codama renders the ACL
23
+ * accounts as required, so callers cannot bypass them. The registry's
24
+ * job is therefore split in two:
25
+ *
26
+ * 1. **Preflight resolution.** Pick the right `AclConfig` + `AclPage`
27
+ * to pass for a record / remove operation, and emit the
28
+ * `register_acl_config` / `add_acl_page` ixs needed to bootstrap
29
+ * missing accounts. See `resolveDestinationAclAccounts` and
30
+ * `resolveSourceAclAccountsForEntry`.
31
+ * 2. **Bulk maintenance.** For operations the contract can't bundle
32
+ * atomically (notably the variable-length ex-controller cleanup
33
+ * after a transfer, plus any caller-driven heal flows), expose
34
+ * `planAclMaintenance` + the standalone `record_acl_*` /
35
+ * `remove_acl_*` instruction builders. `SolanaANTWriteable`
36
+ * forwards an `aclOps` array to `sendTransaction` for these.
37
+ *
38
+ * Why the registry, not `SolanaANTWriteable`?
39
+ * The ACL is a per-user structure shared across every ANT a user
40
+ * touches, so the right home for the page-selection / preflight logic
41
+ * is the registry itself. `SolanaANTWriteable` composes a
42
+ * `SolanaANTRegistryWriteable` and delegates ACL planning to it.
43
+ *
44
+ * Per-user ACL layout (recap):
45
+ * - `AclConfig` head at `["acl_config", user]` tracks `page_count` +
46
+ * `total_entries`.
47
+ * - Each `AclPage` is a content-addressable PDA at
48
+ * `["acl_page", user, page_idx_le]` holding up to
49
+ * `MAX_ACL_PAGE_ENTRIES` `(asset, role)` tuples.
50
+ *
51
+ * NOTE: `register_acl_config` and `add_acl_page` are permissionless —
52
+ * anyone can pay rent on behalf of any user. `payer` (the writeable
53
+ * registry's signer) acts as the rent payer for everything bundled here.
54
+ */
55
+ import { type Address, type Instruction, type TransactionSigner } from '@solana/kit';
56
+ import type { ANTRegistryWrite, AclMaintenanceOp, AclMaintenanceRole } from '../types/ant-registry.js';
57
+ import type { MessageResult } from '../types/common.js';
58
+ import { type SolanaANTRegistryConfig, SolanaANTRegistryReadable } from './ant-registry-readable.js';
59
+ export type SolanaANTRegistryWriteableConfig = SolanaANTRegistryConfig & {
60
+ /** Pays rent on `register_acl_config` / `add_acl_page` and authorises ix bundles. */
61
+ signer: TransactionSigner;
62
+ };
63
+ export declare class SolanaANTRegistryWriteable extends SolanaANTRegistryReadable implements ANTRegistryWrite {
64
+ protected readonly signer: TransactionSigner;
65
+ constructor(config: SolanaANTRegistryWriteableConfig);
66
+ /**
67
+ * The Solana ANT registry does not have a centralised "register" step —
68
+ * `AclConfig` is created lazily the first time a user becomes an owner
69
+ * or controller (via `register_acl_config`, which `planAclMaintenance`
70
+ * emits automatically). This method exists only to satisfy the
71
+ * cross-backend `ANTRegistryWrite` interface.
72
+ */
73
+ register(_params: {
74
+ processId: string;
75
+ }): Promise<MessageResult>;
76
+ /**
77
+ * Pure PDA derivation — no RPC. Useful for callers that already
78
+ * resolved the page via `resolveSourceAclAccountsForEntry` and need a
79
+ * fallback PDA (e.g. `removeController` when the entry can't be found
80
+ * but we still need to pass *some* page address to the contract so
81
+ * the on-chain handler returns the right error).
82
+ */
83
+ deriveAclConfigPda(user: Address): Promise<Address>;
84
+ /** Pure PDA derivation — see {@link deriveAclConfigPda}. */
85
+ deriveAclPagePda(user: Address, pageIdx: bigint): Promise<Address>;
86
+ /**
87
+ * Pick the `AclConfig` + destination `AclPage` to wire into a contract
88
+ * handler that is about to **record** an entry for `user` (e.g.
89
+ * `ario-ant::add_controller`, `ario-ant::transfer`'s new-owner side).
90
+ *
91
+ * Behaviour mirrors the planner's record path:
92
+ * - If `AclConfig(user)` does not exist yet, emit
93
+ * `register_acl_config` so the on-chain handler's seed-binding
94
+ * resolves.
95
+ * - If every existing `AclPage` is at `MAX_ACL_PAGE_ENTRIES`, emit
96
+ * `add_acl_page` for `page_idx == page_count` and use it as the
97
+ * destination.
98
+ * - Otherwise pick the **first non-full page** so density recovers
99
+ * after a `swap_remove` left a mid-life page sparse (see
100
+ * `docs/ACCOUNT_SCALING_PATTERNS.md` § Pattern C).
101
+ *
102
+ * Returns the resolved PDAs plus any prep ixs the caller must
103
+ * **prepend** to the bundle. Idempotent: safe to call again on a
104
+ * partially-bootstrapped ACL — only the missing prep ixs come back.
105
+ *
106
+ * The on-chain handler still validates `acl_config.user == user` and
107
+ * the page seed binding, so a stale resolution simply fails the tx;
108
+ * over-emission is bounded by the current page layout.
109
+ */
110
+ resolveDestinationAclAccounts(params: {
111
+ user: Address;
112
+ }): Promise<{
113
+ aclConfigPda: Address;
114
+ aclPagePda: Address;
115
+ pageIdx: bigint;
116
+ prepIxs: Instruction[];
117
+ }>;
118
+ /**
119
+ * Locate the `AclPage` that currently holds `(asset, role)` for
120
+ * `user`, so a contract handler that is about to **remove** the entry
121
+ * (`ario-ant::remove_controller`, `ario-ant::transfer`'s old-owner
122
+ * side) can be wired with the right page accounts.
123
+ *
124
+ * Returns `null` if `user` has no `AclConfig` head or no matching
125
+ * entry — callers that want strict semantics should treat that as "no
126
+ * record to remove" and either skip the wrapped ix entirely (when the
127
+ * primary mutation is also unnecessary) or fall back to the standalone
128
+ * `remove_acl_*` heal flow.
129
+ *
130
+ * The on-chain handler does the strict check via `position_of` on
131
+ * the supplied page, so a wrong / stale resolution fails the tx with
132
+ * `AclEntryNotFound` rather than corrupting state.
133
+ */
134
+ resolveSourceAclAccountsForEntry(params: {
135
+ user: Address;
136
+ asset: Address;
137
+ role: AclMaintenanceRole;
138
+ }): Promise<{
139
+ aclConfigPda: Address;
140
+ aclPagePda: Address;
141
+ pageIdx: bigint;
142
+ } | null>;
143
+ /**
144
+ * Build a `register_acl_config` instruction. Permissionless: any wallet
145
+ * can pay to bootstrap an ACL head for any user.
146
+ */
147
+ buildRegisterAclConfigIx(params: {
148
+ user: Address;
149
+ }): Promise<Instruction>;
150
+ /**
151
+ * Build an `add_acl_page` instruction that appends the next page (i.e.
152
+ * page `page_count`) to a user's ACL. Caller must derive `pageIdx` from
153
+ * a fresh read of `AclConfig.page_count` to avoid colliding with an
154
+ * existing PDA — `planAclMaintenance` does this for you.
155
+ */
156
+ buildAddAclPageIx(params: {
157
+ user: Address;
158
+ pageIdx: bigint;
159
+ }): Promise<Instruction>;
160
+ /** Build a `record_acl_*` instruction for the given role. */
161
+ buildRecordIx(params: {
162
+ user: Address;
163
+ asset: Address;
164
+ role: AclMaintenanceRole;
165
+ pageIdx: bigint;
166
+ }): Promise<Instruction>;
167
+ /** Build a `remove_acl_*` instruction for the given role. */
168
+ buildRemoveIx(params: {
169
+ user: Address;
170
+ asset: Address;
171
+ role: AclMaintenanceRole;
172
+ pageIdx: bigint;
173
+ }): Promise<Instruction>;
174
+ /**
175
+ * Close the trailing `AclPage` (must be the last page and empty).
176
+ * Returns rent to `beneficiary`, which the on-chain handler enforces
177
+ * equals `acl_config.user`.
178
+ */
179
+ buildCloseAclPageIx(params: {
180
+ user: Address;
181
+ pageIdx: bigint;
182
+ beneficiary: Address;
183
+ }): Promise<Instruction>;
184
+ /**
185
+ * Close `AclConfig` once `page_count == 0` and `total_entries == 0`.
186
+ * Returns rent to `beneficiary`, which must equal `acl_config.user`
187
+ * on-chain.
188
+ */
189
+ buildCloseAclConfigIx(params: {
190
+ user: Address;
191
+ beneficiary: Address;
192
+ }): Promise<Instruction>;
193
+ /**
194
+ * Build the ACL ixs needed to bootstrap a freshly-spawned ANT's
195
+ * paginated owner ACL. The on-chain `initialize` handler seeds
196
+ * `ant_controllers = vec![owner]` (matches the Lua source), so the
197
+ * owner is recorded under **both** roles: `Owner` (for "ANTs I own"
198
+ * lookups) and `Controller` (for "ANTs I can manage" lookups).
199
+ *
200
+ * Returns the instructions in dependency order — `register_acl_config`
201
+ * → `add_acl_page` → `record_acl_owner` → `record_acl_controller`.
202
+ * Caller bundles them into the same tx as the MPL Core create + ANT
203
+ * `initialize` ixs so the ACL is atomic with the spawn.
204
+ */
205
+ bootstrapOwnerOnSpawn(params: {
206
+ owner: Address;
207
+ asset: Address;
208
+ }): Promise<Instruction[]>;
209
+ /**
210
+ * Build the `remove_acl_controller` ixs needed to clean up an ANT's
211
+ * ex-controller ACL entries after a transfer. The contract handler
212
+ * for `transfer` cannot atomically `swap_remove` each ex-controller
213
+ * (variable-length, no clean Codama representation), so the SDK
214
+ * bundles them via this helper instead.
215
+ *
216
+ * Idempotent (skips controllers whose ACL entry is already absent),
217
+ * so it's safe to call against a stale snapshot of `AntControllers`.
218
+ */
219
+ bulkRemoveControllerEntries(params: {
220
+ asset: Address;
221
+ controllers: ReadonlyArray<string>;
222
+ }): Promise<Instruction[]>;
223
+ /**
224
+ * Resolve an array of desired ACL mutations into the minimum
225
+ * instruction set needed to make them happen. For each unique user:
226
+ * - reads the `AclConfig` head once (and all `AclPage`s in one
227
+ * `getMultipleAccountsInfo` round trip)
228
+ * - prepends `register_acl_config` if the head is missing AND any
229
+ * `action: 'record'` op targets that user
230
+ * - emits `add_acl_page` whenever the existing pages have no room
231
+ * - drops `action: 'record'` ops where the entry already exists (no-op)
232
+ * - drops `action: 'remove'` ops where the entry is already absent (no-op)
233
+ *
234
+ * Returned instructions preserve the dependency order:
235
+ * `register_acl_config` → `add_acl_page` → record/remove ixs that
236
+ * target the new page.
237
+ *
238
+ * Page selection on append: we fill the **first non-full page** so
239
+ * density recovers naturally after a `swap_remove` made a mid-life
240
+ * page sparse (see `docs/ACCOUNT_SCALING_PATTERNS.md` § Pattern C).
241
+ *
242
+ * `protected` so subclasses (and the workflow helpers above) can call
243
+ * it, but external callers go through `bootstrapOwnerOnSpawn` /
244
+ * `bulkRemoveControllerEntries` instead.
245
+ */
246
+ protected planAclMaintenance(ops: AclMaintenanceOp[]): Promise<Instruction[]>;
247
+ /** Load the head + every page for `user` in two RPC calls. */
248
+ private loadAclState;
249
+ }
@@ -0,0 +1,177 @@
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
+ * Solana implementation of ANT (Arweave Name Token) write interface.
18
+ *
19
+ * Extends SolanaANTReadable with write operations that build and send
20
+ * Solana transactions to the ario-ant program.
21
+ *
22
+ * All instruction encoding is delegated to the Codama-generated builders in
23
+ * `./generated/ant/instructions/` — they own the discriminator + Borsh codec
24
+ * + account-meta wiring derived from the on-chain IDL.
25
+ *
26
+ * ACL maintenance (ADR-012, paginated per-user ACL):
27
+ * The on-chain handlers for `add_controller`, `remove_controller`, and
28
+ * `transfer` *require* the controller / new-owner / old-owner ACL
29
+ * accounts as instruction inputs and write the ACL inline as part of
30
+ * the same atomic ix. This SDK's job is therefore reduced to two
31
+ * things:
32
+ * 1. **Preflight resolution** — ask the composed
33
+ * `SolanaANTRegistryWriteable` to pick the right page and emit
34
+ * any `register_acl_config` / `add_acl_page` ixs that need to be
35
+ * prepended so the contract's account validation succeeds.
36
+ * 2. **Ex-controller cleanup on transfer** — a wrapped transfer
37
+ * cannot atomically `swap_remove` every ex-controller's ACL
38
+ * entry (variable cardinality, no clean way to express variadic
39
+ * accounts in Codama). The SDK reads the controllers list and
40
+ * delegates to `registry.bulkRemoveControllerEntries`, which
41
+ * produces the right `remove_acl_controller` ixs to append into
42
+ * the transfer tx. Permissionless heal flows clean up any drift
43
+ * if a marketplace transfer bypasses this SDK entirely.
44
+ */
45
+ import { type Address, type Commitment, type Instruction } from '@solana/kit';
46
+ import type { ILogger } from '../common/logger.js';
47
+ import type { ANTRegistryRead } from '../types/ant-registry.js';
48
+ import type { ANTSetBaseNameRecordParams, ANTSetUndernameRecordParams } from '../types/ant.js';
49
+ import type { MessageResult, WriteOptions } from '../types/common.js';
50
+ import { SolanaANTReadable } from './ant-readable.js';
51
+ import { SolanaANTRegistryWriteable } from './ant-registry-writeable.js';
52
+ import type { SolanaRpc, SolanaRpcSubscriptions, SolanaSigner } from './types.js';
53
+ /**
54
+ * Solana-backed read-write client for a single ANT (Arweave Name Token).
55
+ *
56
+ * Usage:
57
+ * ```ts
58
+ * import { createSolanaRpc, createSolanaRpcSubscriptions, createKeyPairSignerFromBytes } from '@solana/kit';
59
+ * import { SolanaANTWriteable } from '@ar.io/sdk/solana';
60
+ *
61
+ * const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
62
+ * const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
63
+ * const signer = await createKeyPairSignerFromBytes(secretKeyBytes);
64
+ * const ant = new SolanaANTWriteable({
65
+ * rpc,
66
+ * rpcSubscriptions,
67
+ * processId: 'MetaplexCoreAssetAddress...',
68
+ * signer,
69
+ * });
70
+ *
71
+ * await ant.setRecord({ undername: 'docs', transactionId: '...', ttlSeconds: 3600 });
72
+ * ```
73
+ */
74
+ export declare class SolanaANTWriteable extends SolanaANTReadable {
75
+ protected readonly signer: SolanaSigner;
76
+ protected readonly rpcSubscriptions: SolanaRpcSubscriptions;
77
+ /**
78
+ * Override the readable's registry with the writeable variant — gives
79
+ * us the preflight resolvers + the spawn / ex-controller workflow
80
+ * helpers, while preserving `accessControlList` reads from the
81
+ * parent's `ANTRegistryRead` surface.
82
+ */
83
+ readonly registry: SolanaANTRegistryWriteable & ANTRegistryRead;
84
+ constructor(config: {
85
+ rpc: SolanaRpc;
86
+ rpcSubscriptions: SolanaRpcSubscriptions;
87
+ processId: string;
88
+ signer: SolanaSigner;
89
+ commitment?: Commitment;
90
+ logger?: ILogger;
91
+ antProgramId?: Address;
92
+ /**
93
+ * Pre-built writeable registry to compose. When omitted we build one
94
+ * from `rpc` / `signer` / `commitment` / `antProgramId` so the simple
95
+ * single-arg call site keeps working.
96
+ */
97
+ registry?: SolanaANTRegistryWriteable;
98
+ });
99
+ /**
100
+ * Build, sign, and send a transaction.
101
+ *
102
+ * Plain pass-through to `sendAndConfirm` — every ANT write whose ACL
103
+ * footprint is bounded (controllers add/remove, owner swap on
104
+ * transfer) is handled inline by the contract handlers. Variable-
105
+ * length cleanup (notably ex-controller wipe after transfer) is
106
+ * pre-built by the caller via `registry.bulkRemoveControllerEntries`
107
+ * and appended into the same `instructions` array, so this method
108
+ * doesn't need its own ACL plumbing.
109
+ */
110
+ protected sendTransaction(instructions: Instruction[]): Promise<string>;
111
+ setRecord(params: ANTSetUndernameRecordParams, _options?: WriteOptions): Promise<MessageResult>;
112
+ setBaseNameRecord(params: ANTSetBaseNameRecordParams, options?: WriteOptions): Promise<MessageResult>;
113
+ setUndernameRecord(params: ANTSetUndernameRecordParams, options?: WriteOptions): Promise<MessageResult>;
114
+ removeRecord(params: {
115
+ undername: string;
116
+ }, _options?: WriteOptions): Promise<MessageResult>;
117
+ removeUndernameRecord(params: {
118
+ undername: string;
119
+ }, options?: WriteOptions): Promise<MessageResult>;
120
+ transferRecord(params: {
121
+ undername: string;
122
+ recipient: string;
123
+ }, _options?: WriteOptions): Promise<MessageResult>;
124
+ addController(params: {
125
+ controller: string;
126
+ }, _options?: WriteOptions): Promise<MessageResult>;
127
+ removeController(params: {
128
+ controller: string;
129
+ }, _options?: WriteOptions): Promise<MessageResult>;
130
+ setName(params: {
131
+ name: string;
132
+ }, _options?: WriteOptions): Promise<MessageResult>;
133
+ setTicker(params: {
134
+ ticker: string;
135
+ }, _options?: WriteOptions): Promise<MessageResult>;
136
+ setDescription(params: {
137
+ description: string;
138
+ }, _options?: WriteOptions): Promise<MessageResult>;
139
+ setKeywords(params: {
140
+ keywords: string[];
141
+ }, _options?: WriteOptions): Promise<MessageResult>;
142
+ setLogo(params: {
143
+ txId: string;
144
+ }, _options?: WriteOptions): Promise<MessageResult>;
145
+ transfer(params: {
146
+ target: string;
147
+ }, _options?: WriteOptions): Promise<MessageResult>;
148
+ reconcile(_options?: WriteOptions): Promise<MessageResult>;
149
+ releaseName(_params: {
150
+ name: string;
151
+ arioProcessId: string;
152
+ }, _options?: WriteOptions): Promise<MessageResult>;
153
+ reassignName(_params: {
154
+ name: string;
155
+ arioProcessId: string;
156
+ antProcessId: string;
157
+ }, _options?: WriteOptions): Promise<MessageResult>;
158
+ approvePrimaryNameRequest(_params: {
159
+ name: string;
160
+ address: string;
161
+ arioProcessId: string;
162
+ }, _options?: WriteOptions): Promise<MessageResult>;
163
+ removePrimaryNames(_params: {
164
+ names: string[];
165
+ arioProcessId: string;
166
+ notifyOwners?: boolean;
167
+ }, _options?: WriteOptions): Promise<MessageResult>;
168
+ /**
169
+ * Migrate this ANT's on-chain state to the latest schema version.
170
+ * On Solana, "upgrade" means per-ANT data migration, not process forking.
171
+ * Returns the transaction signature if migration was needed.
172
+ */
173
+ upgrade(_params?: any): Promise<{
174
+ id: string;
175
+ needsMigration: boolean;
176
+ }>;
177
+ }
@@ -0,0 +1,44 @@
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
+ * Associated Token Account derivation, kit-native.
18
+ * Mirrors the classic SPL `getAssociatedTokenAddress` function but returns
19
+ * a kit `Address` without the web3.js dependency.
20
+ *
21
+ * TODO(C7): replace with `findAssociatedTokenPda` from `@solana-program/associated-token`
22
+ * once that package is added as a dependency.
23
+ */
24
+ import { type Address, type Instruction } from '@solana/kit';
25
+ export declare const ATA_PROGRAM_ADDRESS: Address;
26
+ /**
27
+ * Derive the Associated Token Account (ATA) address for a given owner + mint.
28
+ *
29
+ * @param mint — the SPL token mint address
30
+ * @param owner — the owner's wallet address (or a PDA if `allowOwnerOffCurve = true`)
31
+ * @param allowOwnerOffCurve — unused; kit derives regardless of curve. Kept for
32
+ * parity with the old `@solana/spl-token` signature so call sites don't change.
33
+ */
34
+ export declare function getAssociatedTokenAddressKit(mint: Address, owner: Address, _allowOwnerOffCurve?: boolean): Promise<Address>;
35
+ /**
36
+ * Build an idempotent CreateAssociatedTokenAccount instruction. Safe to
37
+ * include in any tx — if the ATA already exists, the SPL ATA program
38
+ * silently succeeds.
39
+ *
40
+ * Used to pre-create vault / escrow ATAs in the same tx as the program
41
+ * instruction that consumes them. Anchor's `Account<TokenAccount>` constraint
42
+ * does NOT init the account, so the caller is responsible.
43
+ */
44
+ export declare function buildCreateAtaIdempotentIx(payer: Address, ata: Address, owner: Address, mint: Address): Instruction;
@@ -0,0 +1,121 @@
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
+ * Canonical claim-message helper for `ario-ant-escrow`.
18
+ *
19
+ * Produces the EXACT bytes a recipient signs to release an escrowed
20
+ * ANT. Output MUST be byte-identical to the Rust implementation in
21
+ * `ario-ant-escrow/src/canonical.rs::build_ant_escrow_claim_message`
22
+ * (header `ANT_ESCROW_CLAIM_HEADER = "ar.io ant-escrow claim"`). The on-chain
23
+ * program reconstructs these exact bytes and verifies the signature against
24
+ * them, so any drift (header, field set, or ordering) makes every claim fail
25
+ * `EthereumAddressMismatch` / signature verification.
26
+ *
27
+ * Format (UTF-8, line-feed separated, no trailing newline):
28
+ *
29
+ * ```text
30
+ * ar.io ant-escrow claim
31
+ * network: <network>
32
+ * recipient: <base64url(sha256(recipient_pubkey)) — 43 chars, no pad>
33
+ * ant: <ant_mint_base58>
34
+ * claimant: <claimant_solana_pubkey_base58>
35
+ * nonce: <nonce_hex_lowercase>
36
+ * ```
37
+ *
38
+ * Wallets sign these bytes directly:
39
+ * - Arweave: `wallet.signMessage(bytes)` → 512-byte RSA-PSS sig
40
+ * - Ethereum: `wallet.signMessage(bytes)` → 65-byte ECDSA + EIP-191 sig
41
+ * (the wallet applies the EIP-191 prefix; on-chain code re-applies it).
42
+ */
43
+ import type { Address } from '@solana/kit';
44
+ /** Network bound into the canonical message at compile-time on the Rust
45
+ * side. Frontend / SDK callers pass it explicitly so a single SDK build
46
+ * works against either deployment. */
47
+ export type EscrowNetwork = 'solana-mainnet' | 'solana-devnet';
48
+ export interface CanonicalMessageInput {
49
+ /** Must match the program's compile-time network string. */
50
+ network: EscrowNetwork;
51
+ /** ANT mint pubkey — matches `escrow.ant_mint`. */
52
+ antMint: Address;
53
+ /** Solana pubkey that will receive the ANT on claim. Bound into the
54
+ * signature so front-runners can't redirect. */
55
+ claimant: Address;
56
+ /** Recipient identity pubkey bytes the deposit targeted (ETH 20-byte
57
+ * address, Solana 32-byte pubkey, or Arweave RSA modulus). Bound into the
58
+ * message as `recipient: base64url(sha256(bytes))` to match the contract's
59
+ * `derive_recipient_id_b64url`. REQUIRED — the program reconstructs this
60
+ * line, so omitting it makes the claim mismatch. */
61
+ recipient: Uint8Array;
62
+ /** 32-byte anti-replay nonce — read from the EscrowAnt account. */
63
+ nonce: Uint8Array;
64
+ }
65
+ /**
66
+ * Build the canonical claim message bytes. UTF-8 encoded, no trailing
67
+ * newline, exactly the format shown in the docstring.
68
+ *
69
+ * @throws if `nonce` isn't exactly 32 bytes — guards against accidentally
70
+ * passing a hex string or a different-sized buffer.
71
+ */
72
+ export declare function canonicalMessage(input: CanonicalMessageInput): Uint8Array;
73
+ export interface CanonicalMessageV2Input {
74
+ /** Must match the program's compile-time network string. */
75
+ network: EscrowNetwork;
76
+ /** `'token'` for liquid ARIO, `'vault'` for time-locked positions. */
77
+ assetType: 'token' | 'vault';
78
+ /** 32-byte client-supplied unique identifier for the escrowed asset. */
79
+ assetId: Uint8Array;
80
+ /** Amount of ARIO (mARIO) held in escrow. */
81
+ amount: bigint;
82
+ /** Solana pubkey that will receive the tokens on claim. */
83
+ claimant: Address;
84
+ /** Recipient identity pubkey bytes the deposit targeted (ETH 20-byte
85
+ * address, Solana 32-byte pubkey, or Arweave RSA modulus). Bound into the
86
+ * message as `recipient: base64url(sha256(bytes))` to match the contract's
87
+ * `derive_recipient_id_b64url`. REQUIRED — the program reconstructs this
88
+ * line, so omitting it makes the claim mismatch. */
89
+ recipient: Uint8Array;
90
+ /** 32-byte anti-replay nonce — read from the EscrowToken account. */
91
+ nonce: Uint8Array;
92
+ }
93
+ /**
94
+ * Build the v2 canonical claim message bytes for token/vault escrows.
95
+ * UTF-8 encoded, no trailing newline.
96
+ *
97
+ * Format:
98
+ * ```text
99
+ * ar.io escrow claim
100
+ * network: <network>
101
+ * recipient: <base64url(sha256(recipient_pubkey)) — 43 chars, no pad>
102
+ * type: <token|vault>
103
+ * asset: <asset_id_hex_lowercase_64chars>
104
+ * amount: <u64_decimal>
105
+ * claimant: <base58>
106
+ * nonce: <hex_lowercase_64chars>
107
+ * ```
108
+ *
109
+ * @throws if `assetId` or `nonce` aren't exactly 32 bytes.
110
+ */
111
+ export declare function canonicalMessageV2(input: CanonicalMessageV2Input): Uint8Array;
112
+ /**
113
+ * Recipient identity bound into the claim message — `base64url(sha256(bytes))`
114
+ * with no padding (32-byte hash → 43 chars). Byte-identical to the contract's
115
+ * `canonical.rs::derive_recipient_id_b64url`. Input is the recipient pubkey
116
+ * bytes the deposit targeted (ETH 20-byte address / Solana 32-byte pubkey /
117
+ * Arweave RSA modulus, etc.).
118
+ */
119
+ export declare function deriveRecipientId(recipient: Uint8Array): string;
120
+ /** Lowercase-hex encoding. Matches Rust `encode_hex_lowercase`. */
121
+ export declare function bytesToHexLower(bytes: Uint8Array): string;