@ardrive/turbo-sdk 1.42.0-alpha.5 → 1.42.0-alpha.7
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/lib/cjs/cli/cli.js +5 -0
- package/lib/cjs/cli/commands/arns.js +40 -0
- package/lib/cjs/cli/options.js +18 -1
- package/lib/cjs/common/http.js +16 -2
- package/lib/cjs/common/payment.js +103 -0
- package/lib/cjs/common/signer.js +12 -3
- package/lib/cjs/common/token/index.js +0 -11
- package/lib/cjs/common/turbo.js +23 -0
- package/lib/cjs/common/upload.js +3 -2
- package/lib/cjs/types.js +18 -3
- package/lib/cjs/utils/common.js +0 -4
- package/lib/cjs/utils/errors.js +20 -1
- package/lib/esm/cli/cli.js +7 -2
- package/lib/esm/cli/commands/arns.js +40 -1
- package/lib/esm/cli/options.js +17 -0
- package/lib/esm/common/http.js +15 -1
- package/lib/esm/common/payment.js +105 -2
- package/lib/esm/common/signer.js +13 -4
- package/lib/esm/common/token/index.js +1 -12
- package/lib/esm/common/turbo.js +23 -0
- package/lib/esm/common/upload.js +4 -3
- package/lib/esm/types.js +17 -2
- package/lib/esm/utils/common.js +0 -4
- package/lib/esm/utils/errors.js +18 -0
- package/lib/types/cli/commands/arns.d.ts +11 -2
- package/lib/types/cli/commands/arns.d.ts.map +1 -1
- package/lib/types/cli/options.d.ts +26 -0
- package/lib/types/cli/options.d.ts.map +1 -1
- package/lib/types/cli/types.d.ts +6 -0
- package/lib/types/cli/types.d.ts.map +1 -1
- package/lib/types/common/http.d.ts +12 -0
- package/lib/types/common/http.d.ts.map +1 -1
- package/lib/types/common/payment.d.ts +32 -1
- package/lib/types/common/payment.d.ts.map +1 -1
- package/lib/types/common/signer.d.ts +10 -0
- package/lib/types/common/signer.d.ts.map +1 -1
- package/lib/types/common/token/index.d.ts.map +1 -1
- package/lib/types/common/turbo.d.ts +20 -1
- package/lib/types/common/turbo.d.ts.map +1 -1
- package/lib/types/common/upload.d.ts.map +1 -1
- package/lib/types/types.d.ts +110 -1
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/utils/common.d.ts.map +1 -1
- package/lib/types/utils/errors.d.ts +15 -0
- package/lib/types/utils/errors.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/cjs/cli/cli.js
CHANGED
|
@@ -102,6 +102,11 @@ const utils_js_1 = require("./utils.js");
|
|
|
102
102
|
.description('Get the Turbo Credit (winc + mARIO) price to buy, extend, increase undernames, or upgrade an ArNS name'), options_js_1.arnsPriceOptions).action(async (_commandOptions, command) => {
|
|
103
103
|
await (0, utils_js_1.runCommand)(command, arns_js_1.arnsPrice);
|
|
104
104
|
});
|
|
105
|
+
(0, utils_js_1.applyOptions)(commander_1.program
|
|
106
|
+
.command('arns-fiat-quote')
|
|
107
|
+
.description('Quote an ArNS purchase paid by credit card (Stripe) - no credits needed'), options_js_1.arnsFiatQuoteOptions).action(async (_commandOptions, command) => {
|
|
108
|
+
await (0, utils_js_1.runCommand)(command, arns_js_1.arnsFiatQuote);
|
|
109
|
+
});
|
|
105
110
|
(0, utils_js_1.applyOptions)(commander_1.program
|
|
106
111
|
.command('buy-arns-name')
|
|
107
112
|
.description('Buy an ArNS name (lease or permabuy) with Turbo Credits'), options_js_1.buyArNSNameOptions).action(async (_commandOptions, command) => {
|
|
@@ -6,6 +6,7 @@ exports.typeFromOptions = typeFromOptions;
|
|
|
6
6
|
exports.paidByFromArNSOptions = paidByFromArNSOptions;
|
|
7
7
|
exports.arnsPriceParamsFromOptions = arnsPriceParamsFromOptions;
|
|
8
8
|
exports.arnsPrice = arnsPrice;
|
|
9
|
+
exports.arnsFiatQuote = arnsFiatQuote;
|
|
9
10
|
exports.buyArNSName = buyArNSName;
|
|
10
11
|
exports.extendArNSLease = extendArNSLease;
|
|
11
12
|
exports.increaseArNSUndernames = increaseArNSUndernames;
|
|
@@ -146,6 +147,45 @@ async function arnsPrice(options, turbo) {
|
|
|
146
147
|
mARIO,
|
|
147
148
|
}, null, 2));
|
|
148
149
|
}
|
|
150
|
+
async function arnsFiatQuote(options, turbo) {
|
|
151
|
+
const params = arnsPriceParamsFromOptions(options);
|
|
152
|
+
const address = options.address;
|
|
153
|
+
if (address === undefined) {
|
|
154
|
+
throw new Error('A destination --address is required for a fiat ArNS quote.');
|
|
155
|
+
}
|
|
156
|
+
const client = turbo ?? factory_js_1.TurboFactory.unauthenticated((0, utils_js_1.configFromOptions)(options));
|
|
157
|
+
try {
|
|
158
|
+
const { purchaseQuote, paymentSession, adjustments, fees } = await client.getArNSFiatPurchaseQuote({
|
|
159
|
+
...params,
|
|
160
|
+
address,
|
|
161
|
+
currency: (options.currency ?? 'usd'),
|
|
162
|
+
method: options.method,
|
|
163
|
+
promoCodes: options.promoCode,
|
|
164
|
+
});
|
|
165
|
+
console.log(JSON.stringify({
|
|
166
|
+
name: purchaseQuote.name,
|
|
167
|
+
intent: purchaseQuote.intent,
|
|
168
|
+
nonce: purchaseQuote.nonce,
|
|
169
|
+
paymentAmount: purchaseQuote.paymentAmount,
|
|
170
|
+
currency: purchaseQuote.currencyType,
|
|
171
|
+
quoteExpirationDate: purchaseQuote.quoteExpirationDate,
|
|
172
|
+
paymentSessionId: paymentSession.id,
|
|
173
|
+
// Present for a payment intent / embedded checkout; a hosted
|
|
174
|
+
// checkout session returns `url` instead.
|
|
175
|
+
clientSecret: paymentSession.client_secret ?? undefined,
|
|
176
|
+
checkoutUrl: paymentSession.url ?? undefined,
|
|
177
|
+
adjustments,
|
|
178
|
+
fees,
|
|
179
|
+
}, null, 2));
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (error instanceof errors_js_1.FiatPaymentsDisabledError) {
|
|
183
|
+
console.error('Fiat (Stripe) payments are disabled on this payment service. Use the credit-paid commands (buy-arns-name, extend-arns-lease, ...) instead.');
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
149
189
|
async function buyArNSName(options, turbo) {
|
|
150
190
|
const name = requiredNameFromOptions(options);
|
|
151
191
|
const type = typeFromOptions(options.type);
|
package/lib/cjs/cli/options.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.removeArNSRecordOptions = exports.setArNSRecordOptions = exports.transferArNSAntOptions = exports.arnsPurchaseStatusOptions = exports.upgradeArNSNameOptions = exports.increaseArNSUndernamesOptions = exports.extendArNSLeaseOptions = exports.buyArNSNameOptions = exports.arnsPriceOptions = exports.listSharesOptions = exports.revokeCreditsOptions = exports.shareCreditsOptions = exports.uploadFileOptions = exports.uploadFolderOptions = exports.uploadOptions = exports.globalOptions = exports.walletOptions = exports.optionMap = void 0;
|
|
18
|
+
exports.removeArNSRecordOptions = exports.setArNSRecordOptions = exports.transferArNSAntOptions = exports.arnsPurchaseStatusOptions = exports.upgradeArNSNameOptions = exports.increaseArNSUndernamesOptions = exports.extendArNSLeaseOptions = exports.buyArNSNameOptions = exports.arnsFiatQuoteOptions = exports.arnsPriceOptions = exports.listSharesOptions = exports.revokeCreditsOptions = exports.shareCreditsOptions = exports.uploadFileOptions = exports.uploadFolderOptions = exports.uploadOptions = exports.globalOptions = exports.walletOptions = exports.optionMap = void 0;
|
|
19
19
|
exports.optionMap = {
|
|
20
20
|
token: {
|
|
21
21
|
alias: '-t, --token <type>',
|
|
@@ -304,6 +304,23 @@ exports.arnsPriceOptions = [
|
|
|
304
304
|
exports.optionMap.arnsIncreaseQty,
|
|
305
305
|
exports.optionMap.arnsProcessId,
|
|
306
306
|
];
|
|
307
|
+
exports.arnsFiatQuoteOptions = [
|
|
308
|
+
exports.optionMap.arnsName,
|
|
309
|
+
exports.optionMap.arnsType,
|
|
310
|
+
exports.optionMap.arnsYears,
|
|
311
|
+
exports.optionMap.arnsIncreaseQty,
|
|
312
|
+
exports.optionMap.arnsProcessId,
|
|
313
|
+
exports.optionMap.address,
|
|
314
|
+
exports.optionMap.currency,
|
|
315
|
+
{
|
|
316
|
+
alias: '--method <method>',
|
|
317
|
+
description: 'Stripe integration mode: payment-intent (default) or checkout-session',
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
alias: '--promo-code <promoCode...>',
|
|
321
|
+
description: 'Promo code(s) to apply to the fiat price',
|
|
322
|
+
},
|
|
323
|
+
];
|
|
307
324
|
exports.buyArNSNameOptions = [
|
|
308
325
|
...exports.walletOptions,
|
|
309
326
|
exports.optionMap.arnsName,
|
package/lib/cjs/common/http.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TurboHTTPService = exports.defaultRetryConfig = void 0;
|
|
3
|
+
exports.TurboHTTPService = exports.x402UploadEndpoints = exports.defaultRetryConfig = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
6
6
|
*
|
|
@@ -34,6 +34,18 @@ const defaultHeaders = {
|
|
|
34
34
|
'x-turbo-source-version': version_js_1.version,
|
|
35
35
|
'x-turbo-source-identifier': 'turbo-sdk',
|
|
36
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Canonical x402 upload routes on the upload service.
|
|
39
|
+
*
|
|
40
|
+
* These were previously `/x402/data-item/{signed,unsigned}`. The service
|
|
41
|
+
* renamed them to `/x402/upload/*` and kept a `data-item/signed` alias, but not
|
|
42
|
+
* a `data-item/unsigned` one — so every unsigned x402 upload 404ed. Both
|
|
43
|
+
* canonical paths are served by all released upload-service versions.
|
|
44
|
+
*/
|
|
45
|
+
exports.x402UploadEndpoints = {
|
|
46
|
+
signed: '/x402/upload/signed',
|
|
47
|
+
unsigned: '/x402/upload/unsigned',
|
|
48
|
+
};
|
|
37
49
|
class TurboHTTPService {
|
|
38
50
|
constructor({ url, logger, retryConfig = (0, exports.defaultRetryConfig)(logger), }) {
|
|
39
51
|
this.logger = logger;
|
|
@@ -124,7 +136,9 @@ class TurboHTTPService {
|
|
|
124
136
|
throw new errors_js_1.FailedRequestError('Max retries reached - ' + lastError?.message, lastError?.status);
|
|
125
137
|
}
|
|
126
138
|
async x402Post({ signal, allowedStatuses, headers, data, x402Options, }) {
|
|
127
|
-
const endpoint =
|
|
139
|
+
const endpoint = x402Options.unsignedData
|
|
140
|
+
? exports.x402UploadEndpoints.unsigned
|
|
141
|
+
: exports.x402UploadEndpoints.signed;
|
|
128
142
|
this.logger.debug('Using X402 options for POST request', {
|
|
129
143
|
endpoint,
|
|
130
144
|
x402Options,
|
|
@@ -190,6 +190,95 @@ class TurboUnauthenticatedPaymentService {
|
|
|
190
190
|
const query = params.toString();
|
|
191
191
|
return query.length > 0 ? `?${query}` : '';
|
|
192
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Quote a fiat (Stripe) ArNS purchase — buy a name with a credit card in one
|
|
195
|
+
* step, with no Turbo Credits top-up in between.
|
|
196
|
+
*
|
|
197
|
+
* Returns the recorded `purchaseQuote` (its `nonce` is what
|
|
198
|
+
* `getArNSPurchaseStatus` polls) plus the Stripe `paymentSession` to complete
|
|
199
|
+
* payment with. For `payment-intent`, confirm client-side with
|
|
200
|
+
* `stripe.confirmCardPayment(paymentSession.client_secret, ...)`, then poll
|
|
201
|
+
* the nonce until the purchase reports success or failure.
|
|
202
|
+
*
|
|
203
|
+
* Throws {@link FiatPaymentsDisabledError} when the service has Stripe turned
|
|
204
|
+
* off (normal in the testnet sandbox) so callers can fall back to the
|
|
205
|
+
* credit-paid path without string-matching a generic 503.
|
|
206
|
+
*/
|
|
207
|
+
async getArNSFiatPurchaseQuote(params) {
|
|
208
|
+
this.validateArNSPurchaseParams(params);
|
|
209
|
+
const { address, currency, method = 'payment-intent', promoCodes = [], } = params;
|
|
210
|
+
if (typeof address !== 'string' || address.length === 0) {
|
|
211
|
+
throw new errors_js_1.ProvidedInputError('A destination `address` is required for a fiat ArNS purchase quote.');
|
|
212
|
+
}
|
|
213
|
+
if (!(0, types_js_1.isCurrency)(currency)) {
|
|
214
|
+
throw new errors_js_1.ProvidedInputError(`Invalid currency '${currency}'. Supported: ${types_js_1.fiatCurrencyTypes.join(', ')}`);
|
|
215
|
+
}
|
|
216
|
+
// Every interpolated segment is encoded. Five user-controlled values land in
|
|
217
|
+
// the path here, and an unencoded one (e.g. a name or address containing
|
|
218
|
+
// `../`) would silently retarget the request at another route.
|
|
219
|
+
const segments = [
|
|
220
|
+
method,
|
|
221
|
+
address,
|
|
222
|
+
currency,
|
|
223
|
+
params.intent,
|
|
224
|
+
params.name,
|
|
225
|
+
].map((segment) => encodeURIComponent(segment));
|
|
226
|
+
const query = this.buildArNSFiatQuoteQuery(params, promoCodes);
|
|
227
|
+
try {
|
|
228
|
+
return await this.httpService.get({
|
|
229
|
+
endpoint: `/arns/quote/${segments.join('/')}${query}`,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
// The service returns 503 both for "Stripe is disabled" and for internal
|
|
234
|
+
// errors, so the body is what disambiguates them.
|
|
235
|
+
if (error instanceof errors_js_1.FailedRequestError &&
|
|
236
|
+
error.status === 503 &&
|
|
237
|
+
/Fiat \(Stripe\).*disabled/i.test(error.message)) {
|
|
238
|
+
throw new errors_js_1.FiatPaymentsDisabledError(error.message);
|
|
239
|
+
}
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Query string for a fiat quote. Distinct from `buildArNSPurchaseQuery`
|
|
245
|
+
* because this route takes `uiMode` + its paired URLs and has no `paidBy`
|
|
246
|
+
* (fiat has no delegated payer), and because promo codes must be REPEATED
|
|
247
|
+
* params here: the service reads them with `parseQueryParams`, which treats a
|
|
248
|
+
* comma-joined string as one code rather than several.
|
|
249
|
+
*/
|
|
250
|
+
buildArNSFiatQuoteQuery(params, promoCodes) {
|
|
251
|
+
const { type, years, increaseQty, processId } = params;
|
|
252
|
+
const search = new URLSearchParams();
|
|
253
|
+
if (type !== undefined)
|
|
254
|
+
search.set('type', type);
|
|
255
|
+
if (years !== undefined)
|
|
256
|
+
search.set('years', `${years}`);
|
|
257
|
+
if (increaseQty !== undefined)
|
|
258
|
+
search.set('increaseQty', `${increaseQty}`);
|
|
259
|
+
if (processId !== undefined)
|
|
260
|
+
search.set('processId', processId);
|
|
261
|
+
const uiMode = params.uiMode;
|
|
262
|
+
if (uiMode !== undefined)
|
|
263
|
+
search.set('uiMode', uiMode);
|
|
264
|
+
if (uiMode === 'embedded') {
|
|
265
|
+
const { returnUrl } = params;
|
|
266
|
+
if (returnUrl !== undefined)
|
|
267
|
+
search.set('returnUrl', returnUrl);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
const { successUrl, cancelUrl } = params;
|
|
271
|
+
if (successUrl !== undefined)
|
|
272
|
+
search.set('successUrl', successUrl);
|
|
273
|
+
if (cancelUrl !== undefined)
|
|
274
|
+
search.set('cancelUrl', cancelUrl);
|
|
275
|
+
}
|
|
276
|
+
for (const code of promoCodes) {
|
|
277
|
+
search.append('promoCode', code);
|
|
278
|
+
}
|
|
279
|
+
const query = search.toString();
|
|
280
|
+
return query.length > 0 ? `?${query}` : '';
|
|
281
|
+
}
|
|
193
282
|
appendPromoCodesToQuery(promoCodes) {
|
|
194
283
|
const promoCodesQuery = promoCodes.join(',');
|
|
195
284
|
return promoCodesQuery ? `promoCode=${promoCodesQuery}` : '';
|
|
@@ -355,6 +444,20 @@ class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymentServic
|
|
|
355
444
|
userAddress ??= await this.signer.getNativeAddress();
|
|
356
445
|
return super.getBalance(userAddress);
|
|
357
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* Quote a fiat (Stripe) ArNS purchase. `address` defaults to this signer's
|
|
449
|
+
* native address — the wallet that will own the name — so the common case
|
|
450
|
+
* needs no address at all. Pass one explicitly to buy on another wallet's
|
|
451
|
+
* behalf; the route takes the destination as a path param and requires no
|
|
452
|
+
* signature, which is why it is available unauthenticated too.
|
|
453
|
+
*/
|
|
454
|
+
async getArNSFiatPurchaseQuote(params) {
|
|
455
|
+
const address = params.address ?? (await this.signer.getNativeAddress());
|
|
456
|
+
return super.getArNSFiatPurchaseQuote({
|
|
457
|
+
...params,
|
|
458
|
+
address,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
358
461
|
async getFreeStatus(userAddress) {
|
|
359
462
|
userAddress ??= await this.signer.getNativeAddress();
|
|
360
463
|
return super.getFreeStatus(userAddress);
|
package/lib/cjs/common/signer.js
CHANGED
|
@@ -60,7 +60,6 @@ class TurboDataItemAbstractSigner {
|
|
|
60
60
|
case 'base-eth':
|
|
61
61
|
case 'usdc':
|
|
62
62
|
case 'base-usdc':
|
|
63
|
-
case 'base-ario':
|
|
64
63
|
case 'polygon-usdc':
|
|
65
64
|
return (0, ethers_2.computeAddress)((0, signing_key_1.computePublicKey)((0, base64_js_1.fromB64Url)(owner)));
|
|
66
65
|
case 'kyve':
|
|
@@ -172,13 +171,23 @@ class TurboDataItemAbstractSigner {
|
|
|
172
171
|
}
|
|
173
172
|
}
|
|
174
173
|
exports.TurboDataItemAbstractSigner = TurboDataItemAbstractSigner;
|
|
174
|
+
/**
|
|
175
|
+
* Builds the wallet client x402-fetch signs payment authorizations with.
|
|
176
|
+
*
|
|
177
|
+
* The chain matters because `wrapFetchWithPayment` maps `walletClient.chain.id`
|
|
178
|
+
* to a network name and prefers the matching entry in the service's `accepts`
|
|
179
|
+
* list. The upload service advertises Base mainnet (`base`), and x402 support
|
|
180
|
+
* here is limited to `base-usdc`, so mainnet is the correct default. Callers
|
|
181
|
+
* needing another network can supply their own signer via
|
|
182
|
+
* `X402Funding({ signer })`.
|
|
183
|
+
*/
|
|
175
184
|
async function makeX402Signer(arbundlesSigner) {
|
|
176
185
|
// Node: our SDK uses EthereumSigner with a raw private key
|
|
177
186
|
if (arbundlesSigner instanceof arbundles_1.EthereumSigner) {
|
|
178
187
|
return (0, viem_1.createWalletClient)({
|
|
179
188
|
account: (0, accounts_1.privateKeyToAccount)(('0x' +
|
|
180
189
|
Buffer.from(arbundlesSigner.key).toString('hex'))),
|
|
181
|
-
chain: chains_1.
|
|
190
|
+
chain: chains_1.base,
|
|
182
191
|
transport: (0, viem_1.http)(),
|
|
183
192
|
});
|
|
184
193
|
}
|
|
@@ -197,7 +206,7 @@ async function makeX402Signer(arbundlesSigner) {
|
|
|
197
206
|
const account = accounts[0];
|
|
198
207
|
return (0, viem_1.createWalletClient)({
|
|
199
208
|
account,
|
|
200
|
-
chain: chains_1.
|
|
209
|
+
chain: chains_1.base,
|
|
201
210
|
transport: (0, viem_1.custom)(provider),
|
|
202
211
|
});
|
|
203
212
|
}
|
|
@@ -17,17 +17,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.tokenToBaseMap = exports.exponentMap = exports.defaultTokenMap = void 0;
|
|
18
18
|
exports.isTokenType = isTokenType;
|
|
19
19
|
const types_js_1 = require("../../types.js");
|
|
20
|
-
const common_js_1 = require("../../utils/common.js");
|
|
21
20
|
const ario_js_1 = require("./ario.js");
|
|
22
21
|
const arweave_js_1 = require("./arweave.js");
|
|
23
22
|
const baseEth_js_1 = require("./baseEth.js");
|
|
24
|
-
const erc20_js_1 = require("./erc20.js");
|
|
25
23
|
const ethereum_js_1 = require("./ethereum.js");
|
|
26
24
|
const kyve_js_1 = require("./kyve.js");
|
|
27
25
|
const polygon_js_1 = require("./polygon.js");
|
|
28
26
|
const solana_js_1 = require("./solana.js");
|
|
29
27
|
const usdc_js_1 = require("./usdc.js");
|
|
30
|
-
const baseARIOContractAddress = '0x138746adfA52909E5920def027f5a8dc1C7EfFb6';
|
|
31
28
|
exports.defaultTokenMap = {
|
|
32
29
|
arweave: (config) => new arweave_js_1.ArweaveToken(config),
|
|
33
30
|
ario: (config) => new ario_js_1.ARIOToken(config),
|
|
@@ -40,12 +37,6 @@ exports.defaultTokenMap = {
|
|
|
40
37
|
usdc: (config) => new usdc_js_1.USDCToken({ network: 'ethereum', ...config }),
|
|
41
38
|
'base-usdc': (config) => new usdc_js_1.USDCToken({ network: 'base', ...config }),
|
|
42
39
|
'polygon-usdc': (config) => new usdc_js_1.USDCToken({ network: 'polygon', ...config }),
|
|
43
|
-
'base-ario': (config) => new erc20_js_1.ERC20Token({
|
|
44
|
-
...config,
|
|
45
|
-
pollingOptions: config.pollingOptions ?? baseEth_js_1.defaultBaseNetworkPollingOptions,
|
|
46
|
-
tokenContractAddress: baseARIOContractAddress,
|
|
47
|
-
gatewayUrl: config.gatewayUrl ?? common_js_1.defaultProdGatewayUrls['base-ario'],
|
|
48
|
-
}),
|
|
49
40
|
};
|
|
50
41
|
const ethExponent = 18;
|
|
51
42
|
const usdcExponent = 6;
|
|
@@ -53,7 +44,6 @@ const arioExponent = 6;
|
|
|
53
44
|
exports.exponentMap = {
|
|
54
45
|
arweave: 12,
|
|
55
46
|
ario: arioExponent,
|
|
56
|
-
'base-ario': arioExponent,
|
|
57
47
|
solana: 9,
|
|
58
48
|
ethereum: ethExponent,
|
|
59
49
|
'base-eth': ethExponent,
|
|
@@ -67,7 +57,6 @@ exports.exponentMap = {
|
|
|
67
57
|
exports.tokenToBaseMap = {
|
|
68
58
|
arweave: (a) => (0, arweave_js_1.ARToTokenAmount)(a),
|
|
69
59
|
ario: (a) => (0, ario_js_1.ARIOToTokenAmount)(a),
|
|
70
|
-
'base-ario': (a) => (0, usdc_js_1.USDCToTokenAmount)(a),
|
|
71
60
|
solana: (a) => (0, solana_js_1.SOLToTokenAmount)(a),
|
|
72
61
|
ethereum: (a) => (0, ethereum_js_1.ETHToTokenAmount)(a),
|
|
73
62
|
'base-eth': (a) => (0, ethereum_js_1.ETHToTokenAmount)(a),
|
package/lib/cjs/common/turbo.js
CHANGED
|
@@ -69,6 +69,17 @@ class TurboUnauthenticatedClient {
|
|
|
69
69
|
getArNSPurchaseStatus(p) {
|
|
70
70
|
return this.paymentService.getArNSPurchaseStatus(p);
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Quote a fiat (Stripe) ArNS purchase — buy a name with a credit card in one
|
|
74
|
+
* step, no Turbo Credits top-up in between. Complete the returned
|
|
75
|
+
* `paymentSession` with Stripe, then poll {@link getArNSPurchaseStatus} using
|
|
76
|
+
* `purchaseQuote.nonce`.
|
|
77
|
+
*
|
|
78
|
+
* Throws `FiatPaymentsDisabledError` when the service has Stripe switched off.
|
|
79
|
+
*/
|
|
80
|
+
getArNSFiatPurchaseQuote(params) {
|
|
81
|
+
return this.paymentService.getArNSFiatPurchaseQuote(params);
|
|
82
|
+
}
|
|
72
83
|
/**
|
|
73
84
|
* Returns a list of all supported fiat currencies.
|
|
74
85
|
*/
|
|
@@ -201,6 +212,18 @@ class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
|
|
|
201
212
|
buyArNSName(params) {
|
|
202
213
|
return this.paymentService.buyArNSName(params);
|
|
203
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Quote a fiat (Stripe) ArNS purchase for this signer's wallet — a credit-card
|
|
217
|
+
* buy in one step, with no Turbo Credits top-up in between. `address` defaults
|
|
218
|
+
* to the signer's native address; pass one to buy on another wallet's behalf.
|
|
219
|
+
*
|
|
220
|
+
* Complete the returned `paymentSession` with Stripe, then poll
|
|
221
|
+
* {@link getArNSPurchaseStatus} using `purchaseQuote.nonce`. Throws
|
|
222
|
+
* `FiatPaymentsDisabledError` when the service has Stripe switched off.
|
|
223
|
+
*/
|
|
224
|
+
getArNSFiatPurchaseQuote(params) {
|
|
225
|
+
return this.paymentService.getArNSFiatPurchaseQuote(params);
|
|
226
|
+
}
|
|
204
227
|
/** Extends the lease on an existing ArNS name. */
|
|
205
228
|
extendArNSLease(params) {
|
|
206
229
|
return this.paymentService.extendArNSLease(params);
|
package/lib/cjs/common/upload.js
CHANGED
|
@@ -123,7 +123,9 @@ class TurboUnauthenticatedUploadService {
|
|
|
123
123
|
};
|
|
124
124
|
return this.httpService.post({
|
|
125
125
|
data: dataBuffer,
|
|
126
|
-
|
|
126
|
+
// Only reached when no signer was supplied; the x402 path recomputes this
|
|
127
|
+
// from `unsignedData`. Both must name the same route.
|
|
128
|
+
endpoint: http_js_2.x402UploadEndpoints.unsigned,
|
|
127
129
|
signal,
|
|
128
130
|
headers: tags !== undefined
|
|
129
131
|
? { 'x-data-item-tags': JSON.stringify(tags) }
|
|
@@ -142,7 +144,6 @@ class TurboAuthenticatedBaseUploadService extends TurboUnauthenticatedUploadServ
|
|
|
142
144
|
'solana',
|
|
143
145
|
'base-eth',
|
|
144
146
|
'base-usdc',
|
|
145
|
-
'base-ario',
|
|
146
147
|
];
|
|
147
148
|
this.signer = signer;
|
|
148
149
|
this.paymentService = paymentService;
|
package/lib/cjs/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.arNSPurchaseIntents = exports.validChunkingModes = exports.isJWK = exports.isWebUploadFolderParams = exports.isNodeUploadFolderParams = exports.multipartFinalizedStatus = exports.multipartFailedStatus = exports.multipartPendingStatus = exports.X402Funding = exports.OnDemandFunding = exports.ExistingBalanceFunding = exports.supportedEvmSignerTokens = exports.tokenTypes = exports.fiatCurrencyTypes = void 0;
|
|
3
|
+
exports.arNSFiatPurchaseMethods = exports.arNSPurchaseIntents = exports.validChunkingModes = exports.isJWK = exports.isWebUploadFolderParams = exports.isNodeUploadFolderParams = exports.multipartFinalizedStatus = exports.multipartFailedStatus = exports.multipartPendingStatus = exports.X402Funding = exports.OnDemandFunding = exports.ExistingBalanceFunding = exports.supportedEvmSignerTokens = exports.tokenTypes = exports.fiatCurrencyTypes = void 0;
|
|
4
4
|
exports.isCurrency = isCurrency;
|
|
5
5
|
exports.isKyvePrivateKey = isKyvePrivateKey;
|
|
6
6
|
exports.isEthPrivateKey = isEthPrivateKey;
|
|
@@ -25,7 +25,6 @@ function isCurrency(currency) {
|
|
|
25
25
|
exports.tokenTypes = [
|
|
26
26
|
'arweave',
|
|
27
27
|
'ario',
|
|
28
|
-
'base-ario',
|
|
29
28
|
'solana',
|
|
30
29
|
'ethereum',
|
|
31
30
|
'kyve',
|
|
@@ -44,7 +43,6 @@ exports.supportedEvmSignerTokens = new Set([
|
|
|
44
43
|
'polygon-usdc',
|
|
45
44
|
'usdc',
|
|
46
45
|
'base-usdc',
|
|
47
|
-
'base-ario',
|
|
48
46
|
]);
|
|
49
47
|
class ExistingBalanceFunding {
|
|
50
48
|
}
|
|
@@ -115,3 +113,20 @@ exports.arNSPurchaseIntents = [
|
|
|
115
113
|
'Increase-Undername-Limit',
|
|
116
114
|
'Upgrade-Name',
|
|
117
115
|
];
|
|
116
|
+
// ===== ArNS purchases paid with fiat (Stripe) — no Turbo Credits in between ====
|
|
117
|
+
/**
|
|
118
|
+
* Stripe integration mode for a fiat ArNS purchase quote.
|
|
119
|
+
*
|
|
120
|
+
* - `payment-intent` — returns a Stripe PaymentIntent. Confirm it client-side
|
|
121
|
+
* with `stripe.confirmCardPayment(paymentSession.client_secret, ...)`.
|
|
122
|
+
* - `checkout-session` — returns a Stripe Checkout Session to redirect to
|
|
123
|
+
* (`uiMode: 'hosted'`) or embed (`uiMode: 'embedded'`).
|
|
124
|
+
*
|
|
125
|
+
* Widened with `string & Record<never, never>` so a method added service-side is
|
|
126
|
+
* still callable without an SDK bump, while the known values keep autocomplete.
|
|
127
|
+
* (`string & {}` is the usual idiom but trips the `ban-types` lint rule.)
|
|
128
|
+
*/
|
|
129
|
+
exports.arNSFiatPurchaseMethods = [
|
|
130
|
+
'payment-intent',
|
|
131
|
+
'checkout-session',
|
|
132
|
+
];
|
package/lib/cjs/utils/common.js
CHANGED
|
@@ -50,7 +50,6 @@ const baseMainnetRpc = 'https://mainnet.base.org';
|
|
|
50
50
|
exports.tokenToDevGatewayMap = {
|
|
51
51
|
arweave: 'https://turbo-gateway.com', // No arweave test net
|
|
52
52
|
ario: 'https://api.devnet.solana.com',
|
|
53
|
-
'base-ario': baseMainnetRpc, // No base-ario test net contract deployed
|
|
54
53
|
solana: 'https://api.devnet.solana.com',
|
|
55
54
|
ethereum: ethTestnetRpc,
|
|
56
55
|
'base-eth': baseTestnetRpc,
|
|
@@ -64,7 +63,6 @@ exports.tokenToDevGatewayMap = {
|
|
|
64
63
|
exports.defaultProdGatewayUrls = {
|
|
65
64
|
arweave: 'https://turbo-gateway.com',
|
|
66
65
|
ario: 'https://api.mainnet-beta.solana.com',
|
|
67
|
-
'base-ario': baseMainnetRpc,
|
|
68
66
|
solana: 'https://api.mainnet-beta.solana.com',
|
|
69
67
|
ethereum: 'https://cloudflare-eth.com/',
|
|
70
68
|
'base-eth': baseMainnetRpc,
|
|
@@ -102,7 +100,6 @@ function createTurboSigner({ signer: clientProvidedSigner, privateKey: clientPro
|
|
|
102
100
|
case 'base-eth':
|
|
103
101
|
case 'usdc':
|
|
104
102
|
case 'base-usdc':
|
|
105
|
-
case 'base-ario':
|
|
106
103
|
case 'polygon-usdc':
|
|
107
104
|
if (!(0, types_js_1.isEthPrivateKey)(clientProvidedPrivateKey)) {
|
|
108
105
|
throw new Error('A valid Ethereum private key must be provided for EthereumSigner.');
|
|
@@ -167,7 +164,6 @@ function isValidUserAddress(address, type) {
|
|
|
167
164
|
case 'matic':
|
|
168
165
|
case 'pol':
|
|
169
166
|
case 'base-usdc':
|
|
170
|
-
case 'base-ario':
|
|
171
167
|
case 'usdc':
|
|
172
168
|
case 'polygon-usdc':
|
|
173
169
|
return isValidECDSAAddress(address);
|
package/lib/cjs/utils/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AbortError = exports.InsufficientCreditsError = exports.ProvidedInputError = exports.FailedRequestError = exports.UnauthenticatedRequestError = exports.BaseError = void 0;
|
|
3
|
+
exports.AbortError = exports.FiatPaymentsDisabledError = exports.InsufficientCreditsError = exports.ProvidedInputError = exports.FailedRequestError = exports.UnauthenticatedRequestError = exports.BaseError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
6
6
|
*
|
|
@@ -60,6 +60,25 @@ class InsufficientCreditsError extends BaseError {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
exports.InsufficientCreditsError = InsufficientCreditsError;
|
|
63
|
+
/**
|
|
64
|
+
* Raised when the payment service has fiat (Stripe) payments switched off, which
|
|
65
|
+
* it signals with `503` and the body "Fiat (Stripe) ArNS payments are disabled".
|
|
66
|
+
* This is a normal state in the testnet sandbox, not an outage.
|
|
67
|
+
*
|
|
68
|
+
* Distinguished from a generic `503` deliberately: the same status is also used
|
|
69
|
+
* for internal errors (body "Internal Server Error: ..."), so status alone is
|
|
70
|
+
* ambiguous. Recovery: fall back to the credit-paid path (`buyArNSName` and
|
|
71
|
+
* friends), or surface fiat checkout as unavailable.
|
|
72
|
+
*/
|
|
73
|
+
class FiatPaymentsDisabledError extends BaseError {
|
|
74
|
+
constructor(message) {
|
|
75
|
+
super(message ??
|
|
76
|
+
'Fiat (Stripe) payments are disabled on this payment service. Use the credit-paid purchase path instead.');
|
|
77
|
+
/** Always the HTTP status that produced this error. */
|
|
78
|
+
this.status = 503;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.FiatPaymentsDisabledError = FiatPaymentsDisabledError;
|
|
63
82
|
class AbortError extends BaseError {
|
|
64
83
|
constructor(message = 'Request was aborted') {
|
|
65
84
|
super(message);
|
package/lib/esm/cli/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import { DataItem } from '@dha-team/arbundles';
|
|
|
20
20
|
import { program } from 'commander';
|
|
21
21
|
import { readFileSync, readdirSync } from 'fs';
|
|
22
22
|
import { version } from '../version.js';
|
|
23
|
-
import { arnsPrice, arnsPurchaseStatus, buyArNSName, extendArNSLease, increaseArNSUndernames, removeArNSRecord, setArNSRecord, transferArNSAnt, upgradeArNSName, } from './commands/arns.js';
|
|
23
|
+
import { arnsFiatQuote, arnsPrice, arnsPurchaseStatus, buyArNSName, extendArNSLease, increaseArNSUndernames, removeArNSRecord, setArNSRecord, transferArNSAnt, upgradeArNSName, } from './commands/arns.js';
|
|
24
24
|
import { fiatEstimate } from './commands/fiatEstimate.js';
|
|
25
25
|
import { balance, cryptoFund, freeStatus, paymentHistory, price, topUp, uploadFile, uploadFolder, } from './commands/index.js';
|
|
26
26
|
import { listShares } from './commands/listShares.js';
|
|
@@ -28,7 +28,7 @@ import { revokeCredits } from './commands/revokeCredits.js';
|
|
|
28
28
|
import { shareCredits } from './commands/shareCredits.js';
|
|
29
29
|
import { tokenPrice } from './commands/tokenPrice.js';
|
|
30
30
|
import { x402UploadUnsignedFile } from './commands/x402UploadUnsignedData.js';
|
|
31
|
-
import { arnsPriceOptions, arnsPurchaseStatusOptions, buyArNSNameOptions, extendArNSLeaseOptions, globalOptions, increaseArNSUndernamesOptions, listSharesOptions, optionMap, removeArNSRecordOptions, revokeCreditsOptions, setArNSRecordOptions, shareCreditsOptions, transferArNSAntOptions, upgradeArNSNameOptions, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
|
|
31
|
+
import { arnsFiatQuoteOptions, arnsPriceOptions, arnsPurchaseStatusOptions, buyArNSNameOptions, extendArNSLeaseOptions, globalOptions, increaseArNSUndernamesOptions, listSharesOptions, optionMap, removeArNSRecordOptions, revokeCreditsOptions, setArNSRecordOptions, shareCreditsOptions, transferArNSAntOptions, upgradeArNSNameOptions, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
|
|
32
32
|
import { applyOptions, runCommand } from './utils.js';
|
|
33
33
|
applyOptions(program
|
|
34
34
|
.name('turbo')
|
|
@@ -100,6 +100,11 @@ applyOptions(program
|
|
|
100
100
|
.description('Get the Turbo Credit (winc + mARIO) price to buy, extend, increase undernames, or upgrade an ArNS name'), arnsPriceOptions).action(async (_commandOptions, command) => {
|
|
101
101
|
await runCommand(command, arnsPrice);
|
|
102
102
|
});
|
|
103
|
+
applyOptions(program
|
|
104
|
+
.command('arns-fiat-quote')
|
|
105
|
+
.description('Quote an ArNS purchase paid by credit card (Stripe) - no credits needed'), arnsFiatQuoteOptions).action(async (_commandOptions, command) => {
|
|
106
|
+
await runCommand(command, arnsFiatQuote);
|
|
107
|
+
});
|
|
103
108
|
applyOptions(program
|
|
104
109
|
.command('buy-arns-name')
|
|
105
110
|
.description('Buy an ArNS name (lease or permabuy) with Turbo Credits'), buyArNSNameOptions).action(async (_commandOptions, command) => {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { BigNumber } from 'bignumber.js';
|
|
17
17
|
import { TurboFactory } from '../../node/factory.js';
|
|
18
|
-
import { InsufficientCreditsError } from '../../utils/errors.js';
|
|
18
|
+
import { FiatPaymentsDisabledError, InsufficientCreditsError, } from '../../utils/errors.js';
|
|
19
19
|
import { wincPerCredit } from '../constants.js';
|
|
20
20
|
import { configFromOptions, turboFromOptions } from '../utils.js';
|
|
21
21
|
export function requiredNameFromOptions(options) {
|
|
@@ -130,6 +130,45 @@ export async function arnsPrice(options, turbo) {
|
|
|
130
130
|
mARIO,
|
|
131
131
|
}, null, 2));
|
|
132
132
|
}
|
|
133
|
+
export async function arnsFiatQuote(options, turbo) {
|
|
134
|
+
const params = arnsPriceParamsFromOptions(options);
|
|
135
|
+
const address = options.address;
|
|
136
|
+
if (address === undefined) {
|
|
137
|
+
throw new Error('A destination --address is required for a fiat ArNS quote.');
|
|
138
|
+
}
|
|
139
|
+
const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
|
|
140
|
+
try {
|
|
141
|
+
const { purchaseQuote, paymentSession, adjustments, fees } = await client.getArNSFiatPurchaseQuote({
|
|
142
|
+
...params,
|
|
143
|
+
address,
|
|
144
|
+
currency: (options.currency ?? 'usd'),
|
|
145
|
+
method: options.method,
|
|
146
|
+
promoCodes: options.promoCode,
|
|
147
|
+
});
|
|
148
|
+
console.log(JSON.stringify({
|
|
149
|
+
name: purchaseQuote.name,
|
|
150
|
+
intent: purchaseQuote.intent,
|
|
151
|
+
nonce: purchaseQuote.nonce,
|
|
152
|
+
paymentAmount: purchaseQuote.paymentAmount,
|
|
153
|
+
currency: purchaseQuote.currencyType,
|
|
154
|
+
quoteExpirationDate: purchaseQuote.quoteExpirationDate,
|
|
155
|
+
paymentSessionId: paymentSession.id,
|
|
156
|
+
// Present for a payment intent / embedded checkout; a hosted
|
|
157
|
+
// checkout session returns `url` instead.
|
|
158
|
+
clientSecret: paymentSession.client_secret ?? undefined,
|
|
159
|
+
checkoutUrl: paymentSession.url ?? undefined,
|
|
160
|
+
adjustments,
|
|
161
|
+
fees,
|
|
162
|
+
}, null, 2));
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (error instanceof FiatPaymentsDisabledError) {
|
|
166
|
+
console.error('Fiat (Stripe) payments are disabled on this payment service. Use the credit-paid commands (buy-arns-name, extend-arns-lease, ...) instead.');
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
133
172
|
export async function buyArNSName(options, turbo) {
|
|
134
173
|
const name = requiredNameFromOptions(options);
|
|
135
174
|
const type = typeFromOptions(options.type);
|
package/lib/esm/cli/options.js
CHANGED
|
@@ -301,6 +301,23 @@ export const arnsPriceOptions = [
|
|
|
301
301
|
optionMap.arnsIncreaseQty,
|
|
302
302
|
optionMap.arnsProcessId,
|
|
303
303
|
];
|
|
304
|
+
export const arnsFiatQuoteOptions = [
|
|
305
|
+
optionMap.arnsName,
|
|
306
|
+
optionMap.arnsType,
|
|
307
|
+
optionMap.arnsYears,
|
|
308
|
+
optionMap.arnsIncreaseQty,
|
|
309
|
+
optionMap.arnsProcessId,
|
|
310
|
+
optionMap.address,
|
|
311
|
+
optionMap.currency,
|
|
312
|
+
{
|
|
313
|
+
alias: '--method <method>',
|
|
314
|
+
description: 'Stripe integration mode: payment-intent (default) or checkout-session',
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
alias: '--promo-code <promoCode...>',
|
|
318
|
+
description: 'Promo code(s) to apply to the fiat price',
|
|
319
|
+
},
|
|
320
|
+
];
|
|
304
321
|
export const buyArNSNameOptions = [
|
|
305
322
|
...walletOptions,
|
|
306
323
|
optionMap.arnsName,
|
package/lib/esm/common/http.js
CHANGED
|
@@ -30,6 +30,18 @@ const defaultHeaders = {
|
|
|
30
30
|
'x-turbo-source-version': version,
|
|
31
31
|
'x-turbo-source-identifier': 'turbo-sdk',
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Canonical x402 upload routes on the upload service.
|
|
35
|
+
*
|
|
36
|
+
* These were previously `/x402/data-item/{signed,unsigned}`. The service
|
|
37
|
+
* renamed them to `/x402/upload/*` and kept a `data-item/signed` alias, but not
|
|
38
|
+
* a `data-item/unsigned` one — so every unsigned x402 upload 404ed. Both
|
|
39
|
+
* canonical paths are served by all released upload-service versions.
|
|
40
|
+
*/
|
|
41
|
+
export const x402UploadEndpoints = {
|
|
42
|
+
signed: '/x402/upload/signed',
|
|
43
|
+
unsigned: '/x402/upload/unsigned',
|
|
44
|
+
};
|
|
33
45
|
export class TurboHTTPService {
|
|
34
46
|
constructor({ url, logger, retryConfig = defaultRetryConfig(logger), }) {
|
|
35
47
|
this.logger = logger;
|
|
@@ -120,7 +132,9 @@ export class TurboHTTPService {
|
|
|
120
132
|
throw new FailedRequestError('Max retries reached - ' + lastError?.message, lastError?.status);
|
|
121
133
|
}
|
|
122
134
|
async x402Post({ signal, allowedStatuses, headers, data, x402Options, }) {
|
|
123
|
-
const endpoint =
|
|
135
|
+
const endpoint = x402Options.unsignedData
|
|
136
|
+
? x402UploadEndpoints.unsigned
|
|
137
|
+
: x402UploadEndpoints.signed;
|
|
124
138
|
this.logger.debug('Using X402 options for POST request', {
|
|
125
139
|
endpoint,
|
|
126
140
|
x402Options,
|