@ardrive/turbo-sdk 1.33.1 → 1.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/bundles/web.bundle.min.js +103581 -103456
- package/lib/cjs/cli/cli.js +1 -1
- package/lib/cjs/cli/commands/cryptoFund.js +3 -1
- package/lib/cjs/common/payment.js +17 -4
- package/lib/cjs/common/signer.js +13 -1
- package/lib/cjs/common/token/ario.js +27 -19
- package/lib/cjs/common/token/arweave.js +4 -1
- package/lib/cjs/common/token/ethereum.js +32 -13
- package/lib/cjs/common/token/solana.js +11 -2
- package/lib/cjs/utils/common.js +52 -0
- package/lib/cjs/version.js +1 -1
- package/lib/esm/cli/cli.js +1 -1
- package/lib/esm/cli/commands/cryptoFund.js +3 -1
- package/lib/esm/common/payment.js +17 -4
- package/lib/esm/common/signer.js +14 -2
- package/lib/esm/common/token/ario.js +27 -19
- package/lib/esm/common/token/arweave.js +4 -1
- package/lib/esm/common/token/ethereum.js +32 -14
- package/lib/esm/common/token/solana.js +11 -2
- package/lib/esm/utils/common.js +47 -1
- package/lib/esm/version.js +1 -1
- package/lib/types/cli/commands/cryptoFund.d.ts.map +1 -1
- package/lib/types/cli/types.d.ts +1 -0
- package/lib/types/cli/types.d.ts.map +1 -1
- package/lib/types/common/payment.d.ts +1 -1
- package/lib/types/common/payment.d.ts.map +1 -1
- package/lib/types/common/signer.d.ts +1 -1
- package/lib/types/common/signer.d.ts.map +1 -1
- package/lib/types/common/token/ario.d.ts +1 -1
- package/lib/types/common/token/ario.d.ts.map +1 -1
- package/lib/types/common/token/arweave.d.ts +1 -1
- package/lib/types/common/token/arweave.d.ts.map +1 -1
- package/lib/types/common/token/ethereum.d.ts +3 -2
- package/lib/types/common/token/ethereum.d.ts.map +1 -1
- package/lib/types/common/token/solana.d.ts +2 -1
- package/lib/types/common/token/solana.d.ts.map +1 -1
- package/lib/types/types.d.ts +5 -0
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/utils/common.d.ts +6 -0
- package/lib/types/utils/common.d.ts.map +1 -1
- package/lib/types/version.d.ts +1 -1
- package/lib/types/version.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/cjs/cli/cli.js
CHANGED
|
@@ -41,7 +41,7 @@ const utils_js_1 = require("./utils.js");
|
|
|
41
41
|
(0, utils_js_1.applyOptions)(commander_1.program.command('top-up').description('Top up a Turbo address with Fiat'), [...options_js_1.walletOptions, options_js_1.optionMap.address, options_js_1.optionMap.value, options_js_1.optionMap.currency]).action(async (_commandOptions, command) => {
|
|
42
42
|
await (0, utils_js_1.runCommand)(command, index_js_1.topUp);
|
|
43
43
|
});
|
|
44
|
-
(0, utils_js_1.applyOptions)(commander_1.program.command('crypto-fund').description('Top up a wallet with crypto'), [...options_js_1.walletOptions, options_js_1.optionMap.value, options_js_1.optionMap.txId]).action(async (_commandOptions, command) => {
|
|
44
|
+
(0, utils_js_1.applyOptions)(commander_1.program.command('crypto-fund').description('Top up a wallet with crypto'), [...options_js_1.walletOptions, options_js_1.optionMap.value, options_js_1.optionMap.txId, options_js_1.optionMap.address]).action(async (_commandOptions, command) => {
|
|
45
45
|
await (0, utils_js_1.runCommand)(command, index_js_1.cryptoFund);
|
|
46
46
|
});
|
|
47
47
|
(0, utils_js_1.applyOptions)(commander_1.program.command('upload-folder').description('Upload a folder using Turbo'), options_js_1.uploadFolderOptions).action(async (_commandOptions, command) => {
|
|
@@ -28,6 +28,7 @@ const utils_js_1 = require("../utils.js");
|
|
|
28
28
|
async function cryptoFund(options) {
|
|
29
29
|
const value = options.value;
|
|
30
30
|
const txId = options.txId;
|
|
31
|
+
const address = options.address;
|
|
31
32
|
if (txId !== undefined) {
|
|
32
33
|
const turbo = factory_js_1.TurboFactory.unauthenticated((0, utils_js_1.configFromOptions)(options));
|
|
33
34
|
const result = await turbo.submitFundTransaction({ txId: txId });
|
|
@@ -47,7 +48,7 @@ async function cryptoFund(options) {
|
|
|
47
48
|
const { confirm } = await (0, prompts_1.default)({
|
|
48
49
|
type: 'confirm',
|
|
49
50
|
name: 'confirm',
|
|
50
|
-
message: `\nTransaction details:\n\n Amount: ${value} ${token}\n Target: ${targetWallet}\n Est Credits to receive: ${credits}\n Credit recipient: ${await turbo.signer.getNativeAddress()}\n Note: Network Dependent Gas Fees May Apply\n\nThis payment is non-refundable. Proceed with transaction?`,
|
|
51
|
+
message: `\nTransaction details:\n\n Amount: ${value} ${token}\n Target: ${targetWallet}\n Est Credits to receive: ${credits}\n Credit recipient: ${address ?? (await turbo.signer.getNativeAddress())}\n Note: Network Dependent Gas Fees May Apply\n\nThis payment is non-refundable. Proceed with transaction?`,
|
|
51
52
|
initial: true,
|
|
52
53
|
});
|
|
53
54
|
if (!confirm) {
|
|
@@ -57,6 +58,7 @@ async function cryptoFund(options) {
|
|
|
57
58
|
}
|
|
58
59
|
const result = await turbo.topUpWithTokens({
|
|
59
60
|
tokenAmount,
|
|
61
|
+
turboCreditDestinationAddress: address,
|
|
60
62
|
});
|
|
61
63
|
console.log('Sent crypto fund transaction: \n', JSON.stringify(result, null, 2));
|
|
62
64
|
}
|
|
@@ -18,6 +18,7 @@ exports.TurboAuthenticatedPaymentService = exports.TurboUnauthenticatedPaymentSe
|
|
|
18
18
|
*/
|
|
19
19
|
const bignumber_js_1 = require("bignumber.js");
|
|
20
20
|
const axiosClient_js_1 = require("../utils/axiosClient.js");
|
|
21
|
+
const common_js_1 = require("../utils/common.js");
|
|
21
22
|
const http_js_1 = require("./http.js");
|
|
22
23
|
const logger_js_1 = require("./logger.js");
|
|
23
24
|
const index_js_1 = require("./token/index.js");
|
|
@@ -151,31 +152,37 @@ class TurboUnauthenticatedPaymentService {
|
|
|
151
152
|
return {
|
|
152
153
|
id: response.creditedTransaction.transactionId,
|
|
153
154
|
quantity: response.creditedTransaction.transactionQuantity,
|
|
154
|
-
owner: response.creditedTransaction.
|
|
155
|
+
owner: response.creditedTransaction.transactionSenderAddress ??
|
|
156
|
+
response.creditedTransaction.destinationAddress,
|
|
155
157
|
winc: response.creditedTransaction.winstonCreditAmount,
|
|
156
158
|
token: response.creditedTransaction.tokenType,
|
|
157
159
|
status: 'confirmed',
|
|
158
160
|
block: response.creditedTransaction.blockHeight,
|
|
161
|
+
recipient: response.creditedTransaction.destinationAddress,
|
|
159
162
|
};
|
|
160
163
|
}
|
|
161
164
|
else if ('pendingTransaction' in response) {
|
|
162
165
|
return {
|
|
163
166
|
id: response.pendingTransaction.transactionId,
|
|
164
167
|
quantity: response.pendingTransaction.transactionQuantity,
|
|
165
|
-
owner: response.pendingTransaction.
|
|
168
|
+
owner: response.pendingTransaction.transactionSenderAddress ??
|
|
169
|
+
response.pendingTransaction.destinationAddress,
|
|
166
170
|
winc: response.pendingTransaction.winstonCreditAmount,
|
|
167
171
|
token: response.pendingTransaction.tokenType,
|
|
168
172
|
status: 'pending',
|
|
173
|
+
recipient: response.pendingTransaction.destinationAddress,
|
|
169
174
|
};
|
|
170
175
|
}
|
|
171
176
|
else if ('failedTransaction' in response) {
|
|
172
177
|
return {
|
|
173
178
|
id: response.failedTransaction.transactionId,
|
|
174
179
|
quantity: response.failedTransaction.transactionQuantity,
|
|
175
|
-
owner: response.failedTransaction.
|
|
180
|
+
owner: response.failedTransaction.transactionSenderAddress ??
|
|
181
|
+
response.failedTransaction.destinationAddress,
|
|
176
182
|
winc: response.failedTransaction.winstonCreditAmount,
|
|
177
183
|
token: response.failedTransaction.tokenType,
|
|
178
184
|
status: 'failed',
|
|
185
|
+
recipient: response.failedTransaction.destinationAddress,
|
|
179
186
|
};
|
|
180
187
|
}
|
|
181
188
|
throw new Error('Unknown response from payment service: ' + response);
|
|
@@ -271,10 +278,15 @@ class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymentServic
|
|
|
271
278
|
}
|
|
272
279
|
return walletAddress;
|
|
273
280
|
}
|
|
274
|
-
async topUpWithTokens({ feeMultiplier = 1, tokenAmount: tokenAmountV, }) {
|
|
281
|
+
async topUpWithTokens({ feeMultiplier = 1, tokenAmount: tokenAmountV, turboCreditDestinationAddress, }) {
|
|
275
282
|
if (!this.tokenTools) {
|
|
276
283
|
throw new Error(`Token type not supported for crypto fund ${this.token}`);
|
|
277
284
|
}
|
|
285
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
286
|
+
if ((0, common_js_1.isAnyValidUserAddress)(turboCreditDestinationAddress) === false) {
|
|
287
|
+
throw new Error(`Invalid turboCreditDestinationAddress provided: ${turboCreditDestinationAddress}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
278
290
|
const tokenAmount = new bignumber_js_1.BigNumber(tokenAmountV);
|
|
279
291
|
const target = await this.getTargetWalletForFund();
|
|
280
292
|
this.logger.debug('Funding account...', {
|
|
@@ -287,6 +299,7 @@ class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymentServic
|
|
|
287
299
|
tokenAmount,
|
|
288
300
|
feeMultiplier,
|
|
289
301
|
signer: this.signer,
|
|
302
|
+
turboCreditDestinationAddress,
|
|
290
303
|
});
|
|
291
304
|
const txId = fundTx.id;
|
|
292
305
|
try {
|
package/lib/cjs/common/signer.js
CHANGED
|
@@ -34,6 +34,8 @@ const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
|
34
34
|
const types_js_1 = require("../types.js");
|
|
35
35
|
const base64_js_1 = require("../utils/base64.js");
|
|
36
36
|
const logger_js_1 = require("./logger.js");
|
|
37
|
+
const ethereum_js_1 = require("./token/ethereum.js");
|
|
38
|
+
const solana_js_1 = require("./token/solana.js");
|
|
37
39
|
/**
|
|
38
40
|
* Abstract class for signing TurboDataItems.
|
|
39
41
|
*/
|
|
@@ -81,7 +83,7 @@ class TurboDataItemAbstractSigner {
|
|
|
81
83
|
return this.ownerToNativeAddress((0, base64_js_1.toB64Url)(await this.getPublicKey()), this.token);
|
|
82
84
|
}
|
|
83
85
|
/** Let the signer handle sending tx for better compat with cross chain libraries/web wallets */
|
|
84
|
-
async sendTransaction({ target, amount, gatewayUrl, }) {
|
|
86
|
+
async sendTransaction({ target, amount, gatewayUrl, turboCreditDestinationAddress, }) {
|
|
85
87
|
if (this.walletAdapter) {
|
|
86
88
|
if ((0, types_js_1.isSolanaWalletAdapter)(this.walletAdapter)) {
|
|
87
89
|
const connection = new web3_js_1.Connection(gatewayUrl, 'confirmed');
|
|
@@ -95,6 +97,14 @@ class TurboDataItemAbstractSigner {
|
|
|
95
97
|
toPubkey: new web3_js_1.PublicKey(target),
|
|
96
98
|
lamports: +new bignumber_js_1.BigNumber(amount),
|
|
97
99
|
}));
|
|
100
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
101
|
+
tx.add(new web3_js_1.TransactionInstruction({
|
|
102
|
+
programId: new web3_js_1.PublicKey(solana_js_1.memoProgramId),
|
|
103
|
+
keys: [],
|
|
104
|
+
data: Buffer.from('turboCreditDestinationAddress=' +
|
|
105
|
+
turboCreditDestinationAddress),
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
98
108
|
const signedTx = await this.walletAdapter.signTransaction(tx);
|
|
99
109
|
const id = await connection.sendRawTransaction(signedTx.serialize());
|
|
100
110
|
return id;
|
|
@@ -109,6 +119,7 @@ class TurboDataItemAbstractSigner {
|
|
|
109
119
|
const { hash } = await signer.sendTransaction({
|
|
110
120
|
to: target,
|
|
111
121
|
value: (0, ethers_1.parseEther)(amount.toFixed(18)),
|
|
122
|
+
data: (0, ethereum_js_1.ethDataFromTurboCreditDestinationAddress)(turboCreditDestinationAddress),
|
|
112
123
|
});
|
|
113
124
|
return hash;
|
|
114
125
|
}
|
|
@@ -121,6 +132,7 @@ class TurboDataItemAbstractSigner {
|
|
|
121
132
|
const tx = await ethWalletAndProvider.sendTransaction({
|
|
122
133
|
to: target,
|
|
123
134
|
value: (0, ethers_1.parseEther)(amount.toFixed(18)),
|
|
135
|
+
data: (0, ethereum_js_1.ethDataFromTurboCreditDestinationAddress)(turboCreditDestinationAddress),
|
|
124
136
|
});
|
|
125
137
|
this.logger.debug('Sent transaction', { tx });
|
|
126
138
|
return tx.hash;
|
|
@@ -35,34 +35,42 @@ class ARIOToken {
|
|
|
35
35
|
this.pollingOptions = pollingOptions;
|
|
36
36
|
this.logger = logger;
|
|
37
37
|
}
|
|
38
|
-
async createAndSubmitTx({ target, signer: { signer }, tokenAmount, }) {
|
|
38
|
+
async createAndSubmitTx({ target, signer: { signer }, tokenAmount, turboCreditDestinationAddress, }) {
|
|
39
|
+
const tags = [
|
|
40
|
+
{
|
|
41
|
+
name: 'Action',
|
|
42
|
+
value: 'Transfer',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Recipient',
|
|
46
|
+
value: target,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Quantity',
|
|
50
|
+
value: tokenAmount.toString(),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Turbo-SDK',
|
|
54
|
+
value: version_js_1.version,
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
58
|
+
tags.push({
|
|
59
|
+
name: 'Turbo-Credit-Destination-Address',
|
|
60
|
+
value: turboCreditDestinationAddress,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
39
63
|
const txId = await this.ao.message({
|
|
40
64
|
signer: createAoSigner(signer),
|
|
41
65
|
process: this.processId,
|
|
42
|
-
tags
|
|
43
|
-
{
|
|
44
|
-
name: 'Action',
|
|
45
|
-
value: 'Transfer',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: 'Recipient',
|
|
49
|
-
value: target,
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: 'Quantity',
|
|
53
|
-
value: tokenAmount.toString(),
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: 'Turbo-SDK',
|
|
57
|
-
value: version_js_1.version,
|
|
58
|
-
},
|
|
59
|
-
],
|
|
66
|
+
tags,
|
|
60
67
|
});
|
|
61
68
|
this.logger.debug('Submitted Transfer message to ARIO process...', {
|
|
62
69
|
id: txId,
|
|
63
70
|
target,
|
|
64
71
|
tokenAmount,
|
|
65
72
|
processId: this.processId,
|
|
73
|
+
tags,
|
|
66
74
|
});
|
|
67
75
|
return { id: txId, target, reward: '0' };
|
|
68
76
|
}
|
|
@@ -46,7 +46,7 @@ class ArweaveToken {
|
|
|
46
46
|
this.mintU = mintU;
|
|
47
47
|
this.pollingOptions = pollingOptions;
|
|
48
48
|
}
|
|
49
|
-
async createAndSubmitTx({ feeMultiplier, target, tokenAmount, signer, }) {
|
|
49
|
+
async createAndSubmitTx({ feeMultiplier, target, tokenAmount, signer, turboCreditDestinationAddress, }) {
|
|
50
50
|
const tx = await this.arweave.createTransaction({
|
|
51
51
|
target,
|
|
52
52
|
quantity: tokenAmount.toString(),
|
|
@@ -63,6 +63,9 @@ class ArweaveToken {
|
|
|
63
63
|
tx.addTag('Contract', 'KTzTXT_ANmF84fWEKHzWURD1LWd9QaFR9yfYUwH2Lxw'); // cspell:enable
|
|
64
64
|
tx.addTag('Input', JSON.stringify({ function: 'mint' }));
|
|
65
65
|
}
|
|
66
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
67
|
+
tx.addTag('Turbo-Credit-Destination-Address', turboCreditDestinationAddress);
|
|
68
|
+
}
|
|
66
69
|
const publicKeyB64Url = (0, base64_js_1.toB64Url)(await signer.getPublicKey());
|
|
67
70
|
tx.setOwner(publicKeyB64Url);
|
|
68
71
|
const dataToSign = await tx.getSignatureData();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EthereumToken = exports.ETHToTokenAmount = exports.weiToTokenAmount = void 0;
|
|
4
|
+
exports.ethDataFromTurboCreditDestinationAddress = ethDataFromTurboCreditDestinationAddress;
|
|
4
5
|
/**
|
|
5
6
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
6
7
|
*
|
|
@@ -28,25 +29,37 @@ class EthereumToken {
|
|
|
28
29
|
constructor({ logger = logger_js_1.TurboWinstonLogger.default, gatewayUrl = common_js_1.defaultProdGatewayUrls.ethereum, pollingOptions = {
|
|
29
30
|
maxAttempts: 10,
|
|
30
31
|
pollingIntervalMs: 4_000,
|
|
31
|
-
initialBackoffMs:
|
|
32
|
+
initialBackoffMs: 25_000,
|
|
32
33
|
}, } = {}) {
|
|
33
34
|
this.logger = logger;
|
|
34
35
|
this.gatewayUrl = gatewayUrl;
|
|
35
36
|
this.pollingOptions = pollingOptions;
|
|
36
37
|
this.rpcProvider = new ethers_1.ethers.JsonRpcProvider(gatewayUrl);
|
|
37
38
|
}
|
|
38
|
-
async createAndSubmitTx({ target, tokenAmount, signer, }) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
39
|
+
async createAndSubmitTx({ target, tokenAmount, signer, turboCreditDestinationAddress, }) {
|
|
40
|
+
try {
|
|
41
|
+
// convert wei to eth
|
|
42
|
+
const eth = tokenAmount.shiftedBy(-18);
|
|
43
|
+
const txId = await signer.sendTransaction({
|
|
44
|
+
target,
|
|
45
|
+
amount: eth,
|
|
46
|
+
gatewayUrl: this.gatewayUrl,
|
|
47
|
+
turboCreditDestinationAddress,
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
id: txId,
|
|
51
|
+
target,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
this.logger.error('Error creating and submitting Ethereum tx', {
|
|
56
|
+
error: e instanceof Error ? e.message : e,
|
|
57
|
+
target,
|
|
58
|
+
tokenAmount,
|
|
59
|
+
rpcEndpoint: this.gatewayUrl,
|
|
60
|
+
});
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
50
63
|
}
|
|
51
64
|
async getTxAvailability(txId) {
|
|
52
65
|
const tx = await this.rpcProvider.getTransaction(txId);
|
|
@@ -77,3 +90,9 @@ class EthereumToken {
|
|
|
77
90
|
}
|
|
78
91
|
}
|
|
79
92
|
exports.EthereumToken = EthereumToken;
|
|
93
|
+
function ethDataFromTurboCreditDestinationAddress(turboCreditDestinationAddress) {
|
|
94
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
95
|
+
return (0, ethers_1.hexlify)((0, ethers_1.toUtf8Bytes)('turboCreditDestinationAddress=' + turboCreditDestinationAddress));
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SolanaToken = exports.SOLToTokenAmount = exports.lamportToTokenAmount = void 0;
|
|
6
|
+
exports.SolanaToken = exports.memoProgramId = exports.SOLToTokenAmount = exports.lamportToTokenAmount = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
9
9
|
*
|
|
@@ -30,6 +30,7 @@ const lamportToTokenAmount = (winston) => winston;
|
|
|
30
30
|
exports.lamportToTokenAmount = lamportToTokenAmount;
|
|
31
31
|
const SOLToTokenAmount = (sol) => new bignumber_js_1.BigNumber(sol).times(1e9).valueOf();
|
|
32
32
|
exports.SOLToTokenAmount = SOLToTokenAmount;
|
|
33
|
+
exports.memoProgramId = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
|
|
33
34
|
class SolanaToken {
|
|
34
35
|
constructor({ logger = logger_js_1.TurboWinstonLogger.default, gatewayUrl = common_js_1.defaultProdGatewayUrls.solana, pollingOptions = {
|
|
35
36
|
maxAttempts: 10,
|
|
@@ -41,12 +42,13 @@ class SolanaToken {
|
|
|
41
42
|
this.connection = new web3_js_1.Connection(gatewayUrl, 'confirmed');
|
|
42
43
|
this.pollingOptions = pollingOptions;
|
|
43
44
|
}
|
|
44
|
-
async createAndSubmitTx({ target, tokenAmount, signer, }) {
|
|
45
|
+
async createAndSubmitTx({ target, tokenAmount, signer, turboCreditDestinationAddress, }) {
|
|
45
46
|
if (signer.signer instanceof arbundles_1.HexInjectedSolanaSigner) {
|
|
46
47
|
const id = await signer.sendTransaction({
|
|
47
48
|
amount: tokenAmount,
|
|
48
49
|
target,
|
|
49
50
|
gatewayUrl: this.gatewayUrl,
|
|
51
|
+
turboCreditDestinationAddress,
|
|
50
52
|
});
|
|
51
53
|
return { target, id };
|
|
52
54
|
}
|
|
@@ -60,6 +62,13 @@ class SolanaToken {
|
|
|
60
62
|
toPubkey: new web3_js_1.PublicKey(target),
|
|
61
63
|
lamports: +new bignumber_js_1.BigNumber(tokenAmount),
|
|
62
64
|
}));
|
|
65
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
66
|
+
tx.add(new web3_js_1.TransactionInstruction({
|
|
67
|
+
programId: new web3_js_1.PublicKey(exports.memoProgramId),
|
|
68
|
+
keys: [],
|
|
69
|
+
data: Buffer.from('turboCreditDestinationAddress=' + turboCreditDestinationAddress),
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
63
72
|
const serializedTx = tx.serializeMessage();
|
|
64
73
|
const signature = await signer.signData(Uint8Array.from(serializedTx));
|
|
65
74
|
tx.addSignature(publicKey, Buffer.from(signature));
|
package/lib/cjs/utils/common.js
CHANGED
|
@@ -7,6 +7,12 @@ exports.createTurboSigner = createTurboSigner;
|
|
|
7
7
|
exports.signerFromKyvePrivateKey = signerFromKyvePrivateKey;
|
|
8
8
|
exports.signerFromKyveMnemonic = signerFromKyveMnemonic;
|
|
9
9
|
exports.isBlob = isBlob;
|
|
10
|
+
exports.isValidArweaveBase64URL = isValidArweaveBase64URL;
|
|
11
|
+
exports.isValidSolanaAddress = isValidSolanaAddress;
|
|
12
|
+
exports.isValidECDSAAddress = isValidECDSAAddress;
|
|
13
|
+
exports.isValidKyveAddress = isValidKyveAddress;
|
|
14
|
+
exports.isValidUserAddress = isValidUserAddress;
|
|
15
|
+
exports.isAnyValidUserAddress = isAnyValidUserAddress;
|
|
10
16
|
/**
|
|
11
17
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
12
18
|
*
|
|
@@ -28,6 +34,7 @@ const encoding_1 = require("@cosmjs/encoding");
|
|
|
28
34
|
const arbundles_1 = require("@dha-team/arbundles");
|
|
29
35
|
const bytes_1 = require("@ethersproject/bytes");
|
|
30
36
|
const signing_key_1 = require("@ethersproject/signing-key");
|
|
37
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
31
38
|
const ethers_1 = require("ethers");
|
|
32
39
|
const types_js_1 = require("../types.js");
|
|
33
40
|
function sleep(ms) {
|
|
@@ -123,3 +130,48 @@ async function signerFromKyveMnemonic(mnemonic) {
|
|
|
123
130
|
function isBlob(val) {
|
|
124
131
|
return typeof Blob !== 'undefined' && val instanceof Blob;
|
|
125
132
|
}
|
|
133
|
+
// check if it is a valid arweave base64url for a wallet public address, transaction id or smartweave contract
|
|
134
|
+
function isValidArweaveBase64URL(base64URL) {
|
|
135
|
+
const base64URLRegex = new RegExp('^[a-zA-Z0-9_-]{43}$');
|
|
136
|
+
return base64URLRegex.test(base64URL);
|
|
137
|
+
}
|
|
138
|
+
function isValidSolanaAddress(address) {
|
|
139
|
+
try {
|
|
140
|
+
return web3_js_1.PublicKey.isOnCurve(address);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function isValidECDSAAddress(address) {
|
|
147
|
+
const ethAddressRegex = new RegExp('^0x[a-fA-F0-9]{40}$');
|
|
148
|
+
return ethAddressRegex.test(address);
|
|
149
|
+
}
|
|
150
|
+
function isValidKyveAddress(address) {
|
|
151
|
+
const kyveAddressRegex = new RegExp('^kyve[a-zA-Z0-9]{39}$');
|
|
152
|
+
return kyveAddressRegex.test(address);
|
|
153
|
+
}
|
|
154
|
+
function isValidUserAddress(address, type) {
|
|
155
|
+
switch (type) {
|
|
156
|
+
case 'arweave':
|
|
157
|
+
case 'ario':
|
|
158
|
+
return isValidArweaveBase64URL(address);
|
|
159
|
+
case 'solana':
|
|
160
|
+
return isValidSolanaAddress(address);
|
|
161
|
+
case 'ethereum':
|
|
162
|
+
case 'base-eth':
|
|
163
|
+
case 'matic':
|
|
164
|
+
case 'pol':
|
|
165
|
+
return isValidECDSAAddress(address);
|
|
166
|
+
case 'kyve':
|
|
167
|
+
return isValidKyveAddress(address);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function isAnyValidUserAddress(address) {
|
|
171
|
+
for (const type of types_js_1.tokenTypes) {
|
|
172
|
+
if (isValidUserAddress(address, type)) {
|
|
173
|
+
return type;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
package/lib/cjs/version.js
CHANGED
package/lib/esm/cli/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ applyOptions(program.command('balance').description('Get balance of a Turbo addr
|
|
|
39
39
|
applyOptions(program.command('top-up').description('Top up a Turbo address with Fiat'), [...walletOptions, optionMap.address, optionMap.value, optionMap.currency]).action(async (_commandOptions, command) => {
|
|
40
40
|
await runCommand(command, topUp);
|
|
41
41
|
});
|
|
42
|
-
applyOptions(program.command('crypto-fund').description('Top up a wallet with crypto'), [...walletOptions, optionMap.value, optionMap.txId]).action(async (_commandOptions, command) => {
|
|
42
|
+
applyOptions(program.command('crypto-fund').description('Top up a wallet with crypto'), [...walletOptions, optionMap.value, optionMap.txId, optionMap.address]).action(async (_commandOptions, command) => {
|
|
43
43
|
await runCommand(command, cryptoFund);
|
|
44
44
|
});
|
|
45
45
|
applyOptions(program.command('upload-folder').description('Upload a folder using Turbo'), uploadFolderOptions).action(async (_commandOptions, command) => {
|
|
@@ -22,6 +22,7 @@ import { configFromOptions, tokenFromOptions, turboFromOptions, } from '../utils
|
|
|
22
22
|
export async function cryptoFund(options) {
|
|
23
23
|
const value = options.value;
|
|
24
24
|
const txId = options.txId;
|
|
25
|
+
const address = options.address;
|
|
25
26
|
if (txId !== undefined) {
|
|
26
27
|
const turbo = TurboFactory.unauthenticated(configFromOptions(options));
|
|
27
28
|
const result = await turbo.submitFundTransaction({ txId: txId });
|
|
@@ -41,7 +42,7 @@ export async function cryptoFund(options) {
|
|
|
41
42
|
const { confirm } = await prompts({
|
|
42
43
|
type: 'confirm',
|
|
43
44
|
name: 'confirm',
|
|
44
|
-
message: `\nTransaction details:\n\n Amount: ${value} ${token}\n Target: ${targetWallet}\n Est Credits to receive: ${credits}\n Credit recipient: ${await turbo.signer.getNativeAddress()}\n Note: Network Dependent Gas Fees May Apply\n\nThis payment is non-refundable. Proceed with transaction?`,
|
|
45
|
+
message: `\nTransaction details:\n\n Amount: ${value} ${token}\n Target: ${targetWallet}\n Est Credits to receive: ${credits}\n Credit recipient: ${address ?? (await turbo.signer.getNativeAddress())}\n Note: Network Dependent Gas Fees May Apply\n\nThis payment is non-refundable. Proceed with transaction?`,
|
|
45
46
|
initial: true,
|
|
46
47
|
});
|
|
47
48
|
if (!confirm) {
|
|
@@ -51,6 +52,7 @@ export async function cryptoFund(options) {
|
|
|
51
52
|
}
|
|
52
53
|
const result = await turbo.topUpWithTokens({
|
|
53
54
|
tokenAmount,
|
|
55
|
+
turboCreditDestinationAddress: address,
|
|
54
56
|
});
|
|
55
57
|
console.log('Sent crypto fund transaction: \n', JSON.stringify(result, null, 2));
|
|
56
58
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { BigNumber } from 'bignumber.js';
|
|
17
17
|
import { defaultRetryConfig } from '../utils/axiosClient.js';
|
|
18
|
+
import { isAnyValidUserAddress } from '../utils/common.js';
|
|
18
19
|
import { TurboHTTPService } from './http.js';
|
|
19
20
|
import { TurboWinstonLogger } from './logger.js';
|
|
20
21
|
import { exponentMap, tokenToBaseMap } from './token/index.js';
|
|
@@ -148,31 +149,37 @@ export class TurboUnauthenticatedPaymentService {
|
|
|
148
149
|
return {
|
|
149
150
|
id: response.creditedTransaction.transactionId,
|
|
150
151
|
quantity: response.creditedTransaction.transactionQuantity,
|
|
151
|
-
owner: response.creditedTransaction.
|
|
152
|
+
owner: response.creditedTransaction.transactionSenderAddress ??
|
|
153
|
+
response.creditedTransaction.destinationAddress,
|
|
152
154
|
winc: response.creditedTransaction.winstonCreditAmount,
|
|
153
155
|
token: response.creditedTransaction.tokenType,
|
|
154
156
|
status: 'confirmed',
|
|
155
157
|
block: response.creditedTransaction.blockHeight,
|
|
158
|
+
recipient: response.creditedTransaction.destinationAddress,
|
|
156
159
|
};
|
|
157
160
|
}
|
|
158
161
|
else if ('pendingTransaction' in response) {
|
|
159
162
|
return {
|
|
160
163
|
id: response.pendingTransaction.transactionId,
|
|
161
164
|
quantity: response.pendingTransaction.transactionQuantity,
|
|
162
|
-
owner: response.pendingTransaction.
|
|
165
|
+
owner: response.pendingTransaction.transactionSenderAddress ??
|
|
166
|
+
response.pendingTransaction.destinationAddress,
|
|
163
167
|
winc: response.pendingTransaction.winstonCreditAmount,
|
|
164
168
|
token: response.pendingTransaction.tokenType,
|
|
165
169
|
status: 'pending',
|
|
170
|
+
recipient: response.pendingTransaction.destinationAddress,
|
|
166
171
|
};
|
|
167
172
|
}
|
|
168
173
|
else if ('failedTransaction' in response) {
|
|
169
174
|
return {
|
|
170
175
|
id: response.failedTransaction.transactionId,
|
|
171
176
|
quantity: response.failedTransaction.transactionQuantity,
|
|
172
|
-
owner: response.failedTransaction.
|
|
177
|
+
owner: response.failedTransaction.transactionSenderAddress ??
|
|
178
|
+
response.failedTransaction.destinationAddress,
|
|
173
179
|
winc: response.failedTransaction.winstonCreditAmount,
|
|
174
180
|
token: response.failedTransaction.tokenType,
|
|
175
181
|
status: 'failed',
|
|
182
|
+
recipient: response.failedTransaction.destinationAddress,
|
|
176
183
|
};
|
|
177
184
|
}
|
|
178
185
|
throw new Error('Unknown response from payment service: ' + response);
|
|
@@ -267,10 +274,15 @@ export class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymen
|
|
|
267
274
|
}
|
|
268
275
|
return walletAddress;
|
|
269
276
|
}
|
|
270
|
-
async topUpWithTokens({ feeMultiplier = 1, tokenAmount: tokenAmountV, }) {
|
|
277
|
+
async topUpWithTokens({ feeMultiplier = 1, tokenAmount: tokenAmountV, turboCreditDestinationAddress, }) {
|
|
271
278
|
if (!this.tokenTools) {
|
|
272
279
|
throw new Error(`Token type not supported for crypto fund ${this.token}`);
|
|
273
280
|
}
|
|
281
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
282
|
+
if (isAnyValidUserAddress(turboCreditDestinationAddress) === false) {
|
|
283
|
+
throw new Error(`Invalid turboCreditDestinationAddress provided: ${turboCreditDestinationAddress}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
274
286
|
const tokenAmount = new BigNumber(tokenAmountV);
|
|
275
287
|
const target = await this.getTargetWalletForFund();
|
|
276
288
|
this.logger.debug('Funding account...', {
|
|
@@ -283,6 +295,7 @@ export class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymen
|
|
|
283
295
|
tokenAmount,
|
|
284
296
|
feeMultiplier,
|
|
285
297
|
signer: this.signer,
|
|
298
|
+
turboCreditDestinationAddress,
|
|
286
299
|
});
|
|
287
300
|
const txId = fundTx.id;
|
|
288
301
|
try {
|
package/lib/esm/common/signer.js
CHANGED
|
@@ -18,7 +18,7 @@ import { Secp256k1 } from '@cosmjs/crypto';
|
|
|
18
18
|
import { toBase64 } from '@cosmjs/encoding';
|
|
19
19
|
import { EthereumSigner, HexSolanaSigner } from '@dha-team/arbundles';
|
|
20
20
|
import { computePublicKey } from '@ethersproject/signing-key';
|
|
21
|
-
import { Connection, PublicKey, SystemProgram, Transaction, } from '@solana/web3.js';
|
|
21
|
+
import { Connection, PublicKey, SystemProgram, Transaction, TransactionInstruction, } from '@solana/web3.js';
|
|
22
22
|
import { BigNumber } from 'bignumber.js';
|
|
23
23
|
import bs58 from 'bs58';
|
|
24
24
|
import { randomBytes } from 'crypto';
|
|
@@ -28,6 +28,8 @@ import nacl from 'tweetnacl';
|
|
|
28
28
|
import { isEthereumWalletAdapter, isSolanaWalletAdapter, } from '../types.js';
|
|
29
29
|
import { fromB64Url, ownerToAddress as ownerToB64Address, toB64Url, } from '../utils/base64.js';
|
|
30
30
|
import { TurboWinstonLogger } from './logger.js';
|
|
31
|
+
import { ethDataFromTurboCreditDestinationAddress } from './token/ethereum.js';
|
|
32
|
+
import { memoProgramId } from './token/solana.js';
|
|
31
33
|
/**
|
|
32
34
|
* Abstract class for signing TurboDataItems.
|
|
33
35
|
*/
|
|
@@ -75,7 +77,7 @@ export class TurboDataItemAbstractSigner {
|
|
|
75
77
|
return this.ownerToNativeAddress(toB64Url(await this.getPublicKey()), this.token);
|
|
76
78
|
}
|
|
77
79
|
/** Let the signer handle sending tx for better compat with cross chain libraries/web wallets */
|
|
78
|
-
async sendTransaction({ target, amount, gatewayUrl, }) {
|
|
80
|
+
async sendTransaction({ target, amount, gatewayUrl, turboCreditDestinationAddress, }) {
|
|
79
81
|
if (this.walletAdapter) {
|
|
80
82
|
if (isSolanaWalletAdapter(this.walletAdapter)) {
|
|
81
83
|
const connection = new Connection(gatewayUrl, 'confirmed');
|
|
@@ -89,6 +91,14 @@ export class TurboDataItemAbstractSigner {
|
|
|
89
91
|
toPubkey: new PublicKey(target),
|
|
90
92
|
lamports: +new BigNumber(amount),
|
|
91
93
|
}));
|
|
94
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
95
|
+
tx.add(new TransactionInstruction({
|
|
96
|
+
programId: new PublicKey(memoProgramId),
|
|
97
|
+
keys: [],
|
|
98
|
+
data: Buffer.from('turboCreditDestinationAddress=' +
|
|
99
|
+
turboCreditDestinationAddress),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
92
102
|
const signedTx = await this.walletAdapter.signTransaction(tx);
|
|
93
103
|
const id = await connection.sendRawTransaction(signedTx.serialize());
|
|
94
104
|
return id;
|
|
@@ -103,6 +113,7 @@ export class TurboDataItemAbstractSigner {
|
|
|
103
113
|
const { hash } = await signer.sendTransaction({
|
|
104
114
|
to: target,
|
|
105
115
|
value: parseEther(amount.toFixed(18)),
|
|
116
|
+
data: ethDataFromTurboCreditDestinationAddress(turboCreditDestinationAddress),
|
|
106
117
|
});
|
|
107
118
|
return hash;
|
|
108
119
|
}
|
|
@@ -115,6 +126,7 @@ export class TurboDataItemAbstractSigner {
|
|
|
115
126
|
const tx = await ethWalletAndProvider.sendTransaction({
|
|
116
127
|
to: target,
|
|
117
128
|
value: parseEther(amount.toFixed(18)),
|
|
129
|
+
data: ethDataFromTurboCreditDestinationAddress(turboCreditDestinationAddress),
|
|
118
130
|
});
|
|
119
131
|
this.logger.debug('Sent transaction', { tx });
|
|
120
132
|
return tx.hash;
|
|
@@ -32,34 +32,42 @@ export class ARIOToken {
|
|
|
32
32
|
this.pollingOptions = pollingOptions;
|
|
33
33
|
this.logger = logger;
|
|
34
34
|
}
|
|
35
|
-
async createAndSubmitTx({ target, signer: { signer }, tokenAmount, }) {
|
|
35
|
+
async createAndSubmitTx({ target, signer: { signer }, tokenAmount, turboCreditDestinationAddress, }) {
|
|
36
|
+
const tags = [
|
|
37
|
+
{
|
|
38
|
+
name: 'Action',
|
|
39
|
+
value: 'Transfer',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Recipient',
|
|
43
|
+
value: target,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'Quantity',
|
|
47
|
+
value: tokenAmount.toString(),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Turbo-SDK',
|
|
51
|
+
value: version,
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
if (turboCreditDestinationAddress !== undefined) {
|
|
55
|
+
tags.push({
|
|
56
|
+
name: 'Turbo-Credit-Destination-Address',
|
|
57
|
+
value: turboCreditDestinationAddress,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
36
60
|
const txId = await this.ao.message({
|
|
37
61
|
signer: createAoSigner(signer),
|
|
38
62
|
process: this.processId,
|
|
39
|
-
tags
|
|
40
|
-
{
|
|
41
|
-
name: 'Action',
|
|
42
|
-
value: 'Transfer',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'Recipient',
|
|
46
|
-
value: target,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: 'Quantity',
|
|
50
|
-
value: tokenAmount.toString(),
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'Turbo-SDK',
|
|
54
|
-
value: version,
|
|
55
|
-
},
|
|
56
|
-
],
|
|
63
|
+
tags,
|
|
57
64
|
});
|
|
58
65
|
this.logger.debug('Submitted Transfer message to ARIO process...', {
|
|
59
66
|
id: txId,
|
|
60
67
|
target,
|
|
61
68
|
tokenAmount,
|
|
62
69
|
processId: this.processId,
|
|
70
|
+
tags,
|
|
63
71
|
});
|
|
64
72
|
return { id: txId, target, reward: '0' };
|
|
65
73
|
}
|