@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
@@ -1,106 +1,71 @@
1
- import { antRecordMetadataFromOptions, arioProcessIdFromOptions, assertConfirmationPrompt, booleanFromOptions, customTagsFromOptions, defaultTtlSecondsCLI, readARIOFromOptions, requiredStringFromOptions, stringArrayFromOptions, writeANTFromOptions, } from '../utils.js';
1
+ import { antRecordMetadataFromOptions, assertConfirmationPrompt, customTagsFromOptions, defaultTtlSecondsCLI, requiredStringFromOptions, writeANTFromOptions, } from '../utils.js';
2
+ function targetProtocolFromOptions(o) {
3
+ const raw = o.targetProtocol;
4
+ if (!raw || raw === 'arweave')
5
+ return 0;
6
+ if (raw === 'ipfs')
7
+ return 1;
8
+ throw new Error(`Invalid --target-protocol "${raw}". Must be "arweave" or "ipfs".`);
9
+ }
2
10
  /** @deprecated -- use set-ant-base-name and set-ant-undername */
3
11
  export async function setAntRecordCLICommand(o) {
4
12
  const ttlSeconds = +(o.ttlSeconds ?? defaultTtlSecondsCLI);
5
13
  const undername = requiredStringFromOptions(o, 'undername');
6
14
  const transactionId = requiredStringFromOptions(o, 'transactionId');
7
- const writeAnt = writeANTFromOptions(o);
15
+ const targetProtocol = targetProtocolFromOptions(o);
16
+ const writeAnt = await writeANTFromOptions(o);
8
17
  const recordParams = {
9
18
  undername,
10
19
  transactionId,
11
20
  ttlSeconds,
21
+ targetProtocol,
12
22
  ...antRecordMetadataFromOptions(o),
13
23
  };
14
24
  if (!o.skipConfirmation) {
15
25
  await assertConfirmationPrompt(`Are you sure you want to set this record on the ANT process ${writeAnt.processId}?\n${JSON.stringify(recordParams, null, 2)}`, o);
16
26
  }
17
- return writeANTFromOptions(o).setRecord(recordParams, customTagsFromOptions(o));
27
+ return writeAnt.setRecord(recordParams, customTagsFromOptions(o));
18
28
  }
19
29
  export async function setAntBaseNameCLICommand(o) {
20
30
  const ttlSeconds = +(o.ttlSeconds ?? defaultTtlSecondsCLI);
21
31
  const transactionId = requiredStringFromOptions(o, 'transactionId');
32
+ const targetProtocol = targetProtocolFromOptions(o);
22
33
  const params = {
23
34
  transactionId,
24
35
  ttlSeconds,
36
+ targetProtocol,
25
37
  ...antRecordMetadataFromOptions(o),
26
38
  };
27
- const writeAnt = writeANTFromOptions(o);
39
+ const writeAnt = await writeANTFromOptions(o);
28
40
  if (!o.skipConfirmation) {
29
41
  await assertConfirmationPrompt(`Are you sure you want to set this base name on the ANT process ${writeAnt.processId}?\n${JSON.stringify(params, null, 2)}`, o);
30
42
  }
31
- return writeANTFromOptions(o).setBaseNameRecord(params, customTagsFromOptions(o));
43
+ return writeAnt.setBaseNameRecord(params, customTagsFromOptions(o));
32
44
  }
33
45
  export async function setAntUndernameCLICommand(o) {
34
46
  const ttlSeconds = +(o.ttlSeconds ?? defaultTtlSecondsCLI);
35
47
  const undername = requiredStringFromOptions(o, 'undername');
36
48
  const transactionId = requiredStringFromOptions(o, 'transactionId');
49
+ const targetProtocol = targetProtocolFromOptions(o);
37
50
  const params = {
38
51
  undername,
39
52
  transactionId,
40
53
  ttlSeconds,
54
+ targetProtocol,
41
55
  ...antRecordMetadataFromOptions(o),
42
56
  };
43
- const writeAnt = writeANTFromOptions(o);
57
+ const writeAnt = await writeANTFromOptions(o);
44
58
  if (!o.skipConfirmation) {
45
59
  await assertConfirmationPrompt(`Are you sure you want to set this undername on the ANT process ${writeAnt.processId}?\n${JSON.stringify(params, null, 2)}`, o);
46
60
  }
47
- return writeANTFromOptions(o).setUndernameRecord(params, customTagsFromOptions(o));
61
+ return writeAnt.setUndernameRecord(params, customTagsFromOptions(o));
48
62
  }
49
63
  export async function transferRecordOwnershipCLICommand(o) {
50
64
  const undername = requiredStringFromOptions(o, 'undername');
51
65
  const recipient = requiredStringFromOptions(o, 'recipient');
52
- const writeAnt = writeANTFromOptions(o);
66
+ const writeAnt = await writeANTFromOptions(o);
53
67
  if (!o.skipConfirmation) {
54
68
  await assertConfirmationPrompt(`Are you sure you want to transfer ownership of "${undername}" to "${recipient}" on ANT process ${writeAnt.processId}?\n${JSON.stringify({ undername, recipient }, null, 2)}`, o);
55
69
  }
56
- return writeANTFromOptions(o).transferRecord({ undername, recipient }, customTagsFromOptions(o));
57
- }
58
- export async function upgradeAntCLICommand(o) {
59
- const writeAnt = writeANTFromOptions(o);
60
- const arioProcessId = arioProcessIdFromOptions(o);
61
- const ario = readARIOFromOptions(o);
62
- const reassignAffiliatedNames = booleanFromOptions(o, 'reassignAffiliatedNames');
63
- const names = stringArrayFromOptions(o, 'names') || [];
64
- if (reassignAffiliatedNames) {
65
- // Fetch all ArNS records that point to this ANT process
66
- const allRecords = await ario.getArNSRecords({
67
- filters: {
68
- processId: writeAnt.processId,
69
- },
70
- });
71
- // Filter records that belong to this ANT
72
- const affiliatedNames = allRecords.items.map((record) => record.name);
73
- names.push(...affiliatedNames);
74
- }
75
- if (names.length === 0) {
76
- throw new Error('No names to reassign');
77
- }
78
- if (!o.skipConfirmation) {
79
- await assertConfirmationPrompt(`Upgrade all names affiliated with this ANT on ARIO process?\n` +
80
- `ARIO Process ID: ${arioProcessId}\n` +
81
- `ANT Process ID: ${writeAnt.processId}\n` +
82
- `Names that will be reassigned (${names.length}): ${names.join(', ')}`, o);
83
- }
84
- const result = reassignAffiliatedNames
85
- ? await writeANTFromOptions(o).upgrade({
86
- reassignAffiliatedNames,
87
- arioProcessId,
88
- })
89
- : await writeANTFromOptions(o).upgrade({
90
- names,
91
- arioProcessId,
92
- });
93
- // Serialize error objects for JSON compatibility
94
- const serializedFailedReassignedNames = {};
95
- for (const [name, failure] of Object.entries(result.failedReassignedNames)) {
96
- serializedFailedReassignedNames[name] = {
97
- id: failure.id,
98
- error: failure.error.message,
99
- };
100
- }
101
- return {
102
- forkedProcessId: result.forkedProcessId,
103
- reassignedNames: result.reassignedNames,
104
- failedReassignedNames: serializedFailedReassignedNames,
105
- };
70
+ return writeAnt.transferRecord({ undername, recipient }, customTagsFromOptions(o));
106
71
  }
@@ -1,22 +1,16 @@
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
- import { ANT } from '../../common/ant.js';
17
- import { assertConfirmationPrompt, assertEnoughBalanceForArNSPurchase, customTagsFromOptions, fundFromFromOptions, positiveIntegerFromOptions, recordTypeFromOptions, referrerFromOptions, requiredPositiveIntegerFromOptions, requiredStringFromOptions, stringArrayFromOptions, writeARIOFromOptions, } from '../utils.js';
1
+ import { assertConfirmationPrompt, assertEnoughBalanceForArNSPurchase, customTagsFromOptions, fundFromFromOptions, fundingPlanFromOptions, positiveIntegerFromOptions, recordTypeFromOptions, referrerFromOptions, requiredPositiveIntegerFromOptions, requiredStringFromOptions, stringArrayFromOptions, withdrawalIdFromOptions, writeARIOFromOptions, } from '../utils.js';
2
+ /** Coerce the JSON-parsed funding plan to the typed `FundingSourceSpec[]`. */
3
+ function coerceFundingPlanSources(parsed) {
4
+ if (!parsed)
5
+ return undefined;
6
+ return parsed.map((s) => ({
7
+ kind: s.kind,
8
+ amount: s.amount,
9
+ ...(s.gateway ? { gateway: s.gateway } : {}),
10
+ }));
11
+ }
18
12
  export async function buyRecordCLICommand(o) {
19
- const { ario, signerAddress } = writeARIOFromOptions(o);
13
+ const { ario, signerAddress } = await writeARIOFromOptions(o);
20
14
  const name = requiredStringFromOptions(o, 'name');
21
15
  const type = recordTypeFromOptions(o);
22
16
  const years = positiveIntegerFromOptions(o, 'years');
@@ -42,13 +36,9 @@ export async function buyRecordCLICommand(o) {
42
36
  fromAddress: signerAddress,
43
37
  },
44
38
  });
45
- // assert spawn new ant with module id
46
- let antSpawnConfirmation = '';
47
- if (processId === undefined) {
48
- const { moduleId, version } = await ANT.versions.getLatestANTVersion();
49
- antSpawnConfirmation = `Note: A new ANT process will be spawned with module ${moduleId} (v${version}) and assigned to this name.`;
50
- }
51
- await assertConfirmationPrompt(`Are you sure you want to ${type} the record ${name}? ${antSpawnConfirmation}`, o);
39
+ await assertConfirmationPrompt(`Are you sure you want to ${type} the record ${name}?${processId === undefined
40
+ ? ' Note: A new ANT (MPL Core asset) will be spawned and assigned to this name.'
41
+ : ''}`, o);
52
42
  }
53
43
  return ario.buyRecord({
54
44
  name: requiredStringFromOptions(o, 'name'),
@@ -56,13 +46,17 @@ export async function buyRecordCLICommand(o) {
56
46
  type,
57
47
  years,
58
48
  fundFrom: fundFromFromOptions(o),
49
+ gatewayAddress: o.gatewayAddress,
50
+ fundAsOperator: o.fundAsOperator,
51
+ withdrawalId: withdrawalIdFromOptions(o),
52
+ sources: coerceFundingPlanSources(fundingPlanFromOptions(o)),
59
53
  paidBy: stringArrayFromOptions(o, 'paidBy'),
60
54
  referrer,
61
55
  }, customTagsFromOptions(o));
62
56
  }
63
57
  export async function upgradeRecordCLICommand(o) {
64
58
  const name = requiredStringFromOptions(o, 'name');
65
- const { ario, signerAddress } = writeARIOFromOptions(o);
59
+ const { ario, signerAddress } = await writeARIOFromOptions(o);
66
60
  const fundFrom = fundFromFromOptions(o);
67
61
  const referrer = referrerFromOptions(o);
68
62
  if (!o.skipConfirmation) {
@@ -90,6 +84,8 @@ export async function upgradeRecordCLICommand(o) {
90
84
  return ario.upgradeRecord({
91
85
  name,
92
86
  fundFrom,
87
+ gatewayAddress: o.gatewayAddress,
88
+ fundAsOperator: o.fundAsOperator,
93
89
  paidBy: stringArrayFromOptions(o, 'paidBy'),
94
90
  referrer,
95
91
  });
@@ -99,7 +95,7 @@ export async function extendLeaseCLICommand(o) {
99
95
  const years = requiredPositiveIntegerFromOptions(o, 'years');
100
96
  const fundFrom = fundFromFromOptions(o);
101
97
  const referrer = referrerFromOptions(o);
102
- const { ario, signerAddress } = writeARIOFromOptions(o);
98
+ const { ario, signerAddress } = await writeARIOFromOptions(o);
103
99
  if (!o.skipConfirmation) {
104
100
  const existingRecord = await ario.getArNSRecord({
105
101
  name,
@@ -126,6 +122,9 @@ export async function extendLeaseCLICommand(o) {
126
122
  return ario.extendLease({
127
123
  name,
128
124
  years,
125
+ fundFrom,
126
+ gatewayAddress: o.gatewayAddress,
127
+ fundAsOperator: o.fundAsOperator,
129
128
  paidBy: stringArrayFromOptions(o, 'paidBy'),
130
129
  referrer,
131
130
  }, customTagsFromOptions(o));
@@ -135,7 +134,7 @@ export async function increaseUndernameLimitCLICommand(o) {
135
134
  const increaseCount = requiredPositiveIntegerFromOptions(o, 'increaseCount');
136
135
  const fundFrom = fundFromFromOptions(o);
137
136
  const referrer = referrerFromOptions(o);
138
- const { ario, signerAddress } = writeARIOFromOptions(o);
137
+ const { ario, signerAddress } = await writeARIOFromOptions(o);
139
138
  if (!o.skipConfirmation) {
140
139
  const existingRecord = await ario.getArNSRecord({
141
140
  name,
@@ -159,12 +158,15 @@ export async function increaseUndernameLimitCLICommand(o) {
159
158
  return ario.increaseUndernameLimit({
160
159
  name,
161
160
  increaseCount,
161
+ fundFrom,
162
+ gatewayAddress: o.gatewayAddress,
163
+ fundAsOperator: o.fundAsOperator,
162
164
  paidBy: stringArrayFromOptions(o, 'paidBy'),
163
165
  referrer,
164
166
  }, customTagsFromOptions(o));
165
167
  }
166
168
  export async function requestPrimaryNameCLICommand(o) {
167
- const { ario, signerAddress } = writeARIOFromOptions(o);
169
+ const { ario, signerAddress } = await writeARIOFromOptions(o);
168
170
  const fundFrom = fundFromFromOptions(o);
169
171
  const referrer = referrerFromOptions(o);
170
172
  const name = requiredStringFromOptions(o, 'name');
@@ -193,7 +195,7 @@ export async function requestPrimaryNameCLICommand(o) {
193
195
  return result.request;
194
196
  }
195
197
  export async function setPrimaryNameCLICommand(o) {
196
- const { ario, signerAddress } = writeARIOFromOptions(o);
198
+ const { ario, signerAddress } = await writeARIOFromOptions(o);
197
199
  const name = requiredStringFromOptions(o, 'name');
198
200
  const fundFrom = fundFromFromOptions(o);
199
201
  const referrer = referrerFromOptions(o);
@@ -202,3 +204,19 @@ export async function setPrimaryNameCLICommand(o) {
202
204
  }
203
205
  return ario.setPrimaryName({ name, fundFrom, referrer });
204
206
  }
207
+ /**
208
+ * Reconcile the on-chain ANT Attributes plugin (`ArNS Name`, `Type`,
209
+ * `Undername Limit`) with the current `ArnsRecord` state. Permissionless.
210
+ *
211
+ * Use after a `buy-record` where the buyer was not the ANT NFT holder
212
+ * (the ANT-side trait CPI gets skipped at runtime in that case so the
213
+ * plugin stays empty until the actual holder reconciles).
214
+ */
215
+ export async function syncAttributesCLICommand(o) {
216
+ const name = requiredStringFromOptions(o, 'name');
217
+ const { ario } = await writeARIOFromOptions(o);
218
+ if (!o.skipConfirmation) {
219
+ await assertConfirmationPrompt(`Sync on-chain ANT traits for "${name}" to match the current ArnsRecord?`, o);
220
+ }
221
+ return ario.syncAttributes({ name });
222
+ }
@@ -0,0 +1,227 @@
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
+ * CLI commands for `ario-ant-escrow` — trustless multi-protocol ANT custody.
18
+ *
19
+ * Each command instantiates an {@link ANTEscrow} with options-driven RPC +
20
+ * signer wiring (mirrors the rest of the Solana CLI surface — see
21
+ * `arnsPurchaseCommands.ts`). All read commands work without a signer; all
22
+ * write commands require `--wallet-file` or `--private-key`.
23
+ *
24
+ * Recipient pubkey loading:
25
+ * - Arweave: `--recipient-arweave <jwk-file>` reads the JWK JSON, decodes
26
+ * the base64url `n` field to 512 raw bytes (RSA-4096 modulus).
27
+ * - Ethereum: `--recipient-ethereum 0x...` parses the 20-byte hex address.
28
+ */
29
+ import { readFileSync } from 'node:fs';
30
+ import { address, createKeyPairSignerFromBytes, createSolanaRpcSubscriptions, } from '@solana/kit';
31
+ import bs58 from 'bs58';
32
+ import { ARIO_ANT_ESCROW_PROGRAM_ID } from '../../solana/constants.js';
33
+ import { ANTEscrow } from '../../solana/escrow.js';
34
+ import { createCircuitBreakerRpc, defaultFallbackUrl, } from '../../solana/rpc-circuit-breaker.js';
35
+ // =========================================
36
+ // Wiring helpers
37
+ // =========================================
38
+ function wsUrlFromRpcUrl(rpcUrl) {
39
+ return rpcUrl.replace(/^http/, 'ws');
40
+ }
41
+ function escrowProgramIdFrom(options) {
42
+ return options.escrowProgramId
43
+ ? address(options.escrowProgramId)
44
+ : ARIO_ANT_ESCROW_PROGRAM_ID;
45
+ }
46
+ async function readEscrowReader(options) {
47
+ const rpcUrl = options.rpcUrl ?? 'https://api.mainnet-beta.solana.com';
48
+ return ANTEscrow.init({
49
+ rpc: createCircuitBreakerRpc({
50
+ primaryUrl: rpcUrl,
51
+ fallbackUrl: defaultFallbackUrl(rpcUrl),
52
+ }),
53
+ programId: escrowProgramIdFrom(options),
54
+ });
55
+ }
56
+ async function writeEscrowFromOptions(options) {
57
+ let secretKey;
58
+ if (options.privateKey) {
59
+ secretKey = bs58.decode(options.privateKey);
60
+ }
61
+ else if (options.walletFile) {
62
+ const raw = readFileSync(options.walletFile, 'utf-8');
63
+ secretKey = new Uint8Array(JSON.parse(raw));
64
+ }
65
+ else {
66
+ throw new Error('escrow write operations require a signer. Provide --wallet-file <path> or --private-key <base58>');
67
+ }
68
+ const signer = await createKeyPairSignerFromBytes(secretKey);
69
+ const rpcUrl = options.rpcUrl ?? 'https://api.mainnet-beta.solana.com';
70
+ return ANTEscrow.init({
71
+ rpc: createCircuitBreakerRpc({
72
+ primaryUrl: rpcUrl,
73
+ fallbackUrl: defaultFallbackUrl(rpcUrl),
74
+ }),
75
+ rpcSubscriptions: createSolanaRpcSubscriptions(wsUrlFromRpcUrl(rpcUrl)),
76
+ signer,
77
+ programId: escrowProgramIdFrom(options),
78
+ });
79
+ }
80
+ // =========================================
81
+ // Recipient pubkey parsing
82
+ // =========================================
83
+ function base64UrlDecode(s) {
84
+ // Convert base64url → base64, then decode.
85
+ let b64 = s.replace(/-/g, '+').replace(/_/g, '/');
86
+ while (b64.length % 4 !== 0)
87
+ b64 += '=';
88
+ return new Uint8Array(Buffer.from(b64, 'base64'));
89
+ }
90
+ /** Load an Arweave RSA-4096 modulus from a JWK file (`.json` with `n` field). */
91
+ function loadArweaveModulusFromJwk(filePath) {
92
+ const raw = readFileSync(filePath, 'utf-8');
93
+ const jwk = JSON.parse(raw);
94
+ if (jwk.kty !== 'RSA' || !jwk.n) {
95
+ throw new Error(`Not a valid Arweave RSA JWK (missing kty=RSA or n field)`);
96
+ }
97
+ const modulus = base64UrlDecode(jwk.n);
98
+ if (modulus.length !== 512) {
99
+ throw new Error(`Arweave modulus must be 512 bytes (4096-bit RSA); got ${modulus.length}`);
100
+ }
101
+ return modulus;
102
+ }
103
+ /** Parse an Ethereum address (`0xabc...`) into 20 raw bytes. */
104
+ function parseEthereumAddress(hex) {
105
+ const cleaned = hex.startsWith('0x') ? hex.slice(2) : hex;
106
+ if (cleaned.length !== 40 || !/^[0-9a-fA-F]+$/.test(cleaned)) {
107
+ throw new Error(`Ethereum address must be 0x-prefixed 40-char hex; got "${hex}"`);
108
+ }
109
+ return Uint8Array.from(Buffer.from(cleaned, 'hex'));
110
+ }
111
+ function recipientFromDepositOptions(o) {
112
+ if (o.recipientArweave && o.recipientEthereum) {
113
+ throw new Error('--recipient-arweave and --recipient-ethereum are mutually exclusive');
114
+ }
115
+ if (o.recipientArweave) {
116
+ return {
117
+ protocol: 'arweave',
118
+ publicKey: loadArweaveModulusFromJwk(o.recipientArweave),
119
+ };
120
+ }
121
+ if (o.recipientEthereum) {
122
+ return {
123
+ protocol: 'ethereum',
124
+ publicKey: parseEthereumAddress(o.recipientEthereum),
125
+ };
126
+ }
127
+ throw new Error('one of --recipient-arweave or --recipient-ethereum is required');
128
+ }
129
+ function recipientFromUpdateOptions(o) {
130
+ return recipientFromDepositOptions({
131
+ recipientArweave: o.newRecipientArweave,
132
+ recipientEthereum: o.newRecipientEthereum,
133
+ });
134
+ }
135
+ function antFromOptions(o) {
136
+ if (!o.ant)
137
+ throw new Error('--ant <mint> is required');
138
+ return address(o.ant);
139
+ }
140
+ // =========================================
141
+ // CLI handlers
142
+ // =========================================
143
+ /** `ar.io escrow status --ant <mint>` */
144
+ export async function escrowStatusCLICommand(o) {
145
+ const escrow = await readEscrowReader(o);
146
+ const ant = antFromOptions(o);
147
+ const state = await escrow.get(ant);
148
+ if (!state) {
149
+ return { active: false, antMint: ant };
150
+ }
151
+ return {
152
+ active: true,
153
+ antMint: state.antMint,
154
+ depositor: state.depositor,
155
+ recipientProtocol: state.recipientProtocol,
156
+ recipientPubkeyHex: Buffer.from(state.recipientPubkey).toString('hex'),
157
+ nonceHex: Buffer.from(state.nonce).toString('hex'),
158
+ depositSlot: state.depositSlot.toString(),
159
+ version: state.version,
160
+ };
161
+ }
162
+ /** `ar.io escrow deposit --ant <mint> --recipient-{arweave|ethereum} ...` */
163
+ export async function escrowDepositCLICommand(o) {
164
+ const recipient = recipientFromDepositOptions(o);
165
+ const escrow = await writeEscrowFromOptions(o);
166
+ const sig = await escrow.deposit({ antMint: antFromOptions(o), recipient });
167
+ return { signature: sig };
168
+ }
169
+ /** `ar.io escrow cancel --ant <mint>` */
170
+ export async function escrowCancelCLICommand(o) {
171
+ const escrow = await writeEscrowFromOptions(o);
172
+ const sig = await escrow.cancel({ antMint: antFromOptions(o) });
173
+ return { signature: sig };
174
+ }
175
+ /** `ar.io escrow update-recipient --ant <mint> --new-recipient-{arweave|ethereum} ...` */
176
+ export async function escrowUpdateRecipientCLICommand(o) {
177
+ const newRecipient = recipientFromUpdateOptions(o);
178
+ const escrow = await writeEscrowFromOptions(o);
179
+ const sig = await escrow.updateRecipient({
180
+ antMint: antFromOptions(o),
181
+ newRecipient,
182
+ });
183
+ return { signature: sig };
184
+ }
185
+ /** `ar.io escrow claim-arweave --ant <mint> --signature-file <bin> --claimant <pubkey> [--salt-len 32]` */
186
+ export async function escrowClaimArweaveCLICommand(o) {
187
+ if (!o.signatureFile)
188
+ throw new Error('--signature-file <path> is required');
189
+ if (!o.claimant)
190
+ throw new Error('--claimant <pubkey> is required');
191
+ const sigBytes = new Uint8Array(readFileSync(o.signatureFile));
192
+ if (sigBytes.length !== 512) {
193
+ throw new Error(`signature file must be 512 bytes; got ${sigBytes.length}`);
194
+ }
195
+ // RSA-PSS salt length: 0 is a valid value, so only reject NaN / negative /
196
+ // non-integer. An unset flag defaults to 32 (a full SHA-256 digest).
197
+ const saltLen = o.saltLen ? Number.parseInt(o.saltLen, 10) : 32;
198
+ if (!Number.isInteger(saltLen) || saltLen < 0) {
199
+ throw new Error(`--salt-len must be a non-negative integer (got '${o.saltLen}')`);
200
+ }
201
+ const escrow = await writeEscrowFromOptions(o);
202
+ const sig = await escrow.claimArweave({
203
+ antMint: antFromOptions(o),
204
+ claimant: address(o.claimant),
205
+ signature: sigBytes,
206
+ saltLen,
207
+ });
208
+ return { signature: sig };
209
+ }
210
+ /** `ar.io escrow claim-ethereum --ant <mint> --signature-file <bin> --claimant <pubkey>` */
211
+ export async function escrowClaimEthereumCLICommand(o) {
212
+ if (!o.signatureFile)
213
+ throw new Error('--signature-file <path> is required');
214
+ if (!o.claimant)
215
+ throw new Error('--claimant <pubkey> is required');
216
+ const sigBytes = new Uint8Array(readFileSync(o.signatureFile));
217
+ if (sigBytes.length !== 65) {
218
+ throw new Error(`signature file must be 65 bytes (r||s||v); got ${sigBytes.length}`);
219
+ }
220
+ const escrow = await writeEscrowFromOptions(o);
221
+ const sig = await escrow.claimEthereum({
222
+ antMint: antFromOptions(o),
223
+ claimant: address(o.claimant),
224
+ signature: sigBytes,
225
+ });
226
+ return { signature: sig };
227
+ }