@ar.io/sdk 3.24.0 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +682 -600
- package/lib/esm/cli/cli.js +188 -152
- package/lib/esm/cli/commands/antCommands.js +23 -58
- package/lib/esm/cli/commands/arnsPurchaseCommands.js +48 -30
- package/lib/esm/cli/commands/escrowCommands.js +221 -0
- package/lib/esm/cli/commands/gatewayWriteCommands.js +142 -23
- package/lib/esm/cli/commands/pruneCommands.js +150 -0
- package/lib/esm/cli/commands/readCommands.js +22 -3
- package/lib/esm/cli/commands/transfer.js +6 -6
- package/lib/esm/cli/options.js +124 -58
- package/lib/esm/cli/utils.js +280 -174
- package/lib/esm/common/ant-registry.js +17 -143
- package/lib/esm/common/ant.js +44 -1167
- package/lib/esm/common/faucet.js +11 -6
- package/lib/esm/common/index.js +0 -4
- package/lib/esm/common/io.js +25 -1412
- package/lib/esm/constants.js +13 -19
- package/lib/esm/solana/ant-readable.js +724 -0
- package/lib/esm/solana/ant-registry-readable.js +133 -0
- package/lib/esm/solana/ant-registry-writeable.js +472 -0
- package/lib/esm/solana/ant-writeable.js +384 -0
- package/lib/esm/solana/ata.js +70 -0
- package/lib/esm/solana/canonical-message.js +128 -0
- package/lib/esm/solana/clusters.js +111 -0
- package/lib/esm/solana/constants.js +146 -0
- package/lib/esm/solana/delegation-math.js +112 -0
- package/lib/esm/solana/deserialize.js +711 -0
- package/lib/esm/solana/escrow.js +839 -0
- package/lib/{cjs/utils/json.js → esm/solana/events.js} +15 -10
- package/lib/esm/solana/funding-plan.js +699 -0
- package/lib/esm/solana/index.js +126 -0
- package/lib/esm/solana/instruction.js +39 -0
- package/lib/esm/solana/io-readable.js +2182 -0
- package/lib/esm/solana/io-writeable.js +3196 -0
- package/lib/esm/solana/json-rpc.js +90 -0
- package/lib/esm/solana/metadata.js +81 -0
- package/lib/esm/solana/mpl-core.js +192 -0
- package/lib/esm/solana/pda.js +332 -0
- package/lib/esm/solana/predict-prescribed-observers.js +110 -0
- package/lib/esm/solana/retry.js +117 -0
- package/lib/esm/solana/rpc-circuit-breaker.js +258 -0
- package/lib/esm/solana/send.js +372 -0
- package/lib/esm/solana/spawn-ant.js +224 -0
- package/lib/esm/solana/types.js +1 -0
- package/lib/esm/types/ant.js +27 -15
- package/lib/esm/types/io.js +8 -11
- package/lib/esm/utils/ant.js +0 -63
- package/lib/esm/utils/index.js +0 -3
- package/lib/esm/version.js +1 -1
- package/lib/types/cli/commands/antCommands.d.ts +5 -13
- package/lib/types/cli/commands/arnsPurchaseCommands.d.ts +33 -7
- package/lib/types/cli/commands/escrowCommands.d.ts +68 -0
- package/lib/types/cli/commands/gatewayWriteCommands.d.ts +12 -11
- package/lib/types/cli/commands/pruneCommands.d.ts +31 -0
- package/lib/types/cli/commands/readCommands.d.ts +27 -22
- package/lib/types/cli/commands/transfer.d.ts +9 -9
- package/lib/types/cli/options.d.ts +76 -21
- package/lib/types/cli/types.d.ts +11 -13
- package/lib/types/cli/utils.d.ts +71 -31
- package/lib/types/common/ant-registry.d.ts +49 -47
- package/lib/types/common/ant.d.ts +54 -539
- package/lib/types/common/faucet.d.ts +20 -8
- package/lib/types/common/index.d.ts +0 -3
- package/lib/types/common/io.d.ts +51 -263
- package/lib/types/constants.d.ts +11 -18
- package/lib/types/solana/ant-readable.d.ts +180 -0
- package/lib/types/solana/ant-registry-readable.d.ts +105 -0
- package/lib/types/solana/ant-registry-writeable.d.ts +249 -0
- package/lib/types/solana/ant-writeable.d.ts +177 -0
- package/lib/types/solana/ata.d.ts +44 -0
- package/lib/types/solana/canonical-message.d.ts +121 -0
- package/lib/types/solana/clusters.d.ts +109 -0
- package/lib/types/solana/constants.d.ts +119 -0
- package/lib/types/solana/delegation-math.d.ts +45 -0
- package/lib/types/solana/deserialize.d.ts +262 -0
- package/lib/types/solana/escrow.d.ts +480 -0
- package/lib/types/solana/events.d.ts +38 -0
- package/lib/types/solana/funding-plan.d.ts +225 -0
- package/lib/types/solana/index.d.ts +87 -0
- package/lib/types/solana/instruction.d.ts +39 -0
- package/lib/types/solana/io-readable.d.ts +499 -0
- package/lib/types/solana/io-writeable.d.ts +893 -0
- package/lib/types/solana/json-rpc.d.ts +47 -0
- package/lib/types/solana/metadata.d.ts +84 -0
- package/lib/types/solana/mpl-core.d.ts +120 -0
- package/lib/types/solana/pda.d.ts +95 -0
- package/lib/types/solana/predict-prescribed-observers.d.ts +28 -0
- package/lib/types/solana/retry.d.ts +62 -0
- package/lib/types/solana/rpc-circuit-breaker.d.ts +78 -0
- package/lib/types/solana/send.d.ts +94 -0
- package/lib/types/solana/spawn-ant.d.ts +145 -0
- package/lib/types/solana/types.d.ts +82 -0
- package/lib/types/types/ant-registry.d.ts +43 -4
- package/lib/types/types/ant.d.ts +114 -96
- package/lib/types/types/common.d.ts +18 -74
- package/lib/types/types/faucet.d.ts +2 -2
- package/lib/types/types/io.d.ts +244 -158
- package/lib/types/types/token.d.ts +0 -12
- package/lib/types/utils/ant.d.ts +1 -12
- package/lib/types/utils/index.d.ts +0 -3
- package/lib/types/version.d.ts +1 -1
- package/package.json +36 -33
- package/lib/cjs/cli/cli.js +0 -822
- package/lib/cjs/cli/commands/antCommands.js +0 -113
- package/lib/cjs/cli/commands/arnsPurchaseCommands.js +0 -212
- package/lib/cjs/cli/commands/gatewayWriteCommands.js +0 -210
- package/lib/cjs/cli/commands/readCommands.js +0 -215
- package/lib/cjs/cli/commands/transfer.js +0 -159
- package/lib/cjs/cli/options.js +0 -470
- package/lib/cjs/cli/types.js +0 -2
- package/lib/cjs/cli/utils.js +0 -639
- package/lib/cjs/common/ant-registry.js +0 -155
- package/lib/cjs/common/ant-versions.js +0 -93
- package/lib/cjs/common/ant.js +0 -1182
- package/lib/cjs/common/arweave.js +0 -27
- package/lib/cjs/common/contracts/ao-process.js +0 -224
- package/lib/cjs/common/error.js +0 -64
- package/lib/cjs/common/faucet.js +0 -150
- package/lib/cjs/common/hyperbeam/hb.js +0 -173
- package/lib/cjs/common/index.js +0 -42
- package/lib/cjs/common/io.js +0 -1423
- package/lib/cjs/common/logger.js +0 -83
- package/lib/cjs/common/loggers/winston.js +0 -68
- package/lib/cjs/common/marketplace.js +0 -731
- package/lib/cjs/common/turbo.js +0 -223
- package/lib/cjs/constants.js +0 -41
- package/lib/cjs/node/index.js +0 -39
- package/lib/cjs/package.json +0 -1
- package/lib/cjs/types/ant-registry.js +0 -2
- package/lib/cjs/types/ant.js +0 -168
- package/lib/cjs/types/common.js +0 -2
- package/lib/cjs/types/faucet.js +0 -2
- package/lib/cjs/types/index.js +0 -37
- package/lib/cjs/types/io.js +0 -51
- package/lib/cjs/types/token.js +0 -116
- package/lib/cjs/utils/ant.js +0 -108
- package/lib/cjs/utils/ao.js +0 -432
- package/lib/cjs/utils/arweave.js +0 -285
- package/lib/cjs/utils/base64.js +0 -62
- package/lib/cjs/utils/hash.js +0 -56
- package/lib/cjs/utils/index.js +0 -38
- package/lib/cjs/utils/processes.js +0 -173
- package/lib/cjs/utils/random.js +0 -30
- package/lib/cjs/utils/schema.js +0 -15
- package/lib/cjs/utils/url.js +0 -37
- package/lib/cjs/version.js +0 -20
- package/lib/cjs/web/index.js +0 -41
- package/lib/esm/common/ant-versions.js +0 -87
- package/lib/esm/common/arweave.js +0 -21
- package/lib/esm/common/contracts/ao-process.js +0 -220
- package/lib/esm/common/hyperbeam/hb.js +0 -169
- package/lib/esm/common/marketplace.js +0 -724
- package/lib/esm/common/turbo.js +0 -215
- package/lib/esm/node/index.js +0 -20
- package/lib/esm/utils/ao.js +0 -420
- package/lib/esm/utils/arweave.js +0 -271
- package/lib/esm/utils/processes.js +0 -167
- package/lib/esm/web/index.js +0 -20
- package/lib/types/common/ant-versions.d.ts +0 -39
- package/lib/types/common/arweave.d.ts +0 -17
- package/lib/types/common/contracts/ao-process.d.ts +0 -47
- package/lib/types/common/hyperbeam/hb.d.ts +0 -88
- package/lib/types/common/marketplace.d.ts +0 -568
- package/lib/types/common/turbo.d.ts +0 -61
- package/lib/types/node/index.d.ts +0 -20
- package/lib/types/utils/ao.d.ts +0 -80
- package/lib/types/utils/arweave.d.ts +0 -79
- package/lib/types/utils/processes.d.ts +0 -39
- package/lib/types/web/index.d.ts +0 -20
package/lib/esm/common/turbo.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
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 { ArconnectSigner, ArweaveSigner, EthereumSigner, InjectedEthereumSigner, SignatureConfig, } from '@dha-team/arbundles';
|
|
17
|
-
import { mARIOToken } from '../types/token.js';
|
|
18
|
-
import { toB64Url } from '../utils/base64.js';
|
|
19
|
-
import { urlWithSearchParams } from '../utils/url.js';
|
|
20
|
-
import { version } from '../version.js';
|
|
21
|
-
import { Logger } from './logger.js';
|
|
22
|
-
export const defaultHeaders = {
|
|
23
|
-
'x-source-version': `${version}`,
|
|
24
|
-
'x-source-identifier': 'ar-io-sdk',
|
|
25
|
-
};
|
|
26
|
-
export async function signedRequestHeadersFromSigner({ signer, nonce = crypto.randomUUID(), }) {
|
|
27
|
-
let signature = undefined;
|
|
28
|
-
let publicKey = undefined;
|
|
29
|
-
const signatureType = isWanderArweaveBrowserSigner(signer)
|
|
30
|
-
? SignatureConfig.ARWEAVE
|
|
31
|
-
: signer.signatureType;
|
|
32
|
-
// equivalent to window.arweaveWallet
|
|
33
|
-
if (isWanderArweaveBrowserSigner(signer)) {
|
|
34
|
-
signature = toB64Url(Buffer.from(await signer.signMessage(Uint8Array.from(Buffer.from(nonce)))));
|
|
35
|
-
}
|
|
36
|
-
else if (signer instanceof ArconnectSigner) {
|
|
37
|
-
signature = toB64Url(Buffer.from(await signer['signer'].signMessage(Uint8Array.from(Buffer.from(nonce)))));
|
|
38
|
-
}
|
|
39
|
-
else if (signer instanceof ArweaveSigner ||
|
|
40
|
-
signer instanceof EthereumSigner ||
|
|
41
|
-
signer instanceof InjectedEthereumSigner) {
|
|
42
|
-
if ('setPublicKey' in signer && signer['publicKey'] === undefined) {
|
|
43
|
-
await signer.setPublicKey();
|
|
44
|
-
}
|
|
45
|
-
signature = toB64Url(Buffer.from(await signer.sign(Uint8Array.from(Buffer.from(nonce)))));
|
|
46
|
-
}
|
|
47
|
-
switch (signatureType) {
|
|
48
|
-
case SignatureConfig.ARWEAVE:
|
|
49
|
-
if (isWanderArweaveBrowserSigner(signer)) {
|
|
50
|
-
publicKey = await signer.getActivePublicKey();
|
|
51
|
-
}
|
|
52
|
-
else if ('setPublicKey' in signer) {
|
|
53
|
-
await signer.setPublicKey();
|
|
54
|
-
publicKey = toB64Url(signer.publicKey);
|
|
55
|
-
}
|
|
56
|
-
else if ('publicKey' in signer) {
|
|
57
|
-
publicKey = toB64Url(signer.publicKey);
|
|
58
|
-
}
|
|
59
|
-
break;
|
|
60
|
-
case SignatureConfig.ETHEREUM:
|
|
61
|
-
if ('publicKey' in signer) {
|
|
62
|
-
publicKey = '0x' + signer.publicKey.toString('hex');
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
throw new Error('Public key not found');
|
|
66
|
-
}
|
|
67
|
-
break;
|
|
68
|
-
// TODO: solana sig support
|
|
69
|
-
// case SignatureConfig.SOLANA:
|
|
70
|
-
// case SignatureConfig.ED25519:
|
|
71
|
-
default:
|
|
72
|
-
throw new Error(`Unsupported signer type for signing requests: ${signatureType}`);
|
|
73
|
-
}
|
|
74
|
-
if (publicKey === undefined || signature === undefined) {
|
|
75
|
-
throw new Error('Public key or signature not found');
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
'x-public-key': publicKey,
|
|
79
|
-
'x-nonce': nonce,
|
|
80
|
-
'x-signature': signature,
|
|
81
|
-
'x-signature-type': signatureType.toString(),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
export class TurboArNSPaymentFactory {
|
|
85
|
-
static init(config) {
|
|
86
|
-
const { signer, paymentUrl, logger } = config ?? {};
|
|
87
|
-
if (signer !== undefined) {
|
|
88
|
-
return new TurboArNSPaymentProviderAuthenticated({
|
|
89
|
-
signer,
|
|
90
|
-
paymentUrl,
|
|
91
|
-
logger,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
return new TurboArNSPaymentProviderUnauthenticated({
|
|
95
|
-
paymentUrl,
|
|
96
|
-
logger,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
// Base class for unauthenticated operations
|
|
101
|
-
export class TurboArNSPaymentProviderUnauthenticated {
|
|
102
|
-
paymentUrl;
|
|
103
|
-
logger;
|
|
104
|
-
constructor({ paymentUrl = 'https://payment.ardrive.io', logger = Logger.default, }) {
|
|
105
|
-
this.paymentUrl = paymentUrl;
|
|
106
|
-
this.logger = logger;
|
|
107
|
-
}
|
|
108
|
-
async getArNSPriceDetails({ intent, name, quantity, type, years, }) {
|
|
109
|
-
const url = urlWithSearchParams({
|
|
110
|
-
baseUrl: `${this.paymentUrl}/v1/arns/price/${intent}/${name}`,
|
|
111
|
-
params: {
|
|
112
|
-
increaseQty: quantity,
|
|
113
|
-
type,
|
|
114
|
-
years,
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
const response = await fetch(url, {
|
|
118
|
-
method: 'GET',
|
|
119
|
-
headers: defaultHeaders,
|
|
120
|
-
});
|
|
121
|
-
const status = response.status;
|
|
122
|
-
const data = (await response.json());
|
|
123
|
-
this.logger.debug('getArNSPriceDetails', {
|
|
124
|
-
intent,
|
|
125
|
-
name,
|
|
126
|
-
quantity,
|
|
127
|
-
type,
|
|
128
|
-
years,
|
|
129
|
-
data,
|
|
130
|
-
status,
|
|
131
|
-
});
|
|
132
|
-
if (status !== 200) {
|
|
133
|
-
throw new Error('Failed to get ArNS purchase price ' + JSON.stringify(data));
|
|
134
|
-
}
|
|
135
|
-
if (!data.winc || !data.mARIO) {
|
|
136
|
-
throw new Error('Invalid response from Turbo ' + JSON.stringify(data));
|
|
137
|
-
}
|
|
138
|
-
return {
|
|
139
|
-
winc: data.winc,
|
|
140
|
-
mARIO: new mARIOToken(+data.mARIO),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
async getPrice(params) {
|
|
144
|
-
const { winc } = await this.getArNSPriceDetails(params);
|
|
145
|
-
return +winc;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// Class for authenticated operations, extending the base class
|
|
149
|
-
export class TurboArNSPaymentProviderAuthenticated extends TurboArNSPaymentProviderUnauthenticated {
|
|
150
|
-
signer;
|
|
151
|
-
constructor({ signer, ...restConfig }) {
|
|
152
|
-
super(restConfig); // Pass unauthenticated config to base class+
|
|
153
|
-
if (!isTurboArNSSigner(signer)) {
|
|
154
|
-
throw new Error('Signer must be a TurboArNSSigner');
|
|
155
|
-
}
|
|
156
|
-
this.signer = signer;
|
|
157
|
-
}
|
|
158
|
-
async initiateArNSPurchase({ intent, name, quantity, type, processId, years, paidBy = [], referrer, }) {
|
|
159
|
-
// Signer check is implicitly handled by requiring it in the constructor
|
|
160
|
-
const url = urlWithSearchParams({
|
|
161
|
-
baseUrl: `${this.paymentUrl}/v1/arns/purchase/${intent}/${name}`,
|
|
162
|
-
params: {
|
|
163
|
-
increaseQty: quantity,
|
|
164
|
-
processId,
|
|
165
|
-
type,
|
|
166
|
-
years,
|
|
167
|
-
paidBy,
|
|
168
|
-
referrer,
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
const signedHeaders = await signedRequestHeadersFromSigner({
|
|
172
|
-
signer: this.signer,
|
|
173
|
-
});
|
|
174
|
-
const response = await fetch(url, {
|
|
175
|
-
method: 'POST',
|
|
176
|
-
headers: {
|
|
177
|
-
...defaultHeaders,
|
|
178
|
-
...signedHeaders,
|
|
179
|
-
},
|
|
180
|
-
});
|
|
181
|
-
const status = response.status;
|
|
182
|
-
const data = (await response.json());
|
|
183
|
-
this.logger.debug('Initiated ArNS purchase', {
|
|
184
|
-
intent,
|
|
185
|
-
name,
|
|
186
|
-
quantity,
|
|
187
|
-
processId,
|
|
188
|
-
type,
|
|
189
|
-
years,
|
|
190
|
-
data,
|
|
191
|
-
status,
|
|
192
|
-
});
|
|
193
|
-
if (status !== 200) {
|
|
194
|
-
throw new Error('Failed to initiate ArNS purchase ' + JSON.stringify(data));
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
id: data.arioWriteResult.id,
|
|
198
|
-
result: data.purchaseReceipt,
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function isWanderArweaveBrowserSigner(signer) {
|
|
203
|
-
return (typeof signer === 'object' &&
|
|
204
|
-
signer !== null &&
|
|
205
|
-
'signMessage' in signer &&
|
|
206
|
-
'getActivePublicKey' in signer);
|
|
207
|
-
}
|
|
208
|
-
export function isTurboArNSSigner(signer) {
|
|
209
|
-
const isWanderWallet = isWanderArweaveBrowserSigner(signer);
|
|
210
|
-
const isSigner = signer instanceof EthereumSigner ||
|
|
211
|
-
signer instanceof InjectedEthereumSigner ||
|
|
212
|
-
signer instanceof ArweaveSigner ||
|
|
213
|
-
signer instanceof ArconnectSigner;
|
|
214
|
-
return isWanderWallet || isSigner;
|
|
215
|
-
}
|
package/lib/esm/node/index.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
export { ArweaveSigner, ArconnectSigner } from '@dha-team/arbundles';
|
|
17
|
-
export * from '../types/index.js';
|
|
18
|
-
export * from '../common/index.js';
|
|
19
|
-
export * from '../constants.js';
|
|
20
|
-
export * from '../utils/index.js';
|
package/lib/esm/utils/ao.js
DELETED
|
@@ -1,420 +0,0 @@
|
|
|
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 { ArconnectSigner, DataItem, createData } from '@dha-team/arbundles';
|
|
17
|
-
import { connect, createDataItemSigner } from '@permaweb/aoconnect';
|
|
18
|
-
import { z } from 'zod';
|
|
19
|
-
import { ANTRegistry } from '../common/ant-registry.js';
|
|
20
|
-
import { ANTVersions } from '../common/ant-versions.js';
|
|
21
|
-
import { defaultArweave } from '../common/arweave.js';
|
|
22
|
-
import { ANT, AOProcess, Logger } from '../common/index.js';
|
|
23
|
-
import { ANT_LUA_ID, ANT_REGISTRY_ID, AO_AUTHORITY, DEFAULT_SCHEDULER_ID, } from '../constants.js';
|
|
24
|
-
import { SpawnANTStateSchema } from '../types/ant.js';
|
|
25
|
-
import { parseSchemaResult } from './schema.js';
|
|
26
|
-
export async function spawnANT({ signer, module, ao = connect({
|
|
27
|
-
MODE: 'legacy',
|
|
28
|
-
}), scheduler = DEFAULT_SCHEDULER_ID, state, tags = [], antRegistryId = ANT_REGISTRY_ID, logger = Logger.default, authority = AO_AUTHORITY, onSigningProgress = (name, payload) => {
|
|
29
|
-
logger.debug('Signing progress', { name, payload });
|
|
30
|
-
}, hyperbeamUrl, }) {
|
|
31
|
-
if (state) {
|
|
32
|
-
parseSchemaResult(SpawnANTStateSchema, state);
|
|
33
|
-
}
|
|
34
|
-
let version;
|
|
35
|
-
if (module === undefined) {
|
|
36
|
-
const antRegistry = ANTVersions.init({
|
|
37
|
-
process: new AOProcess({
|
|
38
|
-
processId: antRegistryId,
|
|
39
|
-
ao,
|
|
40
|
-
logger,
|
|
41
|
-
}),
|
|
42
|
-
});
|
|
43
|
-
const { moduleId: latestAntModule, version: latestVersion } = await antRegistry.getLatestANTVersion();
|
|
44
|
-
logger.debug('Spawning new ANT with latest module from ANT registry', {
|
|
45
|
-
moduleId: latestAntModule,
|
|
46
|
-
version: latestVersion,
|
|
47
|
-
antRegistryId,
|
|
48
|
-
});
|
|
49
|
-
module = latestAntModule;
|
|
50
|
-
version = latestVersion;
|
|
51
|
-
}
|
|
52
|
-
onSigningProgress?.('spawning-ant', {
|
|
53
|
-
moduleId: module,
|
|
54
|
-
antRegistryId,
|
|
55
|
-
version,
|
|
56
|
-
state,
|
|
57
|
-
});
|
|
58
|
-
const processId = await ao.spawn({
|
|
59
|
-
module,
|
|
60
|
-
scheduler,
|
|
61
|
-
signer,
|
|
62
|
-
data: state ? JSON.stringify(state) : undefined,
|
|
63
|
-
tags: [
|
|
64
|
-
// Required for AOS to initialize the authorities table
|
|
65
|
-
{
|
|
66
|
-
name: 'Authority',
|
|
67
|
-
value: authority,
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: 'ANT-Registry-Id',
|
|
71
|
-
value: antRegistryId,
|
|
72
|
-
},
|
|
73
|
-
...tags,
|
|
74
|
-
],
|
|
75
|
-
});
|
|
76
|
-
/**
|
|
77
|
-
* Note: if we are given a state, ensure the ANT was initialized with it
|
|
78
|
-
* there is a bug in the ANT source where we try to parse the empty default
|
|
79
|
-
* 'Data' string as JSON that causes the Invalid-Boot-Notice error, even though
|
|
80
|
-
* the ANT was initialized with the default state set by the ANT source code.
|
|
81
|
-
*
|
|
82
|
-
* Reference: https://github.com/ar-io/ar-io-ant-process/blob/b89018ffcce079add2e90e7ab82d0bbc9b671346/src/common/main.lua#L355-L358
|
|
83
|
-
*/
|
|
84
|
-
if (state !== undefined) {
|
|
85
|
-
let bootRes;
|
|
86
|
-
let attempts = 0;
|
|
87
|
-
while (attempts < 5 && bootRes === undefined) {
|
|
88
|
-
try {
|
|
89
|
-
// TODO: could add a progress event here to show the boot progress and number of attempts
|
|
90
|
-
if (bootRes === undefined) {
|
|
91
|
-
bootRes = await ao.result({
|
|
92
|
-
process: processId,
|
|
93
|
-
message: processId,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
logger.debug('Retrying ANT boot result fetch', {
|
|
100
|
-
processId,
|
|
101
|
-
module,
|
|
102
|
-
scheduler,
|
|
103
|
-
attempts,
|
|
104
|
-
error,
|
|
105
|
-
});
|
|
106
|
-
attempts++;
|
|
107
|
-
await new Promise((resolve) => setTimeout(resolve, 1000 * attempts ** 2));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (bootRes === undefined ||
|
|
111
|
-
bootRes.Messages?.some((m) => m?.Tags?.some((t) => t.value === 'Invalid-Boot-Notice'))) {
|
|
112
|
-
if (bootRes === undefined) {
|
|
113
|
-
throw new Error('Failed to get boot result');
|
|
114
|
-
}
|
|
115
|
-
const bootError = errorMessageFromOutput(bootRes);
|
|
116
|
-
logger.error('ANT failed to boot correctly', {
|
|
117
|
-
processId,
|
|
118
|
-
module,
|
|
119
|
-
scheduler,
|
|
120
|
-
bootRes,
|
|
121
|
-
bootError,
|
|
122
|
-
});
|
|
123
|
-
throw new Error(`ANT failed to boot correctly: ${bootError}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
onSigningProgress?.('verifying-state', {
|
|
127
|
-
processId,
|
|
128
|
-
moduleId: module,
|
|
129
|
-
antRegistryId,
|
|
130
|
-
});
|
|
131
|
-
// Note: for hyperbeam caching, due to a SU issue, we need to send a second message to the ANT to cache the state
|
|
132
|
-
// We wait for the first message to be processed before sending the second one to ensure this is the second message
|
|
133
|
-
// We use the resulting state to check the owner of the ANT is set in the registry. Should this be patched on MUs,
|
|
134
|
-
// we can convert to just a simple dry-run to avoid sending/signing another message.
|
|
135
|
-
let owner;
|
|
136
|
-
try {
|
|
137
|
-
const processApi = new AOProcess({
|
|
138
|
-
processId,
|
|
139
|
-
ao,
|
|
140
|
-
logger,
|
|
141
|
-
});
|
|
142
|
-
const { id } = await processApi.send({
|
|
143
|
-
tags: [{ name: 'Action', value: 'State' }],
|
|
144
|
-
signer,
|
|
145
|
-
});
|
|
146
|
-
const stateResult = await ao.result({
|
|
147
|
-
process: processId,
|
|
148
|
-
message: id,
|
|
149
|
-
});
|
|
150
|
-
if (stateResult === undefined) {
|
|
151
|
-
throw new Error('Failed to get state result');
|
|
152
|
-
}
|
|
153
|
-
const { Owner } = JSON.parse(stateResult.Messages?.[0]?.Data ?? '{}');
|
|
154
|
-
owner = Owner;
|
|
155
|
-
logger.debug(`Successfully spawned new ANT and validated owner`, {
|
|
156
|
-
processId,
|
|
157
|
-
module,
|
|
158
|
-
owner,
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
logger.error('Failed to validate owner of spawned ANT', {
|
|
163
|
-
processId,
|
|
164
|
-
module,
|
|
165
|
-
error,
|
|
166
|
-
});
|
|
167
|
-
throw error;
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Now confirm the owner of the ANT is set in the registry
|
|
171
|
-
* This is to ensure the ANT is available via the ANT registry
|
|
172
|
-
* for the owner to find and use the ANT.
|
|
173
|
-
*/
|
|
174
|
-
if (owner === undefined) {
|
|
175
|
-
throw new Error(`Spawning ANT (${processId}) failed to set owner`);
|
|
176
|
-
}
|
|
177
|
-
onSigningProgress?.('registering-ant', {
|
|
178
|
-
processId,
|
|
179
|
-
antRegistryId,
|
|
180
|
-
owner,
|
|
181
|
-
});
|
|
182
|
-
// check the ACL for the owner
|
|
183
|
-
const antRegistry = ANTRegistry.init({
|
|
184
|
-
signer,
|
|
185
|
-
process: new AOProcess({
|
|
186
|
-
processId: antRegistryId,
|
|
187
|
-
ao,
|
|
188
|
-
logger,
|
|
189
|
-
}),
|
|
190
|
-
hyperbeamUrl,
|
|
191
|
-
});
|
|
192
|
-
let attempts = 0;
|
|
193
|
-
const maxAttempts = 5;
|
|
194
|
-
while (attempts < maxAttempts) {
|
|
195
|
-
try {
|
|
196
|
-
const acl = await antRegistry.accessControlList({ address: owner });
|
|
197
|
-
if (acl === undefined) {
|
|
198
|
-
throw new Error('ACL not found for owner');
|
|
199
|
-
}
|
|
200
|
-
const { Owned } = acl;
|
|
201
|
-
if (!Owned.includes(processId)) {
|
|
202
|
-
throw new Error(`Spawned ANT (${processId}) not found in registry for owner ${owner}`);
|
|
203
|
-
}
|
|
204
|
-
return processId;
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
logger.debug('Retrying ANT registry access control list fetch', {
|
|
208
|
-
owner,
|
|
209
|
-
antRegistryId,
|
|
210
|
-
attempts,
|
|
211
|
-
error,
|
|
212
|
-
});
|
|
213
|
-
attempts++;
|
|
214
|
-
await new Promise((resolve) => setTimeout(resolve, 1000 * attempts ** 2));
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return processId;
|
|
218
|
-
}
|
|
219
|
-
export async function forkANT({ signer, antProcessId, logger = Logger.default, ao, moduleId, antRegistryId = ANT_REGISTRY_ID, onSigningProgress = (name, payload) => {
|
|
220
|
-
logger.debug('Forking ANT', { name, payload });
|
|
221
|
-
}, hyperbeamUrl, }) {
|
|
222
|
-
// get the state of the current ANT and use it to spawn a new ANT
|
|
223
|
-
const ant = ANT.init({
|
|
224
|
-
process: new AOProcess({
|
|
225
|
-
processId: antProcessId,
|
|
226
|
-
ao,
|
|
227
|
-
logger,
|
|
228
|
-
}),
|
|
229
|
-
hyperbeamUrl,
|
|
230
|
-
});
|
|
231
|
-
const state = await ant.getState();
|
|
232
|
-
if (state === undefined) {
|
|
233
|
-
throw new Error(`ANT state (${antProcessId}) is undefined and cannot be upgraded`);
|
|
234
|
-
}
|
|
235
|
-
const forkedProcessId = await spawnANT({
|
|
236
|
-
signer,
|
|
237
|
-
antRegistryId,
|
|
238
|
-
ao,
|
|
239
|
-
logger,
|
|
240
|
-
module: moduleId,
|
|
241
|
-
onSigningProgress,
|
|
242
|
-
state: {
|
|
243
|
-
owner: state.Owner,
|
|
244
|
-
name: state.Name,
|
|
245
|
-
ticker: state.Ticker,
|
|
246
|
-
description: state.Description,
|
|
247
|
-
keywords: state.Keywords,
|
|
248
|
-
controllers: state.Controllers,
|
|
249
|
-
records: state.Records,
|
|
250
|
-
balances: state.Balances,
|
|
251
|
-
logo: state.Logo,
|
|
252
|
-
},
|
|
253
|
-
hyperbeamUrl,
|
|
254
|
-
});
|
|
255
|
-
return forkedProcessId;
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* @deprecated
|
|
259
|
-
* Direct Evals are not encouraged when dealing with ANTs.
|
|
260
|
-
* Instead, use spawnANT to fork an ANT to new module source code
|
|
261
|
-
*/
|
|
262
|
-
export async function evolveANT({ signer, processId, luaCodeTxId = ANT_LUA_ID, ao = connect({
|
|
263
|
-
MODE: 'legacy',
|
|
264
|
-
}), logger = Logger.default, arweave = defaultArweave, }) {
|
|
265
|
-
const aosClient = new AOProcess({
|
|
266
|
-
processId,
|
|
267
|
-
ao,
|
|
268
|
-
logger,
|
|
269
|
-
});
|
|
270
|
-
logger.warn('Directly running an Eval on a process is not encouraged.');
|
|
271
|
-
//TODO: cache locally and only fetch if not cached
|
|
272
|
-
// We do not use arweave to get the data because it may throw on l2 tx data
|
|
273
|
-
const { api: { host, port, protocol }, } = arweave.getConfig();
|
|
274
|
-
const luaString = await fetch(`${protocol}://${host}:${port}/${luaCodeTxId}`).then((res) => res.text());
|
|
275
|
-
const { id: evolveMsgId } = await aosClient.send({
|
|
276
|
-
tags: [
|
|
277
|
-
{ name: 'Action', value: 'Eval' },
|
|
278
|
-
{ name: 'App-Name', value: 'ArNS-ANT' },
|
|
279
|
-
{ name: 'Source-Code-TX-ID', value: luaCodeTxId },
|
|
280
|
-
],
|
|
281
|
-
data: luaString,
|
|
282
|
-
signer,
|
|
283
|
-
});
|
|
284
|
-
logger.debug(`Evolved ANT`, {
|
|
285
|
-
processId,
|
|
286
|
-
luaCodeTxId,
|
|
287
|
-
evalMsgId: evolveMsgId,
|
|
288
|
-
});
|
|
289
|
-
return evolveMsgId;
|
|
290
|
-
}
|
|
291
|
-
export function isAoSigner(value) {
|
|
292
|
-
const TagSchema = z.object({
|
|
293
|
-
name: z.string(),
|
|
294
|
-
value: z.union([z.string(), z.number()]),
|
|
295
|
-
});
|
|
296
|
-
const AoSignerSchema = z
|
|
297
|
-
.function()
|
|
298
|
-
.args(z.object({
|
|
299
|
-
data: z.union([z.string(), z.instanceof(Buffer)]),
|
|
300
|
-
tags: z.array(TagSchema).optional(),
|
|
301
|
-
target: z.string().optional(),
|
|
302
|
-
anchor: z.string().optional(),
|
|
303
|
-
}))
|
|
304
|
-
.returns(z.promise(z.object({
|
|
305
|
-
id: z.string(),
|
|
306
|
-
raw: z.instanceof(ArrayBuffer),
|
|
307
|
-
})));
|
|
308
|
-
try {
|
|
309
|
-
AoSignerSchema.parse(value);
|
|
310
|
-
return true;
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
export function createAoSigner(signer) {
|
|
317
|
-
if (isAoSigner(signer)) {
|
|
318
|
-
return signer;
|
|
319
|
-
}
|
|
320
|
-
if (!('publicKey' in signer)) {
|
|
321
|
-
return createDataItemSigner(signer);
|
|
322
|
-
}
|
|
323
|
-
const aoSigner = async ({ data, tags, target, anchor }) => {
|
|
324
|
-
// ensure appropriate permissions are granted with injected signers.
|
|
325
|
-
if (signer.publicKey === undefined &&
|
|
326
|
-
'setPublicKey' in signer &&
|
|
327
|
-
typeof signer.setPublicKey === 'function') {
|
|
328
|
-
await signer.setPublicKey();
|
|
329
|
-
}
|
|
330
|
-
if (signer instanceof ArconnectSigner) {
|
|
331
|
-
// Sign using Arconnect signDataItem API
|
|
332
|
-
const signedDataItem = await signer['signer'].signDataItem({
|
|
333
|
-
data,
|
|
334
|
-
tags,
|
|
335
|
-
target,
|
|
336
|
-
anchor,
|
|
337
|
-
});
|
|
338
|
-
const dataItem = new DataItem(Buffer.from(signedDataItem));
|
|
339
|
-
return {
|
|
340
|
-
id: await dataItem.id,
|
|
341
|
-
raw: await dataItem.getRaw(),
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
const dataItem = createData(data, signer, { tags, target, anchor });
|
|
345
|
-
const signedData = dataItem.sign(signer).then(async () => ({
|
|
346
|
-
id: await dataItem.id,
|
|
347
|
-
raw: await dataItem.getRaw(),
|
|
348
|
-
}));
|
|
349
|
-
return signedData;
|
|
350
|
-
};
|
|
351
|
-
// eslint-disable-next-line
|
|
352
|
-
// @ts-ignore Buffer vs ArrayBuffer type mismatch
|
|
353
|
-
return aoSigner;
|
|
354
|
-
}
|
|
355
|
-
export const defaultTargetManifestId = '-k7t8xMoB8hW482609Z9F4bTFMC3MnuW8bTvTyT8pFI';
|
|
356
|
-
export const defaultANTLogoId = 'Sie_26dvgyok0PZD_-iQAFOhOd5YxDTkczOLoqTTL_A';
|
|
357
|
-
export function initANTStateForAddress({ owner, targetId, ttlSeconds = 3600, keywords = [], controllers = [], description = '', ticker = 'aos', name = 'ANT', logo = defaultANTLogoId, }) {
|
|
358
|
-
return {
|
|
359
|
-
ticker,
|
|
360
|
-
name,
|
|
361
|
-
description,
|
|
362
|
-
keywords,
|
|
363
|
-
owner,
|
|
364
|
-
controllers: [owner, ...controllers],
|
|
365
|
-
balances: { [owner]: 1 },
|
|
366
|
-
records: {
|
|
367
|
-
['@']: {
|
|
368
|
-
transactionId: targetId ?? defaultTargetManifestId.toString(),
|
|
369
|
-
ttlSeconds,
|
|
370
|
-
},
|
|
371
|
-
},
|
|
372
|
-
logo,
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Uses zod schema to parse the epoch data
|
|
377
|
-
*/
|
|
378
|
-
export function parseAoEpochData(value) {
|
|
379
|
-
const epochDataSchema = z.object({
|
|
380
|
-
startTimestamp: z.number(),
|
|
381
|
-
startHeight: z.number(),
|
|
382
|
-
distributions: z.any(), // TODO: add full distributed object type
|
|
383
|
-
endTimestamp: z.number(),
|
|
384
|
-
prescribedObservers: z.any(),
|
|
385
|
-
prescribedNames: z.array(z.string()),
|
|
386
|
-
observations: z.any(),
|
|
387
|
-
epochIndex: z.number(),
|
|
388
|
-
arnsStats: z.any(),
|
|
389
|
-
});
|
|
390
|
-
return epochDataSchema.parse(value);
|
|
391
|
-
}
|
|
392
|
-
export function errorMessageFromOutput(output) {
|
|
393
|
-
const errorData = output.Error;
|
|
394
|
-
// Attempt to extract error details from Messages.Tags if Error is undefined
|
|
395
|
-
const error = errorData ??
|
|
396
|
-
output.Messages?.[0]?.Tags?.find((tag) => tag.name === 'Error')?.value;
|
|
397
|
-
if (error !== undefined) {
|
|
398
|
-
const errorStackTrace = output.Messages?.[0]?.Data;
|
|
399
|
-
const errorMessage = errorStackTrace ?? error;
|
|
400
|
-
// Regex to match AO error messages like: [string ".src.main"]:5111: Primary name data not found
|
|
401
|
-
// or [string "aos"]:128: some error
|
|
402
|
-
const match = errorMessage?.match(/\[string "(.+)"\]:(\d+):\s*(.*)/);
|
|
403
|
-
if (match) {
|
|
404
|
-
// The first group is the src file, the second is the line number, and the third is the error message
|
|
405
|
-
const [, , lineNumber, errorMessage] = match;
|
|
406
|
-
const cleanError = removeUnicodeFromError(errorMessage);
|
|
407
|
-
return `${cleanError.trim()} (line ${lineNumber.trim()})`.trim();
|
|
408
|
-
}
|
|
409
|
-
// With no match, just remove unicode
|
|
410
|
-
return removeUnicodeFromError(error);
|
|
411
|
-
}
|
|
412
|
-
return undefined;
|
|
413
|
-
}
|
|
414
|
-
export function removeUnicodeFromError(error) {
|
|
415
|
-
//The regular expression /[\u001b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g is designed to match ANSI escape codes used for terminal formatting. These are sequences that begin with \u001b (ESC character) and are often followed by [ and control codes.
|
|
416
|
-
const ESC = String.fromCharCode(27); // Represents '\u001b' or '\x1b'
|
|
417
|
-
return error
|
|
418
|
-
.replace(new RegExp(`${ESC}[\\[\\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]`, 'g'), '')
|
|
419
|
-
.trim();
|
|
420
|
-
}
|