@ardrive/turbo-sdk 1.19.2 → 1.20.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.
Files changed (67) hide show
  1. package/README.md +95 -1
  2. package/bundles/web.bundle.min.js +143 -14
  3. package/lib/cjs/cli/cli.js +18 -0
  4. package/lib/cjs/cli/commands/balance.js +26 -15
  5. package/lib/cjs/cli/commands/createApproval.js +39 -0
  6. package/lib/cjs/cli/commands/cryptoFund.js +3 -1
  7. package/lib/cjs/cli/commands/listApprovals.js +58 -0
  8. package/lib/cjs/cli/commands/price.js +2 -1
  9. package/lib/cjs/cli/commands/revokeApprovals.js +15 -0
  10. package/lib/cjs/cli/commands/uploadFile.js +2 -1
  11. package/lib/cjs/cli/commands/uploadFolder.js +2 -1
  12. package/lib/cjs/cli/constants.js +2 -1
  13. package/lib/cjs/cli/options.js +43 -4
  14. package/lib/cjs/cli/utils.js +31 -0
  15. package/lib/cjs/common/payment.js +30 -4
  16. package/lib/cjs/common/token/solana.js +2 -2
  17. package/lib/cjs/common/turbo.js +31 -2
  18. package/lib/cjs/common/upload.js +65 -6
  19. package/lib/cjs/version.js +1 -1
  20. package/lib/esm/cli/cli.js +19 -1
  21. package/lib/esm/cli/commands/balance.js +26 -15
  22. package/lib/esm/cli/commands/createApproval.js +36 -0
  23. package/lib/esm/cli/commands/cryptoFund.js +3 -1
  24. package/lib/esm/cli/commands/listApprovals.js +55 -0
  25. package/lib/esm/cli/commands/price.js +2 -1
  26. package/lib/esm/cli/commands/revokeApprovals.js +12 -0
  27. package/lib/esm/cli/commands/uploadFile.js +3 -2
  28. package/lib/esm/cli/commands/uploadFolder.js +3 -2
  29. package/lib/esm/cli/constants.js +1 -0
  30. package/lib/esm/cli/options.js +42 -3
  31. package/lib/esm/cli/utils.js +30 -0
  32. package/lib/esm/common/payment.js +30 -4
  33. package/lib/esm/common/token/solana.js +2 -2
  34. package/lib/esm/common/turbo.js +31 -2
  35. package/lib/esm/common/upload.js +64 -5
  36. package/lib/esm/version.js +1 -1
  37. package/lib/types/cli/commands/balance.d.ts.map +1 -1
  38. package/lib/types/cli/commands/createApproval.d.ts +3 -0
  39. package/lib/types/cli/commands/createApproval.d.ts.map +1 -0
  40. package/lib/types/cli/commands/cryptoFund.d.ts.map +1 -1
  41. package/lib/types/cli/commands/listApprovals.d.ts +3 -0
  42. package/lib/types/cli/commands/listApprovals.d.ts.map +1 -0
  43. package/lib/types/cli/commands/price.d.ts.map +1 -1
  44. package/lib/types/cli/commands/revokeApprovals.d.ts +18 -0
  45. package/lib/types/cli/commands/revokeApprovals.d.ts.map +1 -0
  46. package/lib/types/cli/commands/uploadFile.d.ts.map +1 -1
  47. package/lib/types/cli/commands/uploadFolder.d.ts.map +1 -1
  48. package/lib/types/cli/constants.d.ts +1 -0
  49. package/lib/types/cli/constants.d.ts.map +1 -1
  50. package/lib/types/cli/options.d.ts +121 -2
  51. package/lib/types/cli/options.d.ts.map +1 -1
  52. package/lib/types/cli/types.d.ts +17 -2
  53. package/lib/types/cli/types.d.ts.map +1 -1
  54. package/lib/types/cli/utils.d.ts +2 -1
  55. package/lib/types/cli/utils.d.ts.map +1 -1
  56. package/lib/types/common/payment.d.ts +8 -2
  57. package/lib/types/common/payment.d.ts.map +1 -1
  58. package/lib/types/common/token/solana.d.ts.map +1 -1
  59. package/lib/types/common/turbo.d.ts +27 -2
  60. package/lib/types/common/turbo.d.ts.map +1 -1
  61. package/lib/types/common/upload.d.ts +7 -1
  62. package/lib/types/common/upload.d.ts.map +1 -1
  63. package/lib/types/types.d.ts +54 -3
  64. package/lib/types/types.d.ts.map +1 -1
  65. package/lib/types/version.d.ts +1 -1
  66. package/lib/types/version.d.ts.map +1 -1
  67. package/package.json +4 -3
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.turboCliTags = void 0;
3
+ exports.wincPerCredit = exports.turboCliTags = void 0;
4
4
  /**
5
5
  * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
6
6
  *
@@ -22,3 +22,4 @@ exports.turboCliTags = [
22
22
  { name: 'App-Version', value: version_js_1.version },
23
23
  { name: 'App-Platform', value: process.platform },
24
24
  ];
25
+ exports.wincPerCredit = 1_000_000_000_000;
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.uploadFileOptions = exports.uploadFolderOptions = exports.globalOptions = exports.walletOptions = exports.optionMap = void 0;
18
+ exports.listApprovalsOptions = exports.revokeApprovalsOptions = exports.createApprovalOptions = 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>',
@@ -73,7 +73,12 @@ exports.optionMap = {
73
73
  },
74
74
  dev: {
75
75
  alias: '--dev',
76
- description: 'Enable development endpoints',
76
+ description: 'Enable Turbo development endpoints',
77
+ default: false,
78
+ },
79
+ local: {
80
+ alias: '--local',
81
+ description: 'Enable local development endpoints',
77
82
  default: false,
78
83
  },
79
84
  debug: {
@@ -118,6 +123,25 @@ exports.optionMap = {
118
123
  alias: '--max-concurrency <maxConcurrency>',
119
124
  description: 'Maximum number of concurrent uploads',
120
125
  },
126
+ paidBy: {
127
+ alias: '--paid-by <paidBy...>',
128
+ description: 'Address to pay for the upload',
129
+ type: 'array',
130
+ },
131
+ expiresBySeconds: {
132
+ alias: '--expires-by-seconds <expiresBySeconds>',
133
+ description: 'Expiration time in seconds',
134
+ },
135
+ ignoreApprovals: {
136
+ alias: '--ignore-approvals',
137
+ description: "Ignore all delegated payment approvals, only use signing wallet's balance",
138
+ default: false,
139
+ },
140
+ useSignerBalanceFirst: {
141
+ alias: '--use-signer-balance-first',
142
+ description: 'Use the signer balance first before using delegated payment approvals',
143
+ default: false,
144
+ },
121
145
  };
122
146
  exports.walletOptions = [
123
147
  exports.optionMap.walletFile,
@@ -126,6 +150,7 @@ exports.walletOptions = [
126
150
  ];
127
151
  exports.globalOptions = [
128
152
  exports.optionMap.dev,
153
+ exports.optionMap.local,
129
154
  exports.optionMap.gateway,
130
155
  exports.optionMap.debug,
131
156
  exports.optionMap.quiet,
@@ -134,12 +159,26 @@ exports.globalOptions = [
134
159
  exports.optionMap.paymentUrl,
135
160
  exports.optionMap.uploadUrl,
136
161
  ];
137
- exports.uploadFolderOptions = [
162
+ exports.uploadOptions = [
138
163
  ...exports.walletOptions,
164
+ exports.optionMap.paidBy,
165
+ exports.optionMap.ignoreApprovals,
166
+ exports.optionMap.useSignerBalanceFirst,
167
+ ];
168
+ exports.uploadFolderOptions = [
169
+ ...exports.uploadOptions,
139
170
  exports.optionMap.folderPath,
140
171
  exports.optionMap.indexFile,
141
172
  exports.optionMap.fallbackFile,
142
173
  exports.optionMap.manifest,
143
174
  exports.optionMap.maxConcurrency,
144
175
  ];
145
- exports.uploadFileOptions = [...exports.walletOptions, exports.optionMap.filePath];
176
+ exports.uploadFileOptions = [...exports.uploadOptions, exports.optionMap.filePath];
177
+ exports.createApprovalOptions = [
178
+ ...exports.walletOptions,
179
+ exports.optionMap.value,
180
+ exports.optionMap.address,
181
+ exports.optionMap.expiresBySeconds,
182
+ ];
183
+ exports.revokeApprovalsOptions = [...exports.walletOptions, exports.optionMap.address];
184
+ exports.listApprovalsOptions = exports.revokeApprovalsOptions;
@@ -14,6 +14,7 @@ exports.optionalPrivateKeyFromOptions = optionalPrivateKeyFromOptions;
14
14
  exports.privateKeyFromOptions = privateKeyFromOptions;
15
15
  exports.configFromOptions = configFromOptions;
16
16
  exports.turboFromOptions = turboFromOptions;
17
+ exports.paidByFromOptions = paidByFromOptions;
17
18
  exports.getUploadFolderOptions = getUploadFolderOptions;
18
19
  /**
19
20
  * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
@@ -138,12 +139,21 @@ function configFromOptions(options) {
138
139
  let paymentUrl = undefined;
139
140
  let uploadUrl = undefined;
140
141
  let gatewayUrl = undefined;
142
+ if (options.local && options.dev) {
143
+ throw new Error('Cannot use both --local and --dev flags');
144
+ }
141
145
  if (options.dev) {
142
146
  // Use development endpoints
143
147
  paymentUrl = index_js_1.developmentTurboConfiguration.paymentServiceConfig.url;
144
148
  uploadUrl = index_js_1.developmentTurboConfiguration.uploadServiceConfig.url;
145
149
  gatewayUrl = tokenToDevGatewayMap[token];
146
150
  }
151
+ else if (options.local) {
152
+ // Use local endpoints
153
+ paymentUrl = 'http://localhost:4000';
154
+ uploadUrl = 'http://localhost:3000';
155
+ gatewayUrl = 'http://localhost:1984';
156
+ }
147
157
  else {
148
158
  // Use default endpoints
149
159
  paymentUrl = index_js_1.defaultTurboConfiguration.paymentServiceConfig.url;
@@ -174,6 +184,27 @@ async function turboFromOptions(options) {
174
184
  privateKey,
175
185
  });
176
186
  }
187
+ async function paidByFromOptions({ paidBy: paidByCliInput, ignoreApprovals, useSignerBalanceFirst, }, turbo) {
188
+ const paidBy = await (async () => {
189
+ if (paidByCliInput !== undefined && paidByCliInput.length > 0) {
190
+ return paidByCliInput;
191
+ }
192
+ if (ignoreApprovals) {
193
+ return undefined;
194
+ }
195
+ const { receivedApprovals } = await turbo.getBalance();
196
+ if (receivedApprovals !== undefined && receivedApprovals.length !== 0) {
197
+ // get unique paying addresses from any received approvals
198
+ return Array.from(new Set(receivedApprovals.map((approval) => approval.payingAddress)));
199
+ }
200
+ return undefined;
201
+ })();
202
+ if (paidBy !== undefined && useSignerBalanceFirst) {
203
+ // Add the signer's address to the front of the paidBy array
204
+ paidBy.unshift(await turbo.signer.getNativeAddress());
205
+ }
206
+ return paidBy;
207
+ }
177
208
  function getUploadFolderOptions(options) {
178
209
  if (options.folderPath === undefined) {
179
210
  throw new Error('--folder-path is required');
@@ -37,7 +37,15 @@ class TurboUnauthenticatedPaymentService {
37
37
  endpoint: `/account/balance/${this.token}?address=${address}`,
38
38
  allowedStatuses: [200, 404],
39
39
  });
40
- return balance.winc ? balance : { winc: '0' };
40
+ return balance.winc
41
+ ? balance
42
+ : {
43
+ winc: '0',
44
+ controlledWinc: '0',
45
+ effectiveBalance: '0',
46
+ givenApprovals: [],
47
+ receivedApprovals: [],
48
+ };
41
49
  }
42
50
  getFiatRates() {
43
51
  return this.httpService.get({
@@ -156,6 +164,20 @@ class TurboUnauthenticatedPaymentService {
156
164
  }
157
165
  throw new Error('Unknown response from payment service: ' + response);
158
166
  }
167
+ async getDelegatedPaymentApprovals({ userAddress, }) {
168
+ const response = await this.httpService.get({
169
+ endpoint: `/account/approvals/get?userAddress=${userAddress}`,
170
+ allowedStatuses: [200, 404],
171
+ });
172
+ if (response?.givenApprovals === undefined &&
173
+ response?.receivedApprovals === undefined) {
174
+ return {
175
+ givenApprovals: [],
176
+ receivedApprovals: [],
177
+ };
178
+ }
179
+ return response;
180
+ }
159
181
  }
160
182
  exports.TurboUnauthenticatedPaymentService = TurboUnauthenticatedPaymentService;
161
183
  // NOTE: to avoid redundancy, we use inheritance here - but generally prefer composition over inheritance
@@ -165,9 +187,13 @@ class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymentServic
165
187
  this.signer = signer;
166
188
  this.tokenTools = tokenTools;
167
189
  }
168
- async getBalance(address) {
169
- address ??= await this.signer.getNativeAddress();
170
- return super.getBalance(address);
190
+ async getBalance(userAddress) {
191
+ userAddress ??= await this.signer.getNativeAddress();
192
+ return super.getBalance(userAddress);
193
+ }
194
+ async getDelegatedPaymentApprovals({ userAddress, }) {
195
+ userAddress ??= await this.signer.getNativeAddress();
196
+ return super.getDelegatedPaymentApprovals({ userAddress });
171
197
  }
172
198
  async getWincForFiat({ amount, promoCodes = [], }) {
173
199
  return super.getWincForFiat({
@@ -41,7 +41,7 @@ class SolanaToken {
41
41
  this.pollingOptions = pollingOptions;
42
42
  }
43
43
  async createAndSubmitTx({ target, tokenAmount, signer, }) {
44
- const publicKey = new web3_js_1.PublicKey(bs58_1.default.encode(await signer.getPublicKey()));
44
+ const publicKey = new web3_js_1.PublicKey(bs58_1.default.encode(Uint8Array.from(await signer.getPublicKey())));
45
45
  const tx = new web3_js_1.Transaction({
46
46
  feePayer: publicKey,
47
47
  ...(await this.connection.getLatestBlockhash()),
@@ -52,7 +52,7 @@ class SolanaToken {
52
52
  lamports: +new bignumber_js_1.BigNumber(tokenAmount),
53
53
  }));
54
54
  const serializedTx = tx.serializeMessage();
55
- const signature = await signer.signData(serializedTx);
55
+ const signature = await signer.signData(Uint8Array.from(serializedTx));
56
56
  tx.addSignature(publicKey, node_buffer_1.Buffer.from(signature));
57
57
  const id = bs58_1.default.encode(signature);
58
58
  await this.submitTx(tx, id);
@@ -108,6 +108,12 @@ class TurboUnauthenticatedClient {
108
108
  wallets.pol = wallets.matic;
109
109
  return wallets;
110
110
  }
111
+ /**
112
+ * Returns a list of all delegated payment approvals for the user.
113
+ */
114
+ getDelegatedPaymentApprovals(p) {
115
+ return this.paymentService.getDelegatedPaymentApprovals(p);
116
+ }
111
117
  }
112
118
  exports.TurboUnauthenticatedClient = TurboUnauthenticatedClient;
113
119
  class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
@@ -118,8 +124,14 @@ class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
118
124
  /**
119
125
  * Returns the current balance of the user's wallet in 'winc'.
120
126
  */
121
- getBalance(address) {
122
- return this.paymentService.getBalance(address);
127
+ getBalance(userAddress) {
128
+ return this.paymentService.getBalance(userAddress);
129
+ }
130
+ /**
131
+ * Returns a list of all delegated payment approvals for the user.
132
+ */
133
+ getDelegatedPaymentApprovals(p = {}) {
134
+ return this.paymentService.getDelegatedPaymentApprovals(p);
123
135
  }
124
136
  /**
125
137
  * Signs and uploads raw data to the Turbo Upload Service.
@@ -142,5 +154,22 @@ class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
142
154
  topUpWithTokens(p) {
143
155
  return this.paymentService.topUpWithTokens(p);
144
156
  }
157
+ /**
158
+ * Creates a data item with tags that designate it as a delegated payment approval.
159
+ * Signs the data item and sends it to the Turbo Upload Service, which will verify
160
+ * the signature and forward the admin action towards the Turbo Payment Service.
161
+ */
162
+ createDelegatedPaymentApproval(p) {
163
+ return this.uploadService.createDelegatedPaymentApproval(p);
164
+ }
165
+ /**
166
+ * Creates a data item with tags that designate it as a revoke action for delegated
167
+ * payment approvals for target revokedAddress. Signs the data item and sends it to
168
+ * the Turbo Upload Service, which will verify the signature and forward the admin
169
+ * action towards the Turbo Payment Service.
170
+ */
171
+ revokeDelegatedPaymentApprovals(p) {
172
+ return this.uploadService.revokeDelegatedPaymentApprovals(p);
173
+ }
145
174
  }
146
175
  exports.TurboAuthenticatedClient = TurboAuthenticatedClient;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TurboAuthenticatedBaseUploadService = exports.TurboUnauthenticatedUploadService = exports.defaultUploadServiceURL = exports.developmentUploadServiceURL = void 0;
3
+ exports.TurboAuthenticatedBaseUploadService = exports.TurboUnauthenticatedUploadService = exports.defaultUploadServiceURL = exports.developmentUploadServiceURL = exports.revokeDelegatePaymentApprovalTagName = exports.approvalExpiresBySecondsTagName = exports.approvalAmountTagName = exports.createDelegatedPaymentApprovalTagName = void 0;
4
4
  /**
5
5
  * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
6
6
  *
@@ -17,9 +17,14 @@ exports.TurboAuthenticatedBaseUploadService = exports.TurboUnauthenticatedUpload
17
17
  * limitations under the License.
18
18
  */
19
19
  const node_buffer_1 = require("node:buffer");
20
+ const node_stream_1 = require("node:stream");
20
21
  const plimit_lit_1 = require("plimit-lit");
21
22
  const http_js_1 = require("./http.js");
22
23
  const logger_js_1 = require("./logger.js");
24
+ exports.createDelegatedPaymentApprovalTagName = 'x-approve-payment';
25
+ exports.approvalAmountTagName = 'x-amount';
26
+ exports.approvalExpiresBySecondsTagName = 'x-expires-seconds';
27
+ exports.revokeDelegatePaymentApprovalTagName = 'x-delete-payment-approval';
23
28
  exports.developmentUploadServiceURL = 'https://upload.ardrive.dev';
24
29
  exports.defaultUploadServiceURL = 'https://upload.ardrive.io';
25
30
  class TurboUnauthenticatedUploadService {
@@ -61,17 +66,25 @@ class TurboAuthenticatedBaseUploadService extends TurboUnauthenticatedUploadServ
61
66
  dataItemOpts,
62
67
  });
63
68
  const signedDataItem = dataItemStreamFactory();
64
- const fileSize = dataItemSizeFactory();
65
69
  this.logger.debug('Uploading signed data item...');
66
70
  // TODO: add p-limit constraint or replace with separate upload class
71
+ const headers = {
72
+ 'content-type': 'application/octet-stream',
73
+ 'content-length': `${dataItemSizeFactory()}`,
74
+ };
75
+ if (dataItemOpts !== undefined && dataItemOpts.paidBy !== undefined) {
76
+ const paidBy = Array.isArray(dataItemOpts.paidBy)
77
+ ? dataItemOpts.paidBy
78
+ : [dataItemOpts.paidBy];
79
+ if (dataItemOpts.paidBy.length > 0) {
80
+ headers['x-paid-by'] = paidBy;
81
+ }
82
+ }
67
83
  return this.httpService.post({
68
84
  endpoint: `/tx/${this.token}`,
69
85
  signal,
70
86
  data: signedDataItem,
71
- headers: {
72
- 'content-type': 'application/octet-stream',
73
- 'content-length': `${fileSize}`,
74
- },
87
+ headers,
75
88
  });
76
89
  }
77
90
  async generateManifest({ paths, indexFile, fallbackFile, }) {
@@ -182,5 +195,51 @@ class TurboAuthenticatedBaseUploadService extends TurboUnauthenticatedUploadServ
182
195
  manifestResponse,
183
196
  };
184
197
  }
198
+ async createDelegatedPaymentApproval({ approvedAddress, approvedWincAmount, expiresBySeconds, }) {
199
+ const dataItemOpts = {
200
+ tags: [
201
+ { name: exports.createDelegatedPaymentApprovalTagName, value: approvedAddress },
202
+ { name: exports.approvalAmountTagName, value: approvedWincAmount.toString() },
203
+ ],
204
+ };
205
+ if (expiresBySeconds !== undefined) {
206
+ dataItemOpts.tags.push({
207
+ name: exports.approvalExpiresBySecondsTagName,
208
+ value: expiresBySeconds.toString(),
209
+ });
210
+ }
211
+ const nonceData = node_buffer_1.Buffer.from(approvedAddress + approvedWincAmount + Date.now());
212
+ const { createdApproval, ...uploadResponse } = await this.uploadFile({
213
+ fileStreamFactory: () => node_stream_1.Readable.from(nonceData),
214
+ fileSizeFactory: () => nonceData.byteLength,
215
+ dataItemOpts,
216
+ });
217
+ if (!createdApproval) {
218
+ throw new Error('Failed to create delegated payment approval but upload has succeeded\n' +
219
+ JSON.stringify(uploadResponse));
220
+ }
221
+ return createdApproval;
222
+ }
223
+ async revokeDelegatedPaymentApprovals({ revokedAddress, }) {
224
+ const dataItemOpts = {
225
+ tags: [
226
+ {
227
+ name: exports.revokeDelegatePaymentApprovalTagName,
228
+ value: revokedAddress,
229
+ },
230
+ ],
231
+ };
232
+ const nonceData = node_buffer_1.Buffer.from(revokedAddress + Date.now());
233
+ const { revokedApprovals, ...uploadResponse } = await this.uploadFile({
234
+ fileStreamFactory: () => node_stream_1.Readable.from(nonceData),
235
+ fileSizeFactory: () => nonceData.byteLength,
236
+ dataItemOpts,
237
+ });
238
+ if (!revokedApprovals) {
239
+ throw new Error('Failed to revoke delegated payment approvals but upload has succeeded\n' +
240
+ JSON.stringify(uploadResponse));
241
+ }
242
+ return revokedApprovals;
243
+ }
185
244
  }
186
245
  exports.TurboAuthenticatedBaseUploadService = TurboAuthenticatedBaseUploadService;
@@ -17,4 +17,4 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.version = void 0;
19
19
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
20
- exports.version = '1.19.2';
20
+ exports.version = '1.20.0-alpha.1';
@@ -18,8 +18,11 @@
18
18
  // eslint-disable-next-line header/header -- This is a CLI file
19
19
  import { program } from 'commander';
20
20
  import { version } from '../version.js';
21
+ import { createApproval } from './commands/createApproval.js';
21
22
  import { balance, cryptoFund, price, topUp, uploadFile, uploadFolder, } from './commands/index.js';
22
- import { globalOptions, optionMap, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
23
+ import { listApprovals } from './commands/listApprovals.js';
24
+ import { revokeApprovals } from './commands/revokeApprovals.js';
25
+ import { createApprovalOptions, globalOptions, listApprovalsOptions, optionMap, revokeApprovalsOptions, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
23
26
  import { applyOptions, runCommand } from './utils.js';
24
27
  applyOptions(program
25
28
  .name('turbo')
@@ -46,6 +49,21 @@ applyOptions(program
46
49
  .description('Get the current Credits estimate for byte, crypto, or fiat value'), [optionMap.value, optionMap.type]).action(async (_commandOptions, command) => {
47
50
  await runCommand(command, price);
48
51
  });
52
+ applyOptions(program
53
+ .command('create-approval')
54
+ .description('Create a Turbo delegated payment approval'), createApprovalOptions).action(async (_commandOptions, command) => {
55
+ await runCommand(command, createApproval);
56
+ });
57
+ applyOptions(program
58
+ .command('revoke-approvals')
59
+ .description('Revokes all Turbo delegated payment approvals for given address'), revokeApprovalsOptions).action(async (_commandOptions, command) => {
60
+ await runCommand(command, revokeApprovals);
61
+ });
62
+ applyOptions(program
63
+ .command('list-approvals')
64
+ .description('Lists all Turbo delegated payment approvals for given address or wallet'), listApprovalsOptions).action(async (_commandOptions, command) => {
65
+ await runCommand(command, listApprovals);
66
+ });
49
67
  if (process.argv[1].includes('bin/turbo') || // Running from global .bin
50
68
  process.argv[1].includes('cli/cli') // Running from source
51
69
  ) {
@@ -13,24 +13,35 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
+ import { BigNumber } from 'bignumber.js';
16
17
  import { TurboFactory } from '../../node/factory.js';
18
+ import { wincPerCredit } from '../constants.js';
17
19
  import { addressOrPrivateKeyFromOptions, configFromOptions } from '../utils.js';
18
20
  export async function balance(options) {
19
21
  const config = configFromOptions(options);
20
22
  const { address, privateKey } = await addressOrPrivateKeyFromOptions(options);
21
- if (address !== undefined) {
22
- const turbo = TurboFactory.unauthenticated(config);
23
- const { winc } = await turbo.getBalance(address);
24
- console.log(`Turbo Balance for Native Address "${address}"\nCredits: ${+winc / 1_000_000_000_000}`);
25
- return;
26
- }
27
- if (privateKey === undefined) {
28
- throw new Error('Must provide an (--address) or use a valid wallet');
29
- }
30
- const turbo = TurboFactory.authenticated({
31
- ...config,
32
- privateKey,
33
- });
34
- const { winc } = await turbo.getBalance();
35
- console.log(`Turbo Balance for Wallet Address "${await turbo.signer.getNativeAddress()}"\nCredits: ${+winc / 1_000_000_000_000}`);
23
+ const { effectiveBalance, nativeAddress, winc, controlledWinc } = await (async () => {
24
+ if (address !== undefined) {
25
+ return {
26
+ ...(await TurboFactory.unauthenticated(config).getBalance(address)),
27
+ nativeAddress: address,
28
+ };
29
+ }
30
+ if (privateKey === undefined) {
31
+ throw new Error('Must provide an (--address) or use a valid wallet');
32
+ }
33
+ const turbo = TurboFactory.authenticated({
34
+ ...config,
35
+ privateKey,
36
+ });
37
+ return {
38
+ ...(await turbo.getBalance()),
39
+ nativeAddress: await turbo.signer.getNativeAddress(),
40
+ };
41
+ })();
42
+ console.log(`Turbo Balance for Native Address "${nativeAddress}"\nEffective Credits: ${+effectiveBalance / wincPerCredit}${winc === controlledWinc
43
+ ? ''
44
+ : `\nCredits Shared to Other Wallets: ${BigNumber(controlledWinc)
45
+ .minus(winc)
46
+ .div(wincPerCredit)}`}`);
36
47
  }
@@ -0,0 +1,36 @@
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 { BigNumber } from 'bignumber.js';
17
+ import { turboFromOptions } from '../utils.js';
18
+ export async function createApproval(options) {
19
+ const { address: approvedAddress, value: creditAmount, expiresBySeconds, } = options;
20
+ if (approvedAddress === undefined) {
21
+ throw new Error('Must provide an approved --address to create approval for');
22
+ }
23
+ if (creditAmount === undefined) {
24
+ throw new Error('Must provide a credit --value to create approval for');
25
+ }
26
+ const turbo = await turboFromOptions(options);
27
+ const approvedWincAmount = new BigNumber(creditAmount)
28
+ .shiftedBy(12)
29
+ .toFixed(0);
30
+ const result = await turbo.createDelegatedPaymentApproval({
31
+ approvedAddress,
32
+ approvedWincAmount,
33
+ expiresBySeconds,
34
+ });
35
+ console.log(JSON.stringify({ message: 'Created approval:', ...result }, null, 2));
36
+ }
@@ -13,9 +13,11 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
+ import { BigNumber } from 'bignumber.js';
16
17
  import prompts from 'prompts';
17
18
  import { tokenToBaseMap } from '../../common/index.js';
18
19
  import { TurboFactory } from '../../node/factory.js';
20
+ import { wincPerCredit } from '../constants.js';
19
21
  import { configFromOptions, tokenFromOptions, turboFromOptions, } from '../utils.js';
20
22
  export async function cryptoFund(options) {
21
23
  const value = options.value;
@@ -35,7 +37,7 @@ export async function cryptoFund(options) {
35
37
  if (!options.skipConfirmation) {
36
38
  const { winc } = await turbo.getWincForToken({ tokenAmount });
37
39
  const targetWallet = (await turbo.getTurboCryptoWallets())[token];
38
- const credits = (+winc / 1_000_000_000_000).toFixed(12);
40
+ const credits = BigNumber(winc).dividedBy(wincPerCredit).toFixed(12);
39
41
  const { confirm } = await prompts({
40
42
  type: 'confirm',
41
43
  name: 'confirm',
@@ -0,0 +1,55 @@
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 { TurboFactory } from '../../node/factory.js';
17
+ import { addressOrPrivateKeyFromOptions, configFromOptions } from '../utils.js';
18
+ export async function listApprovals(options) {
19
+ const config = configFromOptions(options);
20
+ const { address, privateKey } = await addressOrPrivateKeyFromOptions(options);
21
+ const { givenApprovals, receivedApprovals, nativeAddress } = await (async () => {
22
+ if (address !== undefined) {
23
+ const approvals = await TurboFactory.unauthenticated(config).getDelegatedPaymentApprovals({
24
+ userAddress: address,
25
+ });
26
+ return { ...approvals, nativeAddress: address };
27
+ }
28
+ if (privateKey === undefined) {
29
+ throw new Error('Must provide an (--address) or use a valid wallet');
30
+ }
31
+ const turbo = TurboFactory.authenticated({
32
+ ...config,
33
+ privateKey,
34
+ });
35
+ const approvals = await turbo.getDelegatedPaymentApprovals();
36
+ return {
37
+ ...approvals,
38
+ nativeAddress: await turbo.signer.getNativeAddress(),
39
+ };
40
+ })();
41
+ const hasApprovals = givenApprovals?.length === 0 && receivedApprovals?.length === 0;
42
+ const body = {
43
+ message: `${hasApprovals ? 'No approvals found' : 'Approvals found'}` +
44
+ ` for native address '${nativeAddress}'`,
45
+ givenApprovals,
46
+ receivedApprovals,
47
+ };
48
+ if (givenApprovals?.length > 0) {
49
+ body['givenApprovals'] = givenApprovals;
50
+ }
51
+ if (receivedApprovals?.length > 0) {
52
+ body['receivedApprovals'] = receivedApprovals;
53
+ }
54
+ console.log(JSON.stringify(body, null, 2));
55
+ }
@@ -17,6 +17,7 @@ import { currencyMap } from '../../common/currency.js';
17
17
  import { isTokenType, tokenToBaseMap } from '../../common/index.js';
18
18
  import { TurboFactory } from '../../node/factory.js';
19
19
  import { fiatCurrencyTypes, isCurrency, tokenTypes } from '../../types.js';
20
+ import { wincPerCredit } from '../constants.js';
20
21
  import { configFromOptions } from '../utils.js';
21
22
  export async function price(options) {
22
23
  const value = options.value;
@@ -45,5 +46,5 @@ export async function price(options) {
45
46
  }
46
47
  throw new Error(`Invalid price type!\nMust be one of: bytes, ${fiatCurrencyTypes.join(', ') + ' ' + tokenTypes.join(', ')}`);
47
48
  })();
48
- console.log(`Current price estimate for ${value} ${type} is ~${(+winc / 1_000_000_000_000).toFixed(12)} Credits`);
49
+ console.log(`Current price estimate for ${value} ${type} is ~${(+winc / wincPerCredit).toFixed(12)} Credits`);
49
50
  }
@@ -0,0 +1,12 @@
1
+ import { turboFromOptions } from '../utils.js';
2
+ export async function revokeApprovals(options) {
3
+ const { address: revokedAddress } = options;
4
+ if (revokedAddress === undefined) {
5
+ throw new Error('Must provide an approved --address to revoke approvals for');
6
+ }
7
+ const turbo = await turboFromOptions(options);
8
+ const revokedApprovals = await turbo.revokeDelegatedPaymentApprovals({
9
+ revokedAddress,
10
+ });
11
+ console.log(JSON.stringify({ message: 'Revoked approvals', revokedApprovals }, null, 2));
12
+ }
@@ -15,18 +15,19 @@
15
15
  */
16
16
  import { createReadStream, statSync } from 'fs';
17
17
  import { turboCliTags } from '../constants.js';
18
- import { turboFromOptions } from '../utils.js';
18
+ import { paidByFromOptions, turboFromOptions } from '../utils.js';
19
19
  export async function uploadFile(options) {
20
20
  const { filePath } = options;
21
21
  if (filePath === undefined) {
22
22
  throw new Error('Must provide a --file-path to upload');
23
23
  }
24
24
  const turbo = await turboFromOptions(options);
25
+ const paidBy = await paidByFromOptions(options, turbo);
25
26
  const fileSize = statSync(filePath).size;
26
27
  const result = await turbo.uploadFile({
27
28
  fileStreamFactory: () => createReadStream(filePath),
28
29
  fileSizeFactory: () => fileSize,
29
- dataItemOpts: { tags: [...turboCliTags] }, // TODO: Inject user tags
30
+ dataItemOpts: { tags: [...turboCliTags], paidBy }, // TODO: Inject user tags
30
31
  });
31
32
  console.log('Uploaded file:', JSON.stringify(result, null, 2));
32
33
  }