@ardrive/turbo-sdk 1.19.2 → 1.20.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +123 -1
  2. package/bundles/web.bundle.min.js +148 -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/cryptoFund.js +3 -1
  6. package/lib/cjs/cli/commands/listShares.js +58 -0
  7. package/lib/cjs/cli/commands/price.js +2 -1
  8. package/lib/cjs/cli/commands/revokeCredits.js +15 -0
  9. package/lib/cjs/cli/commands/shareCredits.js +39 -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 +73 -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/cryptoFund.js +3 -1
  23. package/lib/esm/cli/commands/listShares.js +55 -0
  24. package/lib/esm/cli/commands/price.js +2 -1
  25. package/lib/esm/cli/commands/revokeCredits.js +12 -0
  26. package/lib/esm/cli/commands/shareCredits.js +36 -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 +72 -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/cryptoFund.d.ts.map +1 -1
  39. package/lib/types/cli/commands/listShares.d.ts +3 -0
  40. package/lib/types/cli/commands/listShares.d.ts.map +1 -0
  41. package/lib/types/cli/commands/price.d.ts.map +1 -1
  42. package/lib/types/cli/commands/revokeCredits.d.ts +18 -0
  43. package/lib/types/cli/commands/revokeCredits.d.ts.map +1 -0
  44. package/lib/types/cli/commands/shareCredits.d.ts +3 -0
  45. package/lib/types/cli/commands/shareCredits.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 +9 -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/utils/axiosClient.d.ts.map +1 -1
  66. package/lib/types/version.d.ts +1 -1
  67. package/package.json +4 -3
@@ -25,11 +25,12 @@ async function uploadFile(options) {
25
25
  throw new Error('Must provide a --file-path to upload');
26
26
  }
27
27
  const turbo = await (0, utils_js_1.turboFromOptions)(options);
28
+ const paidBy = await (0, utils_js_1.paidByFromOptions)(options, turbo);
28
29
  const fileSize = (0, fs_1.statSync)(filePath).size;
29
30
  const result = await turbo.uploadFile({
30
31
  fileStreamFactory: () => (0, fs_1.createReadStream)(filePath),
31
32
  fileSizeFactory: () => fileSize,
32
- dataItemOpts: { tags: [...constants_js_1.turboCliTags] }, // TODO: Inject user tags
33
+ dataItemOpts: { tags: [...constants_js_1.turboCliTags], paidBy }, // TODO: Inject user tags
33
34
  });
34
35
  console.log('Uploaded file:', JSON.stringify(result, null, 2));
35
36
  }
@@ -20,10 +20,11 @@ const constants_js_1 = require("../constants.js");
20
20
  const utils_js_1 = require("../utils.js");
21
21
  async function uploadFolder(options) {
22
22
  const turbo = await (0, utils_js_1.turboFromOptions)(options);
23
+ const paidBy = await (0, utils_js_1.paidByFromOptions)(options, turbo);
23
24
  const { disableManifest, fallbackFile, folderPath, indexFile, maxConcurrentUploads, } = (0, utils_js_1.getUploadFolderOptions)(options);
24
25
  const result = await turbo.uploadFolder({
25
26
  folderPath: folderPath,
26
- dataItemOpts: { tags: [...constants_js_1.turboCliTags] }, // TODO: Inject user tags
27
+ dataItemOpts: { tags: [...constants_js_1.turboCliTags], paidBy }, // TODO: Inject user tags
27
28
  manifestOptions: {
28
29
  disableManifest,
29
30
  indexFile,
@@ -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.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>',
@@ -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 credit share 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 credit share 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.shareCreditsOptions = [
178
+ ...exports.walletOptions,
179
+ exports.optionMap.value,
180
+ exports.optionMap.address,
181
+ exports.optionMap.expiresBySeconds,
182
+ ];
183
+ exports.revokeCreditsOptions = [...exports.walletOptions, exports.optionMap.address];
184
+ exports.listSharesOptions = exports.revokeCreditsOptions;
@@ -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 getCreditShareApprovals({ 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 getCreditShareApprovals({ userAddress, }) {
195
+ userAddress ??= await this.signer.getNativeAddress();
196
+ return super.getCreditShareApprovals({ 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 credit share approvals for the user.
113
+ */
114
+ getCreditShareApprovals(p) {
115
+ return this.paymentService.getCreditShareApprovals(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 credit share approvals for the user.
132
+ */
133
+ getCreditShareApprovals(p = {}) {
134
+ return this.paymentService.getCreditShareApprovals(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 credit share 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
+ shareCredits(p) {
163
+ return this.uploadService.shareCredits(p);
164
+ }
165
+ /**
166
+ * Creates a data item with tags that designate it as a revoke action for credit
167
+ * share 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
+ revokeCredits(p) {
172
+ return this.uploadService.revokeCredits(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.creditSharingTagNames = void 0;
4
4
  /**
5
5
  * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
6
6
  *
@@ -17,9 +17,16 @@ 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.creditSharingTagNames = {
25
+ shareCredits: 'x-approve-payment',
26
+ sharedWincAmount: 'x-amount',
27
+ approvalExpiresBySeconds: 'x-expires-seconds',
28
+ revokeCredits: 'x-delete-payment-approval',
29
+ };
23
30
  exports.developmentUploadServiceURL = 'https://upload.ardrive.dev';
24
31
  exports.defaultUploadServiceURL = 'https://upload.ardrive.io';
25
32
  class TurboUnauthenticatedUploadService {
@@ -61,17 +68,25 @@ class TurboAuthenticatedBaseUploadService extends TurboUnauthenticatedUploadServ
61
68
  dataItemOpts,
62
69
  });
63
70
  const signedDataItem = dataItemStreamFactory();
64
- const fileSize = dataItemSizeFactory();
65
71
  this.logger.debug('Uploading signed data item...');
66
72
  // TODO: add p-limit constraint or replace with separate upload class
73
+ const headers = {
74
+ 'content-type': 'application/octet-stream',
75
+ 'content-length': `${dataItemSizeFactory()}`,
76
+ };
77
+ if (dataItemOpts !== undefined && dataItemOpts.paidBy !== undefined) {
78
+ const paidBy = Array.isArray(dataItemOpts.paidBy)
79
+ ? dataItemOpts.paidBy
80
+ : [dataItemOpts.paidBy];
81
+ if (dataItemOpts.paidBy.length > 0) {
82
+ headers['x-paid-by'] = paidBy;
83
+ }
84
+ }
67
85
  return this.httpService.post({
68
86
  endpoint: `/tx/${this.token}`,
69
87
  signal,
70
88
  data: signedDataItem,
71
- headers: {
72
- 'content-type': 'application/octet-stream',
73
- 'content-length': `${fileSize}`,
74
- },
89
+ headers,
75
90
  });
76
91
  }
77
92
  async generateManifest({ paths, indexFile, fallbackFile, }) {
@@ -182,5 +197,57 @@ class TurboAuthenticatedBaseUploadService extends TurboUnauthenticatedUploadServ
182
197
  manifestResponse,
183
198
  };
184
199
  }
200
+ async shareCredits({ approvedAddress, approvedWincAmount, expiresBySeconds, }) {
201
+ const dataItemOpts = {
202
+ tags: [
203
+ {
204
+ name: exports.creditSharingTagNames.shareCredits,
205
+ value: approvedAddress,
206
+ },
207
+ {
208
+ name: exports.creditSharingTagNames.sharedWincAmount,
209
+ value: approvedWincAmount.toString(),
210
+ },
211
+ ],
212
+ };
213
+ if (expiresBySeconds !== undefined) {
214
+ dataItemOpts.tags.push({
215
+ name: exports.creditSharingTagNames.approvalExpiresBySeconds,
216
+ value: expiresBySeconds.toString(),
217
+ });
218
+ }
219
+ const nonceData = node_buffer_1.Buffer.from(approvedAddress + approvedWincAmount + Date.now());
220
+ const { createdApproval, ...uploadResponse } = await this.uploadFile({
221
+ fileStreamFactory: () => node_stream_1.Readable.from(nonceData),
222
+ fileSizeFactory: () => nonceData.byteLength,
223
+ dataItemOpts,
224
+ });
225
+ if (!createdApproval) {
226
+ throw new Error('Failed to create credit share approval but upload has succeeded\n' +
227
+ JSON.stringify(uploadResponse));
228
+ }
229
+ return createdApproval;
230
+ }
231
+ async revokeCredits({ revokedAddress, }) {
232
+ const dataItemOpts = {
233
+ tags: [
234
+ {
235
+ name: exports.creditSharingTagNames.revokeCredits,
236
+ value: revokedAddress,
237
+ },
238
+ ],
239
+ };
240
+ const nonceData = node_buffer_1.Buffer.from(revokedAddress + Date.now());
241
+ const { revokedApprovals, ...uploadResponse } = await this.uploadFile({
242
+ fileStreamFactory: () => node_stream_1.Readable.from(nonceData),
243
+ fileSizeFactory: () => nonceData.byteLength,
244
+ dataItemOpts,
245
+ });
246
+ if (!revokedApprovals) {
247
+ throw new Error('Failed to revoke credit share approvals but upload has succeeded\n' +
248
+ JSON.stringify(uploadResponse));
249
+ }
250
+ return revokedApprovals;
251
+ }
185
252
  }
186
253
  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.2';
@@ -19,7 +19,10 @@
19
19
  import { program } from 'commander';
20
20
  import { version } from '../version.js';
21
21
  import { balance, cryptoFund, price, topUp, uploadFile, uploadFolder, } from './commands/index.js';
22
- import { globalOptions, optionMap, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
22
+ import { listShares } from './commands/listShares.js';
23
+ import { revokeCredits } from './commands/revokeCredits.js';
24
+ import { shareCredits } from './commands/shareCredits.js';
25
+ import { globalOptions, listSharesOptions, optionMap, revokeCreditsOptions, shareCreditsOptions, 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('share-credits')
54
+ .description('Create a Turbo credit share approval'), shareCreditsOptions).action(async (_commandOptions, command) => {
55
+ await runCommand(command, shareCredits);
56
+ });
57
+ applyOptions(program
58
+ .command('revoke-credits')
59
+ .description('Revokes all Turbo credit share approvals for given address'), revokeCreditsOptions).action(async (_commandOptions, command) => {
60
+ await runCommand(command, revokeCredits);
61
+ });
62
+ applyOptions(program
63
+ .command('list-shares')
64
+ .description('Lists all given or received Turbo credit share approvals for specified address or connected wallet'), listSharesOptions).action(async (_commandOptions, command) => {
65
+ await runCommand(command, listShares);
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
  }
@@ -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 listShares(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).getCreditShareApprovals({
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.getCreditShareApprovals();
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 ' : ''}` +
44
+ `Credit Share Approvals found 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 revokeCredits(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.revokeCredits({
9
+ revokedAddress,
10
+ });
11
+ console.log(JSON.stringify({ message: 'Revoked credit share approvals!', revokedApprovals }, null, 2));
12
+ }
@@ -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 shareCredits(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.shareCredits({
31
+ approvedAddress,
32
+ approvedWincAmount,
33
+ expiresBySeconds,
34
+ });
35
+ console.log(JSON.stringify({ message: 'Created credit share approval!', ...result }, null, 2));
36
+ }