@ar.io/sdk 3.11.0-alpha.7 → 3.11.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/bundles/web.bundle.min.js +119 -116
- package/lib/cjs/cli/cli.js +137 -122
- package/lib/cjs/cli/commands/readCommands.js +6 -0
- package/lib/cjs/common/ant.js +5 -5
- package/lib/cjs/common/io.js +37 -0
- package/lib/cjs/common/wayfinder/gateways/trusted-gateways.js +106 -0
- package/lib/cjs/common/wayfinder/index.js +6 -0
- package/lib/cjs/common/wayfinder/verification/data-root-verifier.js +139 -0
- package/lib/cjs/common/wayfinder/verification/hash-verifier.js +50 -0
- package/lib/cjs/common/wayfinder/wayfinder.js +407 -18
- package/lib/cjs/common/wayfinder/wayfinder.test.js +262 -3
- package/lib/cjs/types/wayfinder.js +1 -0
- package/lib/cjs/utils/hash.js +56 -0
- package/lib/cjs/version.js +1 -1
- package/lib/esm/cli/cli.js +138 -123
- package/lib/esm/cli/commands/readCommands.js +5 -0
- package/lib/esm/common/ant.js +5 -5
- package/lib/esm/common/io.js +37 -0
- package/lib/esm/common/wayfinder/gateways/trusted-gateways.js +102 -0
- package/lib/esm/common/wayfinder/index.js +6 -0
- package/lib/esm/common/wayfinder/verification/data-root-verifier.js +130 -0
- package/lib/esm/common/wayfinder/verification/hash-verifier.js +46 -0
- package/lib/esm/common/wayfinder/wayfinder.js +401 -18
- package/lib/esm/common/wayfinder/wayfinder.test.js +263 -4
- package/lib/esm/types/wayfinder.js +1 -0
- package/lib/esm/utils/hash.js +50 -0
- package/lib/esm/version.js +1 -1
- package/lib/types/cli/commands/readCommands.d.ts +1 -0
- package/lib/types/common/io.d.ts +5 -2
- package/lib/types/common/wayfinder/gateways/trusted-gateways.d.ts +51 -0
- package/lib/types/common/wayfinder/index.d.ts +3 -0
- package/lib/types/common/wayfinder/verification/data-root-verifier.d.ts +31 -0
- package/lib/types/common/wayfinder/verification/hash-verifier.d.ts +27 -0
- package/lib/types/common/wayfinder/wayfinder.d.ts +148 -10
- package/lib/types/types/io.d.ts +16 -1
- package/lib/types/types/wayfinder.d.ts +43 -0
- package/lib/types/utils/hash.d.ts +4 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
package/lib/esm/cli/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import { version } from '../version.js';
|
|
|
22
22
|
import { setAntBaseNameCLICommand, setAntRecordCLICommand, } from './commands/antCommands.js';
|
|
23
23
|
import { buyRecordCLICommand, extendLeaseCLICommand, increaseUndernameLimitCLICommand, requestPrimaryNameCLICommand, upgradeRecordCLICommand, } from './commands/arnsPurchaseCommands.js';
|
|
24
24
|
import { cancelWithdrawal, decreaseDelegateStake, decreaseOperatorStake, delegateStake, increaseOperatorStake, instantWithdrawal, joinNetwork, leaveNetwork, redelegateStake, saveObservations, updateGatewaySettings, } from './commands/gatewayWriteCommands.js';
|
|
25
|
-
import { getAllGatewayVaults, getAllowedDelegates, getArNSRecord, getArNSReservedName, getArNSReturnedName, getCostDetails, getDelegations, getEpoch, getGateway, getGatewayDelegates, getGatewayVaults, getPrescribedNames, getPrescribedObservers, getPrimaryName, getTokenCost, getVault, listAllDelegatesCLICommand, listArNSRecords, listArNSReservedNames, listArNSReturnedNames, listGateways, } from './commands/readCommands.js';
|
|
25
|
+
import { getAllGatewayVaults, getAllowedDelegates, getArNSRecord, getArNSReservedName, getArNSReturnedName, getCostDetails, getDelegations, getEpoch, getGateway, getGatewayDelegates, getGatewayVaults, getPrescribedNames, getPrescribedObservers, getPrimaryName, getTokenCost, getVault, listAllDelegatesCLICommand, listArNSRecords, listArNSReservedNames, listArNSReturnedNames, listGateways, resolveArNSName, } from './commands/readCommands.js';
|
|
26
26
|
import { createVaultCLICommand, extendVaultCLICommand, increaseVaultCLICommand, revokeVaultCLICommand, transferCLICommand, vaultedTransferCLICommand, } from './commands/transfer.js';
|
|
27
27
|
import { addressAndVaultIdOptions, antStateOptions, arnsPurchaseOptions, buyRecordOptions, decreaseDelegateStakeOptions, delegateStakeOptions, epochOptions, getVaultOptions, globalOptions, joinNetworkOptions, operatorStakeOptions, optionMap, paginationAddressOptions, paginationOptions, redelegateStakeOptions, setAntBaseNameOptions, setAntUndernameOptions, tokenCostOptions, transferOptions, updateGatewaySettingsOptions, vaultedTransferOptions, writeActionOptions, } from './options.js';
|
|
28
28
|
import { applyOptions, arioProcessIdFromOptions, assertConfirmationPrompt, customTagsFromOptions, epochInputFromOptions, formatARIOWithCommas, getANTStateFromOptions, getLoggerFromOptions, makeCommand, paginationParamsFromOptions, readANTFromOptions, readARIOFromOptions, requiredAddressFromOptions, requiredAoSignerFromOptions, requiredProcessIdFromOptions, requiredStringArrayFromOptions, requiredStringFromOptions, writeANTFromOptions, } from './utils.js';
|
|
@@ -31,6 +31,7 @@ applyOptions(program
|
|
|
31
31
|
.version(version)
|
|
32
32
|
.description('AR.IO Network CLI')
|
|
33
33
|
.helpCommand(true), globalOptions);
|
|
34
|
+
// # Getters
|
|
34
35
|
makeCommand({
|
|
35
36
|
name: 'info',
|
|
36
37
|
description: 'Get network info',
|
|
@@ -41,6 +42,18 @@ makeCommand({
|
|
|
41
42
|
description: 'Get the total token supply',
|
|
42
43
|
action: (options) => readARIOFromOptions(options).getTokenSupply(),
|
|
43
44
|
});
|
|
45
|
+
makeCommand({
|
|
46
|
+
name: 'balance',
|
|
47
|
+
description: 'Get the balance of an address',
|
|
48
|
+
options: [optionMap.address],
|
|
49
|
+
action: (options) => readARIOFromOptions(options)
|
|
50
|
+
.getBalance({ address: requiredAddressFromOptions(options) })
|
|
51
|
+
.then((result) => ({
|
|
52
|
+
address: requiredAddressFromOptions(options),
|
|
53
|
+
mARIOBalance: result,
|
|
54
|
+
message: `Provided address current has a balance of ${formatARIOWithCommas(new mARIOToken(result).toARIO())} ARIO`,
|
|
55
|
+
})),
|
|
56
|
+
});
|
|
44
57
|
makeCommand({
|
|
45
58
|
name: 'get-registration-fees',
|
|
46
59
|
description: 'Get registration fees',
|
|
@@ -67,24 +80,18 @@ makeCommand({
|
|
|
67
80
|
options: [optionMap.address],
|
|
68
81
|
action: getGateway,
|
|
69
82
|
});
|
|
70
|
-
makeCommand({
|
|
71
|
-
name: 'list-gateways',
|
|
72
|
-
description: 'List the gateways of the network',
|
|
73
|
-
options: paginationOptions,
|
|
74
|
-
action: listGateways,
|
|
75
|
-
});
|
|
76
|
-
makeCommand({
|
|
77
|
-
name: 'list-all-delegates',
|
|
78
|
-
description: 'List all paginated delegates from all gateways',
|
|
79
|
-
options: paginationOptions,
|
|
80
|
-
action: listAllDelegatesCLICommand,
|
|
81
|
-
});
|
|
82
83
|
makeCommand({
|
|
83
84
|
name: 'get-gateway-delegates',
|
|
84
85
|
description: 'Get the delegates of a gateway',
|
|
85
86
|
options: paginationAddressOptions,
|
|
86
87
|
action: getGatewayDelegates,
|
|
87
88
|
});
|
|
89
|
+
makeCommand({
|
|
90
|
+
name: 'get-gateway-vaults',
|
|
91
|
+
description: 'Get the vaults of a gateway',
|
|
92
|
+
options: paginationAddressOptions,
|
|
93
|
+
action: getGatewayVaults,
|
|
94
|
+
});
|
|
88
95
|
makeCommand({
|
|
89
96
|
name: 'get-delegations',
|
|
90
97
|
description: 'Get all stake delegated to gateways from this address',
|
|
@@ -103,36 +110,18 @@ makeCommand({
|
|
|
103
110
|
options: [optionMap.name],
|
|
104
111
|
action: getArNSRecord,
|
|
105
112
|
});
|
|
106
|
-
makeCommand({
|
|
107
|
-
name: 'list-arns-records',
|
|
108
|
-
description: 'List all ArNS records',
|
|
109
|
-
options: paginationOptions,
|
|
110
|
-
action: listArNSRecords,
|
|
111
|
-
});
|
|
112
113
|
makeCommand({
|
|
113
114
|
name: 'get-arns-reserved-name',
|
|
114
115
|
description: 'Get a reserved ArNS name',
|
|
115
116
|
options: [optionMap.name],
|
|
116
117
|
action: getArNSReservedName,
|
|
117
118
|
});
|
|
118
|
-
makeCommand({
|
|
119
|
-
name: 'list-arns-reserved-names',
|
|
120
|
-
description: 'Get all reserved ArNS names',
|
|
121
|
-
options: paginationOptions,
|
|
122
|
-
action: listArNSReservedNames,
|
|
123
|
-
});
|
|
124
119
|
makeCommand({
|
|
125
120
|
name: 'get-arns-returned-name',
|
|
126
121
|
description: 'Get an ArNS returned name by name',
|
|
127
122
|
options: [optionMap.name],
|
|
128
123
|
action: getArNSReturnedName,
|
|
129
124
|
});
|
|
130
|
-
makeCommand({
|
|
131
|
-
name: 'list-arns-returned-names',
|
|
132
|
-
description: 'Get all ArNS recently returned names',
|
|
133
|
-
options: paginationOptions,
|
|
134
|
-
action: listArNSReturnedNames,
|
|
135
|
-
});
|
|
136
125
|
makeCommand({
|
|
137
126
|
name: 'get-epoch',
|
|
138
127
|
description: 'Get epoch data',
|
|
@@ -193,14 +182,11 @@ makeCommand({
|
|
|
193
182
|
action: getCostDetails,
|
|
194
183
|
});
|
|
195
184
|
makeCommand({
|
|
196
|
-
name: '
|
|
197
|
-
description: 'Get
|
|
198
|
-
options:
|
|
199
|
-
action:
|
|
200
|
-
.getVaults(paginationParamsFromOptions(o))
|
|
201
|
-
.then((result) => result.items.length ? result : { message: 'No vaults found' }),
|
|
185
|
+
name: 'get-primary-name',
|
|
186
|
+
description: 'Get primary name',
|
|
187
|
+
options: [optionMap.address, optionMap.name],
|
|
188
|
+
action: getPrimaryName,
|
|
202
189
|
});
|
|
203
|
-
// TODO: Could assert valid arweave (or ETH) addresses at CLI level when coming from options (no need from wallet)
|
|
204
190
|
makeCommand({
|
|
205
191
|
name: 'get-primary-name-request',
|
|
206
192
|
description: 'Get primary name request',
|
|
@@ -213,6 +199,66 @@ makeCommand({
|
|
|
213
199
|
message: `No primary name request found`,
|
|
214
200
|
}),
|
|
215
201
|
});
|
|
202
|
+
makeCommand({
|
|
203
|
+
name: 'get-redelegation-fee',
|
|
204
|
+
description: 'Get redelegation fee',
|
|
205
|
+
options: [optionMap.address],
|
|
206
|
+
action: (options) => readARIOFromOptions(options).getRedelegationFee({
|
|
207
|
+
address: requiredAddressFromOptions(options),
|
|
208
|
+
}),
|
|
209
|
+
});
|
|
210
|
+
makeCommand({
|
|
211
|
+
name: 'get-vault',
|
|
212
|
+
description: 'Get the vault of provided address and vault ID',
|
|
213
|
+
options: getVaultOptions,
|
|
214
|
+
action: getVault,
|
|
215
|
+
});
|
|
216
|
+
// # ArNS Resolution
|
|
217
|
+
makeCommand({
|
|
218
|
+
name: 'resolve-arns-name',
|
|
219
|
+
description: 'Resolve an ArNS name',
|
|
220
|
+
options: [optionMap.name],
|
|
221
|
+
action: resolveArNSName,
|
|
222
|
+
});
|
|
223
|
+
// # Paginated handlers
|
|
224
|
+
makeCommand({
|
|
225
|
+
name: 'list-gateways',
|
|
226
|
+
description: 'List the gateways of the network',
|
|
227
|
+
options: paginationOptions,
|
|
228
|
+
action: listGateways,
|
|
229
|
+
});
|
|
230
|
+
makeCommand({
|
|
231
|
+
name: 'list-all-delegates',
|
|
232
|
+
description: 'List all paginated delegates from all gateways',
|
|
233
|
+
options: paginationOptions,
|
|
234
|
+
action: listAllDelegatesCLICommand,
|
|
235
|
+
});
|
|
236
|
+
makeCommand({
|
|
237
|
+
name: 'list-arns-records',
|
|
238
|
+
description: 'List all ArNS records',
|
|
239
|
+
options: paginationOptions,
|
|
240
|
+
action: listArNSRecords,
|
|
241
|
+
});
|
|
242
|
+
makeCommand({
|
|
243
|
+
name: 'list-arns-reserved-names',
|
|
244
|
+
description: 'Get all reserved ArNS names',
|
|
245
|
+
options: paginationOptions,
|
|
246
|
+
action: listArNSReservedNames,
|
|
247
|
+
});
|
|
248
|
+
makeCommand({
|
|
249
|
+
name: 'list-arns-returned-names',
|
|
250
|
+
description: 'Get all ArNS recently returned names',
|
|
251
|
+
options: paginationOptions,
|
|
252
|
+
action: listArNSReturnedNames,
|
|
253
|
+
});
|
|
254
|
+
makeCommand({
|
|
255
|
+
name: 'list-vaults',
|
|
256
|
+
description: 'Get all wallet vaults',
|
|
257
|
+
options: paginationOptions,
|
|
258
|
+
action: (o) => readARIOFromOptions(o)
|
|
259
|
+
.getVaults(paginationParamsFromOptions(o))
|
|
260
|
+
.then((result) => result.items.length ? result : { message: 'No vaults found' }),
|
|
261
|
+
});
|
|
216
262
|
makeCommand({
|
|
217
263
|
name: 'list-primary-name-requests',
|
|
218
264
|
description: 'Get primary name requests',
|
|
@@ -221,12 +267,6 @@ makeCommand({
|
|
|
221
267
|
.getPrimaryNameRequests(paginationParamsFromOptions(o))
|
|
222
268
|
.then((result) => result.items.length ? result : { message: 'No requests found' }),
|
|
223
269
|
});
|
|
224
|
-
makeCommand({
|
|
225
|
-
name: 'get-primary-name',
|
|
226
|
-
description: 'Get primary name',
|
|
227
|
-
options: [optionMap.address, optionMap.name],
|
|
228
|
-
action: getPrimaryName,
|
|
229
|
-
});
|
|
230
270
|
makeCommand({
|
|
231
271
|
name: 'list-primary-names',
|
|
232
272
|
description: 'Get primary names',
|
|
@@ -235,18 +275,6 @@ makeCommand({
|
|
|
235
275
|
.getPrimaryNames(paginationParamsFromOptions(o))
|
|
236
276
|
.then((result) => result.items.length ? result : { message: 'No names found' }),
|
|
237
277
|
});
|
|
238
|
-
makeCommand({
|
|
239
|
-
name: 'balance',
|
|
240
|
-
description: 'Get the balance of an address',
|
|
241
|
-
options: [optionMap.address],
|
|
242
|
-
action: (options) => readARIOFromOptions(options)
|
|
243
|
-
.getBalance({ address: requiredAddressFromOptions(options) })
|
|
244
|
-
.then((result) => ({
|
|
245
|
-
address: requiredAddressFromOptions(options),
|
|
246
|
-
mARIOBalance: result,
|
|
247
|
-
message: `Provided address current has a balance of ${formatARIOWithCommas(new mARIOToken(result).toARIO())} ARIO`,
|
|
248
|
-
})),
|
|
249
|
-
});
|
|
250
278
|
makeCommand({
|
|
251
279
|
name: 'list-balances',
|
|
252
280
|
description: 'List all balances',
|
|
@@ -255,32 +283,13 @@ makeCommand({
|
|
|
255
283
|
.getBalances(paginationParamsFromOptions(o))
|
|
256
284
|
.then((result) => result.items.length ? result : { message: 'No balances found' }),
|
|
257
285
|
});
|
|
258
|
-
makeCommand({
|
|
259
|
-
name: 'get-redelegation-fee',
|
|
260
|
-
description: 'Get redelegation fee',
|
|
261
|
-
options: [optionMap.address],
|
|
262
|
-
action: (options) => readARIOFromOptions(options).getRedelegationFee({
|
|
263
|
-
address: requiredAddressFromOptions(options),
|
|
264
|
-
}),
|
|
265
|
-
});
|
|
266
|
-
makeCommand({
|
|
267
|
-
name: 'get-vault',
|
|
268
|
-
description: 'Get the vault of provided address and vault ID',
|
|
269
|
-
options: getVaultOptions,
|
|
270
|
-
action: getVault,
|
|
271
|
-
});
|
|
272
|
-
makeCommand({
|
|
273
|
-
name: 'get-gateway-vaults',
|
|
274
|
-
description: 'Get the vaults of a gateway',
|
|
275
|
-
options: paginationAddressOptions,
|
|
276
|
-
action: getGatewayVaults,
|
|
277
|
-
});
|
|
278
286
|
makeCommand({
|
|
279
287
|
name: 'list-all-gateway-vaults',
|
|
280
288
|
description: 'List vaults from all gateways',
|
|
281
289
|
options: paginationAddressOptions,
|
|
282
290
|
action: getAllGatewayVaults,
|
|
283
291
|
});
|
|
292
|
+
// # Actions
|
|
284
293
|
makeCommand({
|
|
285
294
|
name: 'transfer',
|
|
286
295
|
description: 'Transfer ARIO to another address',
|
|
@@ -416,24 +425,8 @@ makeCommand({
|
|
|
416
425
|
options: arnsPurchaseOptions,
|
|
417
426
|
action: requestPrimaryNameCLICommand,
|
|
418
427
|
});
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
description: 'Spawn an ANT process',
|
|
422
|
-
options: antStateOptions,
|
|
423
|
-
action: async (options) => {
|
|
424
|
-
const state = getANTStateFromOptions(options);
|
|
425
|
-
const antProcessId = await spawnANT({
|
|
426
|
-
state,
|
|
427
|
-
signer: requiredAoSignerFromOptions(options),
|
|
428
|
-
logger: getLoggerFromOptions(options),
|
|
429
|
-
});
|
|
430
|
-
return {
|
|
431
|
-
processId: antProcessId,
|
|
432
|
-
state,
|
|
433
|
-
message: `Spawned ANT process with process ID ${antProcessId}`,
|
|
434
|
-
};
|
|
435
|
-
},
|
|
436
|
-
});
|
|
428
|
+
// # ANTS
|
|
429
|
+
// # Getters
|
|
437
430
|
makeCommand({
|
|
438
431
|
name: 'get-ant-state',
|
|
439
432
|
description: 'Get the state of an ANT process',
|
|
@@ -460,14 +453,6 @@ makeCommand({
|
|
|
460
453
|
})) ?? { message: 'No record found' });
|
|
461
454
|
},
|
|
462
455
|
});
|
|
463
|
-
makeCommand({
|
|
464
|
-
name: 'list-ant-records',
|
|
465
|
-
description: 'Get the records of an ANT process',
|
|
466
|
-
options: [optionMap.processId],
|
|
467
|
-
action: async (options) => {
|
|
468
|
-
return readANTFromOptions(options).getRecords();
|
|
469
|
-
},
|
|
470
|
-
});
|
|
471
456
|
makeCommand({
|
|
472
457
|
name: 'get-ant-owner',
|
|
473
458
|
description: 'Get the owner of an ANT process',
|
|
@@ -476,14 +461,6 @@ makeCommand({
|
|
|
476
461
|
return readANTFromOptions(options).getOwner();
|
|
477
462
|
},
|
|
478
463
|
});
|
|
479
|
-
makeCommand({
|
|
480
|
-
name: 'list-ant-controllers',
|
|
481
|
-
description: 'List the controllers of an ANT process',
|
|
482
|
-
options: [optionMap.processId],
|
|
483
|
-
action: async (options) => {
|
|
484
|
-
return readANTFromOptions(options).getControllers();
|
|
485
|
-
},
|
|
486
|
-
});
|
|
487
464
|
makeCommand({
|
|
488
465
|
name: 'get-ant-name',
|
|
489
466
|
description: 'Get the name of an ANT process',
|
|
@@ -510,6 +487,42 @@ makeCommand({
|
|
|
510
487
|
});
|
|
511
488
|
},
|
|
512
489
|
});
|
|
490
|
+
// # Spawn
|
|
491
|
+
makeCommand({
|
|
492
|
+
name: 'spawn-ant',
|
|
493
|
+
description: 'Spawn an ANT process',
|
|
494
|
+
options: antStateOptions,
|
|
495
|
+
action: async (options) => {
|
|
496
|
+
const state = getANTStateFromOptions(options);
|
|
497
|
+
const antProcessId = await spawnANT({
|
|
498
|
+
state,
|
|
499
|
+
signer: requiredAoSignerFromOptions(options),
|
|
500
|
+
logger: getLoggerFromOptions(options),
|
|
501
|
+
});
|
|
502
|
+
return {
|
|
503
|
+
processId: antProcessId,
|
|
504
|
+
state,
|
|
505
|
+
message: `Spawned ANT process with process ID ${antProcessId}`,
|
|
506
|
+
};
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
// # ANT Paginated Handlers
|
|
510
|
+
makeCommand({
|
|
511
|
+
name: 'list-ant-records',
|
|
512
|
+
description: 'Get the records of an ANT process',
|
|
513
|
+
options: [optionMap.processId],
|
|
514
|
+
action: async (options) => {
|
|
515
|
+
return readANTFromOptions(options).getRecords();
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
makeCommand({
|
|
519
|
+
name: 'list-ant-controllers',
|
|
520
|
+
description: 'List the controllers of an ANT process',
|
|
521
|
+
options: [optionMap.processId],
|
|
522
|
+
action: async (options) => {
|
|
523
|
+
return readANTFromOptions(options).getControllers();
|
|
524
|
+
},
|
|
525
|
+
});
|
|
513
526
|
makeCommand({
|
|
514
527
|
name: 'list-ant-balances',
|
|
515
528
|
description: 'Get the balances of an ANT process',
|
|
@@ -518,6 +531,7 @@ makeCommand({
|
|
|
518
531
|
return readANTFromOptions(options).getBalances();
|
|
519
532
|
},
|
|
520
533
|
});
|
|
534
|
+
// # Actions
|
|
521
535
|
makeCommand({
|
|
522
536
|
name: 'transfer-ant-ownership',
|
|
523
537
|
description: 'Transfer ownership of an ANT process',
|
|
@@ -552,6 +566,18 @@ makeCommand({
|
|
|
552
566
|
}, customTagsFromOptions(options));
|
|
553
567
|
},
|
|
554
568
|
});
|
|
569
|
+
makeCommand({
|
|
570
|
+
name: 'remove-ant-record',
|
|
571
|
+
description: 'Remove a record from an ANT process',
|
|
572
|
+
options: [optionMap.processId, optionMap.undername, ...writeActionOptions],
|
|
573
|
+
action: async (options) => {
|
|
574
|
+
const undername = requiredStringFromOptions(options, 'undername');
|
|
575
|
+
await assertConfirmationPrompt(`Are you sure you want to remove the record with undername ${undername}?`, options);
|
|
576
|
+
return writeANTFromOptions(options).removeRecord({
|
|
577
|
+
undername,
|
|
578
|
+
}, customTagsFromOptions(options));
|
|
579
|
+
},
|
|
580
|
+
});
|
|
555
581
|
makeCommand({
|
|
556
582
|
name: 'set-ant-record',
|
|
557
583
|
description: 'Set a record of an ANT process. Deprecated: use set-ant-base-name and set-ant-undername',
|
|
@@ -570,18 +596,6 @@ makeCommand({
|
|
|
570
596
|
options: setAntUndernameOptions,
|
|
571
597
|
action: setAntRecordCLICommand,
|
|
572
598
|
});
|
|
573
|
-
makeCommand({
|
|
574
|
-
name: 'remove-ant-record',
|
|
575
|
-
description: 'Remove a record from an ANT process',
|
|
576
|
-
options: [optionMap.processId, optionMap.undername, ...writeActionOptions],
|
|
577
|
-
action: async (options) => {
|
|
578
|
-
const undername = requiredStringFromOptions(options, 'undername');
|
|
579
|
-
await assertConfirmationPrompt(`Are you sure you want to remove the record with undername ${undername}?`, options);
|
|
580
|
-
return writeANTFromOptions(options).removeRecord({
|
|
581
|
-
undername,
|
|
582
|
-
}, customTagsFromOptions(options));
|
|
583
|
-
},
|
|
584
|
-
});
|
|
585
599
|
makeCommand({
|
|
586
600
|
name: 'set-ant-ticker',
|
|
587
601
|
description: 'Set the ticker of an ANT process',
|
|
@@ -642,11 +656,11 @@ makeCommand({
|
|
|
642
656
|
const txId = requiredStringFromOptions(options, 'transactionId');
|
|
643
657
|
await assertConfirmationPrompt(`Are you sure you want to set the ANT logo to target Arweave TxID ${txId}?`, options);
|
|
644
658
|
return writeANTFromOptions(options).setLogo({
|
|
645
|
-
// TODO: Could take a logo file, upload it to Arweave, get transaction ID
|
|
646
659
|
txId,
|
|
647
660
|
}, customTagsFromOptions(options));
|
|
648
661
|
},
|
|
649
662
|
});
|
|
663
|
+
// # ARIO Actions
|
|
650
664
|
makeCommand({
|
|
651
665
|
name: 'release-name',
|
|
652
666
|
description: 'Release the name of an ANT process',
|
|
@@ -713,6 +727,7 @@ makeCommand({
|
|
|
713
727
|
}, customTagsFromOptions(options));
|
|
714
728
|
},
|
|
715
729
|
});
|
|
730
|
+
// # Utilities
|
|
716
731
|
makeCommand({
|
|
717
732
|
name: 'write-action',
|
|
718
733
|
description: 'Send a write action to an AO Process',
|
|
@@ -165,3 +165,8 @@ export async function getVault(o) {
|
|
|
165
165
|
message: `No vault found for provided address and vault ID`,
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
|
+
export async function resolveArNSName(o) {
|
|
169
|
+
const name = requiredStringFromOptions(o, 'name');
|
|
170
|
+
const result = await readARIOFromOptions(o).resolveArNSName({ name });
|
|
171
|
+
return result ?? { message: `No record found for name ${name}` };
|
|
172
|
+
}
|
package/lib/esm/common/ant.js
CHANGED
|
@@ -89,12 +89,12 @@ export class AoANTReadable {
|
|
|
89
89
|
* ```
|
|
90
90
|
*/
|
|
91
91
|
async getRecord({ undername }, { strict } = { strict: this.strict }) {
|
|
92
|
-
|
|
93
|
-
{ name: 'Sub-Domain', value: undername },
|
|
94
|
-
{ name: 'Action', value: 'Record' },
|
|
95
|
-
];
|
|
92
|
+
// TODO: use sortedANTRecords to get priority on all records, even if ANT does not have a priority set
|
|
96
93
|
const record = await this.process.read({
|
|
97
|
-
tags
|
|
94
|
+
tags: [
|
|
95
|
+
{ name: 'Action', value: 'Record' },
|
|
96
|
+
{ name: 'Sub-Domain', value: undername },
|
|
97
|
+
],
|
|
98
98
|
});
|
|
99
99
|
if (strict)
|
|
100
100
|
parseSchemaResult(AntRecordSchema.passthrough(), record);
|
package/lib/esm/common/io.js
CHANGED
|
@@ -18,6 +18,7 @@ import { ARIO_MAINNET_PROCESS_ID, ARIO_TESTNET_PROCESS_ID, } from '../constants.
|
|
|
18
18
|
import { isProcessConfiguration, isProcessIdConfiguration, } from '../types/index.js';
|
|
19
19
|
import { createAoSigner } from '../utils/ao.js';
|
|
20
20
|
import { getEpochDataFromGqlWithCUFallback, paginationParamsToTags, pruneTags, removeEligibleRewardsFromEpochData, sortAndPaginateEpochDataIntoEligibleDistributions, } from '../utils/arweave.js';
|
|
21
|
+
import { ANT } from './ant.js';
|
|
21
22
|
import { defaultArweave } from './arweave.js';
|
|
22
23
|
import { AOProcess } from './contracts/ao-process.js';
|
|
23
24
|
import { InvalidContractConfigurationError } from './error.js';
|
|
@@ -620,6 +621,42 @@ export class ARIOReadable {
|
|
|
620
621
|
],
|
|
621
622
|
});
|
|
622
623
|
}
|
|
624
|
+
async resolveArNSName({ name, }) {
|
|
625
|
+
const baseName = name.split('_').pop();
|
|
626
|
+
if (baseName === undefined) {
|
|
627
|
+
throw new Error('Invalid name');
|
|
628
|
+
}
|
|
629
|
+
const undername = name === baseName ? '@' : name.replace(`_${baseName}`, '');
|
|
630
|
+
const nameData = await this.getArNSRecord({ name: baseName });
|
|
631
|
+
const ant = ANT.init({
|
|
632
|
+
process: new AOProcess({
|
|
633
|
+
ao: this.process.ao,
|
|
634
|
+
processId: nameData.processId,
|
|
635
|
+
}),
|
|
636
|
+
});
|
|
637
|
+
const [owner, antRecord] = await Promise.all([
|
|
638
|
+
ant.getOwner(),
|
|
639
|
+
ant.getRecord({ undername }),
|
|
640
|
+
]);
|
|
641
|
+
if (antRecord === undefined) {
|
|
642
|
+
throw new Error(`Record for ${undername} not found on ANT.`);
|
|
643
|
+
}
|
|
644
|
+
if (antRecord.ttlSeconds === undefined ||
|
|
645
|
+
antRecord.transactionId === undefined) {
|
|
646
|
+
throw new Error(`Invalid record on ANT. Must have ttlSeconds and transactionId. Record: ${JSON.stringify(antRecord)}`);
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
name: name,
|
|
650
|
+
owner: owner,
|
|
651
|
+
txId: antRecord.transactionId,
|
|
652
|
+
ttlSeconds: antRecord.ttlSeconds,
|
|
653
|
+
priority: antRecord.priority,
|
|
654
|
+
// NOTE: we may want return the actual index of the record based on sorting in case ANT tries to set duplicate priority values to get around undername limits
|
|
655
|
+
processId: nameData.processId,
|
|
656
|
+
undernameLimit: nameData.undernameLimit,
|
|
657
|
+
type: nameData.type,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
623
660
|
}
|
|
624
661
|
export class ARIOWriteable extends ARIOReadable {
|
|
625
662
|
signer;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const arioGatewayHeaders = {
|
|
2
|
+
digest: 'x-ar-io-digest',
|
|
3
|
+
verified: 'x-ar-io-verified',
|
|
4
|
+
txId: 'x-arns-resolved-tx-id',
|
|
5
|
+
processId: 'x-arns-resolved-process-id',
|
|
6
|
+
};
|
|
7
|
+
export class TrustedGatewaysHashProvider {
|
|
8
|
+
gatewaysProvider;
|
|
9
|
+
constructor({ gatewaysProvider,
|
|
10
|
+
// TODO: add threshold for allowed hash difference (i.e. by count or ratio of total gateways checked)
|
|
11
|
+
}) {
|
|
12
|
+
this.gatewaysProvider = gatewaysProvider;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gets the digest for a given txId from all trusted gateways and ensures they all match.
|
|
16
|
+
* @param txId - The txId to get the digest for.
|
|
17
|
+
* @returns The digest for the given txId.
|
|
18
|
+
*/
|
|
19
|
+
async getHash({ txId, }) {
|
|
20
|
+
// get the hash from every gateway, and ensure they all match
|
|
21
|
+
const hashSet = new Set();
|
|
22
|
+
const hashResults = [];
|
|
23
|
+
const gateways = await this.gatewaysProvider.getGateways();
|
|
24
|
+
const hashes = await Promise.all(gateways.map(async (gateway) => {
|
|
25
|
+
const response = await fetch(`${gateway.toString()}${txId}`, {
|
|
26
|
+
method: 'HEAD',
|
|
27
|
+
redirect: 'follow',
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
// skip this gateway
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const txIdHash = response.headers.get(arioGatewayHeaders.digest);
|
|
34
|
+
if (txIdHash === null || txIdHash === undefined) {
|
|
35
|
+
// skip this gateway
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
hashResults.push({
|
|
39
|
+
gateway: gateway.hostname,
|
|
40
|
+
txIdHash,
|
|
41
|
+
});
|
|
42
|
+
return txIdHash;
|
|
43
|
+
}));
|
|
44
|
+
for (const hash of hashes) {
|
|
45
|
+
if (hash !== undefined) {
|
|
46
|
+
hashSet.add(hash);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (hashSet.size === 0) {
|
|
50
|
+
throw new Error(`No trusted gateways found for txId ${txId}`);
|
|
51
|
+
}
|
|
52
|
+
if (hashSet.size > 1) {
|
|
53
|
+
throw new Error(`Failed to get consistent hash from all trusted gateways. ${JSON.stringify(hashResults)}`);
|
|
54
|
+
}
|
|
55
|
+
return { hash: hashResults[0].txIdHash, algorithm: 'sha256' };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the data root for a given txId from all trusted gateways and ensure they all match.
|
|
59
|
+
* @param txId - The txId to get the data root for.
|
|
60
|
+
* @returns The data root for the given txId.
|
|
61
|
+
*/
|
|
62
|
+
async getDataRoot({ txId }) {
|
|
63
|
+
const dataRootSet = new Set();
|
|
64
|
+
const dataRootResults = [];
|
|
65
|
+
const gateways = await this.gatewaysProvider.getGateways();
|
|
66
|
+
const dataRoots = await Promise.all(gateways.map(async (gateway) => {
|
|
67
|
+
const response = await fetch(`${gateway.toString()}tx/${txId}/data_root`);
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
// skip this gateway
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
const dataRoot = await response.text();
|
|
73
|
+
dataRootResults.push({
|
|
74
|
+
gateway: gateway.hostname,
|
|
75
|
+
dataRoot,
|
|
76
|
+
});
|
|
77
|
+
return dataRoot;
|
|
78
|
+
}));
|
|
79
|
+
for (const dataRoot of dataRoots) {
|
|
80
|
+
if (dataRoot !== undefined) {
|
|
81
|
+
dataRootSet.add(dataRoot);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (dataRootSet.size > 1) {
|
|
85
|
+
throw new Error(`Failed to get consistent data root from all trusted gateways. ${JSON.stringify(dataRootResults)}`);
|
|
86
|
+
}
|
|
87
|
+
return dataRootSet.values().next().value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// client could check hashes of data items, match expected hash
|
|
91
|
+
// if the gateway has the hash and they've verified it, you can trust the data item and offset
|
|
92
|
+
// you would be only trusting the gateway that it is a valid bundle
|
|
93
|
+
// you can request the offset from the gateway to verify the id
|
|
94
|
+
/**
|
|
95
|
+
* Note from @djwhitt
|
|
96
|
+
*
|
|
97
|
+
* Calculating data roots this way is fine, but it may not reproduce the original data root.
|
|
98
|
+
* We could also implement a data root verifier that pulls all the chunks, checks that they
|
|
99
|
+
* reproduce the expected data root, and then compares the concatenated chunk data to the
|
|
100
|
+
* original data retrieved. That would take a while, but it should be able to verify any L1
|
|
101
|
+
* data where we can find the chunks.
|
|
102
|
+
*/
|
|
@@ -20,3 +20,9 @@ export * from './routers/priority.js';
|
|
|
20
20
|
export * from './routers/static.js';
|
|
21
21
|
// gateways providers
|
|
22
22
|
export * from './gateways.js';
|
|
23
|
+
// trusted gateways
|
|
24
|
+
export * from './gateways/trusted-gateways.js';
|
|
25
|
+
// hash providers
|
|
26
|
+
export * from './verification/data-root-verifier.js';
|
|
27
|
+
export * from './verification/hash-verifier.js';
|
|
28
|
+
// TODO: signature verification
|