@ledgerhq/coin-solana 0.12.0 → 0.12.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 (104) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/CHANGELOG.md +14 -0
  3. package/lib/api/chain/index.js +15 -20
  4. package/lib/api/chain/index.js.map +1 -1
  5. package/lib/api/chain/program/parser.js +20 -5
  6. package/lib/api/chain/program/parser.js.map +1 -1
  7. package/lib/api/chain/stake-activation/rpc.js +40 -51
  8. package/lib/api/chain/stake-activation/rpc.js.map +1 -1
  9. package/lib/api/chain/web3.js +136 -211
  10. package/lib/api/chain/web3.js.map +1 -1
  11. package/lib/api/traced.js +1 -1
  12. package/lib/api/traced.js.map +1 -1
  13. package/lib/bridge/bridge.js +14 -24
  14. package/lib/bridge/bridge.js.map +1 -1
  15. package/lib/bridge/js.js +3 -3
  16. package/lib/bridge/js.js.map +1 -1
  17. package/lib/bridge.integration.test.js +133 -65
  18. package/lib/bridge.integration.test.js.map +1 -1
  19. package/lib/broadcast.js +3 -12
  20. package/lib/broadcast.js.map +1 -1
  21. package/lib/buildTransaction.js +33 -46
  22. package/lib/buildTransaction.js.map +1 -1
  23. package/lib/cli-transaction.js +50 -27
  24. package/lib/cli-transaction.js.map +1 -1
  25. package/lib/estimateMaxSpendable.js +11 -21
  26. package/lib/estimateMaxSpendable.js.map +1 -1
  27. package/lib/getTransactionStatus.js +2 -11
  28. package/lib/getTransactionStatus.js.map +1 -1
  29. package/lib/hw-getAddress.js +3 -12
  30. package/lib/hw-getAddress.js.map +1 -1
  31. package/lib/logic.js +3 -5
  32. package/lib/logic.js.map +1 -1
  33. package/lib/preload.js +20 -33
  34. package/lib/preload.js.map +1 -1
  35. package/lib/prepareTransaction.js +354 -382
  36. package/lib/prepareTransaction.js.map +1 -1
  37. package/lib/signOperation.js +98 -26
  38. package/lib/signOperation.js.map +1 -1
  39. package/lib/specs.js +11 -20
  40. package/lib/specs.js.map +1 -1
  41. package/lib/speculos-deviceActions.js +48 -72
  42. package/lib/speculos-deviceActions.js.map +1 -1
  43. package/lib/synchronization.js +66 -76
  44. package/lib/synchronization.js.map +1 -1
  45. package/lib/transaction.js +10 -2
  46. package/lib/transaction.js.map +1 -1
  47. package/lib/tx-fees.js +97 -76
  48. package/lib/tx-fees.js.map +1 -1
  49. package/lib/utils.js +16 -49
  50. package/lib/utils.js.map +1 -1
  51. package/lib/validator-app/index.js +26 -38
  52. package/lib/validator-app/index.js.map +1 -1
  53. package/lib-es/api/chain/index.js +15 -20
  54. package/lib-es/api/chain/index.js.map +1 -1
  55. package/lib-es/api/chain/program/parser.js +20 -5
  56. package/lib-es/api/chain/program/parser.js.map +1 -1
  57. package/lib-es/api/chain/stake-activation/rpc.js +40 -51
  58. package/lib-es/api/chain/stake-activation/rpc.js.map +1 -1
  59. package/lib-es/api/chain/web3.js +152 -227
  60. package/lib-es/api/chain/web3.js.map +1 -1
  61. package/lib-es/api/traced.js +1 -1
  62. package/lib-es/api/traced.js.map +1 -1
  63. package/lib-es/bridge/bridge.js +14 -24
  64. package/lib-es/bridge/bridge.js.map +1 -1
  65. package/lib-es/bridge/js.js +3 -3
  66. package/lib-es/bridge/js.js.map +1 -1
  67. package/lib-es/bridge.integration.test.js +133 -65
  68. package/lib-es/bridge.integration.test.js.map +1 -1
  69. package/lib-es/broadcast.js +3 -12
  70. package/lib-es/broadcast.js.map +1 -1
  71. package/lib-es/buildTransaction.js +33 -46
  72. package/lib-es/buildTransaction.js.map +1 -1
  73. package/lib-es/cli-transaction.js +50 -27
  74. package/lib-es/cli-transaction.js.map +1 -1
  75. package/lib-es/estimateMaxSpendable.js +11 -21
  76. package/lib-es/estimateMaxSpendable.js.map +1 -1
  77. package/lib-es/getTransactionStatus.js +2 -11
  78. package/lib-es/getTransactionStatus.js.map +1 -1
  79. package/lib-es/hw-getAddress.js +3 -12
  80. package/lib-es/hw-getAddress.js.map +1 -1
  81. package/lib-es/logic.js +3 -5
  82. package/lib-es/logic.js.map +1 -1
  83. package/lib-es/preload.js +20 -33
  84. package/lib-es/preload.js.map +1 -1
  85. package/lib-es/prepareTransaction.js +354 -382
  86. package/lib-es/prepareTransaction.js.map +1 -1
  87. package/lib-es/signOperation.js +98 -26
  88. package/lib-es/signOperation.js.map +1 -1
  89. package/lib-es/specs.js +11 -20
  90. package/lib-es/specs.js.map +1 -1
  91. package/lib-es/speculos-deviceActions.js +48 -72
  92. package/lib-es/speculos-deviceActions.js.map +1 -1
  93. package/lib-es/synchronization.js +66 -76
  94. package/lib-es/synchronization.js.map +1 -1
  95. package/lib-es/transaction.js +10 -2
  96. package/lib-es/transaction.js.map +1 -1
  97. package/lib-es/tx-fees.js +97 -76
  98. package/lib-es/tx-fees.js.map +1 -1
  99. package/lib-es/utils.js +16 -49
  100. package/lib-es/utils.js.map +1 -1
  101. package/lib-es/validator-app/index.js +26 -38
  102. package/lib-es/validator-app/index.js.map +1 -1
  103. package/package.json +3 -3
  104. package/tsconfig.json +3 -3
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.prepareTransaction = void 0;
13
4
  const cryptoassets_1 = require("@ledgerhq/cryptoassets");
@@ -19,52 +10,53 @@ const logic_1 = require("./logic");
19
10
  const utils_1 = require("./utils");
20
11
  const jsHelpers_1 = require("@ledgerhq/coin-framework/bridge/jsHelpers");
21
12
  const estimateMaxSpendable_1 = require("./estimateMaxSpendable");
22
- function deriveCommandDescriptor(mainAccount, tx, api) {
23
- return __awaiter(this, void 0, void 0, function* () {
24
- const { model } = tx;
25
- switch (model.kind) {
26
- case "transfer":
27
- return deriveTransferCommandDescriptor(mainAccount, tx, model, api);
28
- case "token.transfer":
29
- return deriveTokenTransferCommandDescriptor(mainAccount, tx, model, api);
30
- case "token.createATA":
31
- return deriveCreateAssociatedTokenAccountCommandDescriptor(mainAccount, tx, model, api);
32
- case "stake.createAccount":
33
- return deriveStakeCreateAccountCommandDescriptor(mainAccount, tx, model, api);
34
- case "stake.delegate":
35
- return deriveStakeDelegateCommandDescriptor(mainAccount, tx, model, api);
36
- case "stake.undelegate":
37
- return deriveStakeUndelegateCommandDescriptor(mainAccount, tx, model, api);
38
- case "stake.withdraw":
39
- return deriveStakeWithdrawCommandDescriptor(mainAccount, tx, model, api);
40
- case "stake.split":
41
- return deriveStakeSplitCommandDescriptor(mainAccount, tx, model, api);
42
- default:
43
- return (0, utils_1.assertUnreachable)(model);
44
- }
45
- });
13
+ async function deriveCommandDescriptor(mainAccount, tx, api) {
14
+ const { model } = tx;
15
+ switch (model.kind) {
16
+ case "transfer":
17
+ return deriveTransferCommandDescriptor(mainAccount, tx, model, api);
18
+ case "token.transfer":
19
+ return deriveTokenTransferCommandDescriptor(mainAccount, tx, model, api);
20
+ case "token.createATA":
21
+ return deriveCreateAssociatedTokenAccountCommandDescriptor(mainAccount, tx, model, api);
22
+ case "stake.createAccount":
23
+ return deriveStakeCreateAccountCommandDescriptor(mainAccount, tx, model, api);
24
+ case "stake.delegate":
25
+ return deriveStakeDelegateCommandDescriptor(mainAccount, tx, model, api);
26
+ case "stake.undelegate":
27
+ return deriveStakeUndelegateCommandDescriptor(mainAccount, tx, model, api);
28
+ case "stake.withdraw":
29
+ return deriveStakeWithdrawCommandDescriptor(mainAccount, tx, model, api);
30
+ case "stake.split":
31
+ return deriveStakeSplitCommandDescriptor(mainAccount, tx, model, api);
32
+ default:
33
+ return (0, utils_1.assertUnreachable)(model);
34
+ }
46
35
  }
47
- const prepareTransaction = (mainAccount, tx, api) => __awaiter(void 0, void 0, void 0, function* () {
36
+ const prepareTransaction = async (mainAccount, tx, api) => {
48
37
  const txToDeriveFrom = updateModelIfSubAccountIdPresent(tx);
49
- const commandDescriptor = yield deriveCommandDescriptor(mainAccount, txToDeriveFrom, api);
50
- const model = Object.assign(Object.assign({}, tx.model), { commandDescriptor });
38
+ const commandDescriptor = await deriveCommandDescriptor(mainAccount, txToDeriveFrom, api);
39
+ const model = {
40
+ ...tx.model,
41
+ commandDescriptor,
42
+ };
51
43
  const patch = {
52
44
  model,
53
45
  };
54
46
  return (0, jsHelpers_1.updateTransaction)(tx, patch);
55
- });
47
+ };
56
48
  exports.prepareTransaction = prepareTransaction;
57
- const deriveTokenTransferCommandDescriptor = (mainAccount, tx, model, api) => __awaiter(void 0, void 0, void 0, function* () {
49
+ const deriveTokenTransferCommandDescriptor = async (mainAccount, tx, model, api) => {
58
50
  const errors = {};
59
51
  const warnings = {};
60
52
  const subAccount = (0, index_1.findSubAccountById)(mainAccount, model.uiState.subAccountId);
61
53
  if (!subAccount || subAccount.type !== "TokenAccount") {
62
54
  throw new Error("subaccount not found");
63
55
  }
64
- if ((subAccount === null || subAccount === void 0 ? void 0 : subAccount.state) === "frozen") {
56
+ if (subAccount?.state === "frozen") {
65
57
  errors.amount = new errors_2.SolanaTokenAccountFrozen();
66
58
  }
67
- yield validateRecipientCommon(mainAccount, tx, errors, warnings, api, true);
59
+ await validateRecipientCommon(mainAccount, tx, errors, warnings, api, true);
68
60
  const memo = model.uiState.memo;
69
61
  if (typeof memo === "string" && memo.length > 0) {
70
62
  validateMemoCommon(memo, errors);
@@ -82,7 +74,7 @@ const deriveTokenTransferCommandDescriptor = (mainAccount, tx, model, api) => __
82
74
  };
83
75
  const recipientDescriptorOrError = errors.recipient
84
76
  ? defaultRecipientDescriptor
85
- : yield getTokenRecipient(tx.recipient, mintAddress, api);
77
+ : await getTokenRecipient(tx.recipient, mintAddress, api);
86
78
  if (!errors.recipient && recipientDescriptorOrError instanceof Error) {
87
79
  errors.recipient = recipientDescriptorOrError;
88
80
  }
@@ -90,12 +82,12 @@ const deriveTokenTransferCommandDescriptor = (mainAccount, tx, model, api) => __
90
82
  ? defaultRecipientDescriptor
91
83
  : recipientDescriptorOrError;
92
84
  const assocAccRentExempt = recipientDescriptor.shouldCreateAsAssociatedTokenAccount
93
- ? yield api.getAssocTokenAccMinNativeBalance()
85
+ ? await api.getAssocTokenAccMinNativeBalance()
94
86
  : 0;
95
87
  if (recipientDescriptor.shouldCreateAsAssociatedTokenAccount) {
96
88
  warnings.recipient = new errors_2.SolanaRecipientAssociatedTokenAccountWillBeFunded();
97
89
  }
98
- const { fee, spendable: spendableSol } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
90
+ const { fee, spendable: spendableSol } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
99
91
  if (spendableSol.lt(assocAccRentExempt) || spendableSol.isZero()) {
100
92
  errors.fee = new errors_1.NotEnoughBalance();
101
93
  }
@@ -121,370 +113,353 @@ const deriveTokenTransferCommandDescriptor = (mainAccount, tx, model, api) => __
121
113
  warnings,
122
114
  errors,
123
115
  };
124
- });
125
- function getTokenRecipient(recipientAddress, mintAddress, api) {
126
- return __awaiter(this, void 0, void 0, function* () {
127
- const recipientTokenAccount = yield (0, web3_1.getMaybeTokenAccount)(recipientAddress, api);
128
- if (recipientTokenAccount instanceof Error) {
129
- throw recipientTokenAccount;
130
- }
131
- if (recipientTokenAccount === undefined) {
132
- if (!(0, logic_1.isEd25519Address)(recipientAddress)) {
133
- return new errors_2.SolanaAddressOffEd25519();
134
- }
135
- const recipientAssociatedTokenAccountAddress = yield api.findAssocTokenAccAddress(recipientAddress, mintAddress);
136
- const shouldCreateAsAssociatedTokenAccount = !(yield isAccountFunded(recipientAssociatedTokenAccountAddress, api));
137
- if (!shouldCreateAsAssociatedTokenAccount) {
138
- const associatedTokenAccount = yield (0, web3_1.getMaybeTokenAccount)(recipientAssociatedTokenAccountAddress, api);
139
- if (associatedTokenAccount instanceof Error)
140
- throw recipientTokenAccount;
141
- if ((associatedTokenAccount === null || associatedTokenAccount === void 0 ? void 0 : associatedTokenAccount.state) === "frozen") {
142
- return new errors_2.SolanaTokenAccountFrozen();
143
- }
144
- }
145
- return {
146
- walletAddress: recipientAddress,
147
- shouldCreateAsAssociatedTokenAccount,
148
- tokenAccAddress: recipientAssociatedTokenAccountAddress,
149
- };
116
+ };
117
+ async function getTokenRecipient(recipientAddress, mintAddress, api) {
118
+ const recipientTokenAccount = await (0, web3_1.getMaybeTokenAccount)(recipientAddress, api);
119
+ if (recipientTokenAccount instanceof Error) {
120
+ throw recipientTokenAccount;
121
+ }
122
+ if (recipientTokenAccount === undefined) {
123
+ if (!(0, logic_1.isEd25519Address)(recipientAddress)) {
124
+ return new errors_2.SolanaAddressOffEd25519();
150
125
  }
151
- else {
152
- if (recipientTokenAccount.mint.toBase58() !== mintAddress) {
153
- return new errors_2.SolanaTokenAccountHoldsAnotherToken();
154
- }
155
- if (recipientTokenAccount.state === "frozen") {
126
+ const recipientAssociatedTokenAccountAddress = await api.findAssocTokenAccAddress(recipientAddress, mintAddress);
127
+ const shouldCreateAsAssociatedTokenAccount = !(await isAccountFunded(recipientAssociatedTokenAccountAddress, api));
128
+ if (!shouldCreateAsAssociatedTokenAccount) {
129
+ const associatedTokenAccount = await (0, web3_1.getMaybeTokenAccount)(recipientAssociatedTokenAccountAddress, api);
130
+ if (associatedTokenAccount instanceof Error)
131
+ throw recipientTokenAccount;
132
+ if (associatedTokenAccount?.state === "frozen") {
156
133
  return new errors_2.SolanaTokenAccountFrozen();
157
134
  }
158
- if (recipientTokenAccount.state !== "initialized") {
159
- return new errors_2.SolanaTokenAccounNotInitialized();
160
- }
161
135
  }
162
136
  return {
163
- walletAddress: recipientTokenAccount.owner.toBase58(),
164
- shouldCreateAsAssociatedTokenAccount: false,
165
- tokenAccAddress: recipientAddress,
137
+ walletAddress: recipientAddress,
138
+ shouldCreateAsAssociatedTokenAccount,
139
+ tokenAccAddress: recipientAssociatedTokenAccountAddress,
166
140
  };
167
- });
168
- }
169
- function deriveCreateAssociatedTokenAccountCommandDescriptor(mainAccount, tx, model, api) {
170
- return __awaiter(this, void 0, void 0, function* () {
171
- const errors = {};
172
- const token = (0, cryptoassets_1.getTokenById)(model.uiState.tokenId);
173
- const mint = token.contractAddress;
174
- const associatedTokenAccountAddress = yield api.findAssocTokenAccAddress(mainAccount.freshAddress, mint);
175
- const { fee } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
176
- if (mainAccount.spendableBalance.lt(fee)) {
177
- errors.fee = new errors_1.NotEnoughBalance();
178
- }
179
- return {
180
- fee,
181
- command: {
182
- kind: model.kind,
183
- mint: mint,
184
- owner: mainAccount.freshAddress,
185
- associatedTokenAccountAddress,
186
- },
187
- warnings: {},
188
- errors,
189
- };
190
- });
191
- }
192
- function deriveTransferCommandDescriptor(mainAccount, tx, model, api) {
193
- return __awaiter(this, void 0, void 0, function* () {
194
- const errors = {};
195
- const warnings = {};
196
- yield validateRecipientCommon(mainAccount, tx, errors, warnings, api, false);
197
- const memo = model.uiState.memo;
198
- if (typeof memo === "string" && memo.length > 0) {
199
- validateMemoCommon(memo, errors);
141
+ }
142
+ else {
143
+ if (recipientTokenAccount.mint.toBase58() !== mintAddress) {
144
+ return new errors_2.SolanaTokenAccountHoldsAnotherToken();
200
145
  }
201
- const { fee, spendable } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
202
- const txAmount = tx.useAllAmount ? spendable : tx.amount;
203
- if (tx.useAllAmount) {
204
- if (txAmount.eq(0)) {
205
- errors.amount = new errors_1.NotEnoughBalance();
206
- }
146
+ if (recipientTokenAccount.state === "frozen") {
147
+ return new errors_2.SolanaTokenAccountFrozen();
207
148
  }
208
- else {
209
- if (txAmount.lte(0)) {
210
- errors.amount = new errors_1.AmountRequired();
211
- }
212
- else if (txAmount.gt(spendable)) {
213
- errors.amount = new errors_1.NotEnoughBalance();
214
- }
149
+ if (recipientTokenAccount.state !== "initialized") {
150
+ return new errors_2.SolanaTokenAccounNotInitialized();
215
151
  }
216
- const command = {
217
- kind: "transfer",
218
- amount: txAmount.toNumber(),
219
- sender: mainAccount.freshAddress,
220
- recipient: tx.recipient,
221
- memo: model.uiState.memo,
222
- };
223
- return {
224
- command,
225
- fee,
226
- warnings,
227
- errors,
228
- };
229
- });
152
+ }
153
+ return {
154
+ walletAddress: recipientTokenAccount.owner.toBase58(),
155
+ shouldCreateAsAssociatedTokenAccount: false,
156
+ tokenAccAddress: recipientAddress,
157
+ };
230
158
  }
231
- function deriveStakeCreateAccountCommandDescriptor(mainAccount, tx, model, api) {
232
- return __awaiter(this, void 0, void 0, function* () {
233
- const errors = {};
234
- const warnings = {};
235
- const { fee, spendable } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
236
- const txAmount = tx.useAllAmount ? spendable : tx.amount;
237
- if (tx.useAllAmount) {
238
- if (txAmount.eq(0)) {
239
- errors.amount = new errors_1.NotEnoughBalance();
240
- }
159
+ async function deriveCreateAssociatedTokenAccountCommandDescriptor(mainAccount, tx, model, api) {
160
+ const errors = {};
161
+ const token = (0, cryptoassets_1.getTokenById)(model.uiState.tokenId);
162
+ const mint = token.contractAddress;
163
+ const associatedTokenAccountAddress = await api.findAssocTokenAccAddress(mainAccount.freshAddress, mint);
164
+ const { fee } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
165
+ if (mainAccount.spendableBalance.lt(fee)) {
166
+ errors.fee = new errors_1.NotEnoughBalance();
167
+ }
168
+ return {
169
+ fee,
170
+ command: {
171
+ kind: model.kind,
172
+ mint: mint,
173
+ owner: mainAccount.freshAddress,
174
+ associatedTokenAccountAddress,
175
+ },
176
+ warnings: {},
177
+ errors,
178
+ };
179
+ }
180
+ async function deriveTransferCommandDescriptor(mainAccount, tx, model, api) {
181
+ const errors = {};
182
+ const warnings = {};
183
+ await validateRecipientCommon(mainAccount, tx, errors, warnings, api, false);
184
+ const memo = model.uiState.memo;
185
+ if (typeof memo === "string" && memo.length > 0) {
186
+ validateMemoCommon(memo, errors);
187
+ }
188
+ const { fee, spendable } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
189
+ const txAmount = tx.useAllAmount ? spendable : tx.amount;
190
+ if (tx.useAllAmount) {
191
+ if (txAmount.eq(0)) {
192
+ errors.amount = new errors_1.NotEnoughBalance();
241
193
  }
242
- else {
243
- if (txAmount.lte(0)) {
244
- errors.amount = new errors_1.AmountRequired();
245
- }
246
- else if (txAmount.gt(spendable)) {
247
- errors.amount = new errors_1.NotEnoughBalance();
248
- }
194
+ }
195
+ else {
196
+ if (txAmount.lte(0)) {
197
+ errors.amount = new errors_1.AmountRequired();
249
198
  }
250
- const { uiState: { delegate }, } = model;
251
- yield validateValidatorCommon(delegate.voteAccAddress, errors, api);
252
- const stakeAccAddressSeed = `stake:${Math.random().toString()}`;
253
- const stakeAccAddress = yield (0, web3_1.getStakeAccountAddressWithSeed)({
254
- fromAddress: mainAccount.freshAddress,
255
- seed: stakeAccAddressSeed,
256
- });
257
- const stakeAccRentExemptAmount = yield (0, web3_1.getStakeAccountMinimumBalanceForRentExemption)(api);
258
- return {
259
- command: {
260
- kind: "stake.createAccount",
261
- amount: txAmount.toNumber(),
262
- stakeAccRentExemptAmount,
263
- fromAccAddress: mainAccount.freshAddress,
264
- stakeAccAddress,
265
- delegate,
266
- seed: stakeAccAddressSeed,
267
- },
268
- fee,
269
- warnings,
270
- errors,
271
- };
272
- });
199
+ else if (txAmount.gt(spendable)) {
200
+ errors.amount = new errors_1.NotEnoughBalance();
201
+ }
202
+ }
203
+ const command = {
204
+ kind: "transfer",
205
+ amount: txAmount.toNumber(),
206
+ sender: mainAccount.freshAddress,
207
+ recipient: tx.recipient,
208
+ memo: model.uiState.memo,
209
+ };
210
+ return {
211
+ command,
212
+ fee,
213
+ warnings,
214
+ errors,
215
+ };
273
216
  }
274
- function deriveStakeDelegateCommandDescriptor(mainAccount, tx, model, api) {
275
- return __awaiter(this, void 0, void 0, function* () {
276
- var _a;
277
- const errors = {};
278
- const { uiState } = model;
279
- const stake = validateAndTryGetStakeAccount(mainAccount, uiState.stakeAccAddr, errors);
280
- if (stake !== undefined && !stake.hasStakeAuth && !stake.hasWithdrawAuth) {
281
- errors.stakeAccAddr = new errors_2.SolanaStakeNoStakeAuth();
217
+ async function deriveStakeCreateAccountCommandDescriptor(mainAccount, tx, model, api) {
218
+ const errors = {};
219
+ const warnings = {};
220
+ const { fee, spendable } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
221
+ const txAmount = tx.useAllAmount ? spendable : tx.amount;
222
+ if (tx.useAllAmount) {
223
+ if (txAmount.eq(0)) {
224
+ errors.amount = new errors_1.NotEnoughBalance();
282
225
  }
283
- yield validateValidatorCommon(uiState.voteAccAddr, errors, api);
284
- if (!errors.voteAccAddr && stake !== undefined) {
285
- switch (stake.activation.state) {
286
- case "active":
287
- case "activating":
288
- errors.stakeAccAddr = new errors_2.SolanaStakeAccountIsNotDelegatable();
289
- break;
290
- case "inactive":
291
- break;
292
- case "deactivating":
293
- if (((_a = stake.delegation) === null || _a === void 0 ? void 0 : _a.voteAccAddr) !== uiState.voteAccAddr) {
294
- errors.stakeAccAddr = new errors_2.SolanaStakeAccountValidatorIsUnchangeable();
295
- }
296
- break;
297
- default:
298
- return (0, utils_1.assertUnreachable)(stake.activation.state);
299
- }
226
+ }
227
+ else {
228
+ if (txAmount.lte(0)) {
229
+ errors.amount = new errors_1.AmountRequired();
300
230
  }
301
- const { fee } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
302
- if (mainAccount.spendableBalance.lt(fee)) {
303
- errors.fee = new errors_1.NotEnoughBalance();
231
+ else if (txAmount.gt(spendable)) {
232
+ errors.amount = new errors_1.NotEnoughBalance();
304
233
  }
305
- return {
306
- command: {
307
- kind: "stake.delegate",
308
- authorizedAccAddr: mainAccount.freshAddress,
309
- stakeAccAddr: uiState.stakeAccAddr,
310
- voteAccAddr: uiState.voteAccAddr,
311
- },
312
- fee,
313
- warnings: {},
314
- errors,
315
- };
234
+ }
235
+ const { uiState: { delegate }, } = model;
236
+ await validateValidatorCommon(delegate.voteAccAddress, errors, api);
237
+ const stakeAccAddressSeed = `stake:${Math.random().toString()}`;
238
+ const stakeAccAddress = await (0, web3_1.getStakeAccountAddressWithSeed)({
239
+ fromAddress: mainAccount.freshAddress,
240
+ seed: stakeAccAddressSeed,
316
241
  });
242
+ const stakeAccRentExemptAmount = await (0, web3_1.getStakeAccountMinimumBalanceForRentExemption)(api);
243
+ return {
244
+ command: {
245
+ kind: "stake.createAccount",
246
+ amount: txAmount.toNumber(),
247
+ stakeAccRentExemptAmount,
248
+ fromAccAddress: mainAccount.freshAddress,
249
+ stakeAccAddress,
250
+ delegate,
251
+ seed: stakeAccAddressSeed,
252
+ },
253
+ fee,
254
+ warnings,
255
+ errors,
256
+ };
317
257
  }
318
- function deriveStakeUndelegateCommandDescriptor(mainAccount, tx, model, api) {
319
- return __awaiter(this, void 0, void 0, function* () {
320
- const errors = {};
321
- const { uiState } = model;
322
- const stake = validateAndTryGetStakeAccount(mainAccount, uiState.stakeAccAddr, errors);
323
- if (stake !== undefined) {
324
- switch (stake.activation.state) {
325
- case "active":
326
- case "activating":
327
- break;
328
- case "inactive":
329
- case "deactivating":
330
- errors.stakeAccAddr = new errors_2.SolanaStakeAccountIsNotUndelegatable();
331
- break;
332
- default:
333
- return (0, utils_1.assertUnreachable)(stake.activation.state);
334
- }
335
- if (!errors.stakeAccAddr && !stake.hasStakeAuth && !stake.hasWithdrawAuth) {
336
- errors.stakeAccAddr = new errors_2.SolanaStakeNoStakeAuth();
337
- }
338
- }
339
- const { fee } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
340
- if (mainAccount.solanaResources.unstakeReserve.lt(fee)) {
341
- errors.fee = new errors_1.NotEnoughBalance();
258
+ async function deriveStakeDelegateCommandDescriptor(mainAccount, tx, model, api) {
259
+ const errors = {};
260
+ const { uiState } = model;
261
+ const stake = validateAndTryGetStakeAccount(mainAccount, uiState.stakeAccAddr, errors);
262
+ if (stake !== undefined && !stake.hasStakeAuth && !stake.hasWithdrawAuth) {
263
+ errors.stakeAccAddr = new errors_2.SolanaStakeNoStakeAuth();
264
+ }
265
+ await validateValidatorCommon(uiState.voteAccAddr, errors, api);
266
+ if (!errors.voteAccAddr && stake !== undefined) {
267
+ switch (stake.activation.state) {
268
+ case "active":
269
+ case "activating":
270
+ errors.stakeAccAddr = new errors_2.SolanaStakeAccountIsNotDelegatable();
271
+ break;
272
+ case "inactive":
273
+ break;
274
+ case "deactivating":
275
+ if (stake.delegation?.voteAccAddr !== uiState.voteAccAddr) {
276
+ errors.stakeAccAddr = new errors_2.SolanaStakeAccountValidatorIsUnchangeable();
277
+ }
278
+ break;
279
+ default:
280
+ return (0, utils_1.assertUnreachable)(stake.activation.state);
342
281
  }
343
- return {
344
- command: {
345
- kind: "stake.undelegate",
346
- authorizedAccAddr: mainAccount.freshAddress,
347
- stakeAccAddr: uiState.stakeAccAddr,
348
- },
349
- fee,
350
- warnings: {},
351
- errors,
352
- };
353
- });
282
+ }
283
+ const { fee } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
284
+ if (mainAccount.spendableBalance.lt(fee)) {
285
+ errors.fee = new errors_1.NotEnoughBalance();
286
+ }
287
+ return {
288
+ command: {
289
+ kind: "stake.delegate",
290
+ authorizedAccAddr: mainAccount.freshAddress,
291
+ stakeAccAddr: uiState.stakeAccAddr,
292
+ voteAccAddr: uiState.voteAccAddr,
293
+ },
294
+ fee,
295
+ warnings: {},
296
+ errors,
297
+ };
354
298
  }
355
- function deriveStakeWithdrawCommandDescriptor(mainAccount, tx, model, api) {
356
- return __awaiter(this, void 0, void 0, function* () {
357
- var _a;
358
- const errors = {};
359
- const { uiState } = model;
360
- const stake = validateAndTryGetStakeAccount(mainAccount, uiState.stakeAccAddr, errors);
361
- if (!errors.stakeAccAddr && stake !== undefined) {
362
- if (!stake.hasWithdrawAuth) {
363
- errors.stakeAccAddr = new errors_2.SolanaStakeNoWithdrawAuth();
364
- }
365
- else if (stake.withdrawable <= 0) {
366
- errors.stakeAccAddr = new errors_2.SolanaStakeAccountNothingToWithdraw();
367
- }
299
+ async function deriveStakeUndelegateCommandDescriptor(mainAccount, tx, model, api) {
300
+ const errors = {};
301
+ const { uiState } = model;
302
+ const stake = validateAndTryGetStakeAccount(mainAccount, uiState.stakeAccAddr, errors);
303
+ if (stake !== undefined) {
304
+ switch (stake.activation.state) {
305
+ case "active":
306
+ case "activating":
307
+ break;
308
+ case "inactive":
309
+ case "deactivating":
310
+ errors.stakeAccAddr = new errors_2.SolanaStakeAccountIsNotUndelegatable();
311
+ break;
312
+ default:
313
+ return (0, utils_1.assertUnreachable)(stake.activation.state);
368
314
  }
369
- const { fee } = yield (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
370
- if (mainAccount.solanaResources.unstakeReserve.lt(fee)) {
371
- errors.fee = new errors_1.NotEnoughBalance();
315
+ if (!errors.stakeAccAddr && !stake.hasStakeAuth && !stake.hasWithdrawAuth) {
316
+ errors.stakeAccAddr = new errors_2.SolanaStakeNoStakeAuth();
372
317
  }
373
- return {
374
- command: {
375
- kind: "stake.withdraw",
376
- authorizedAccAddr: mainAccount.freshAddress,
377
- stakeAccAddr: uiState.stakeAccAddr,
378
- amount: (_a = stake === null || stake === void 0 ? void 0 : stake.withdrawable) !== null && _a !== void 0 ? _a : 0,
379
- toAccAddr: mainAccount.freshAddress,
380
- },
381
- fee,
382
- warnings: {},
383
- errors,
384
- };
385
- });
318
+ }
319
+ const { fee } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
320
+ if (mainAccount.solanaResources.unstakeReserve.lt(fee)) {
321
+ errors.fee = new errors_1.NotEnoughBalance();
322
+ }
323
+ return {
324
+ command: {
325
+ kind: "stake.undelegate",
326
+ authorizedAccAddr: mainAccount.freshAddress,
327
+ stakeAccAddr: uiState.stakeAccAddr,
328
+ },
329
+ fee,
330
+ warnings: {},
331
+ errors,
332
+ };
386
333
  }
387
- function deriveStakeSplitCommandDescriptor(mainAccount, tx, model, api) {
388
- return __awaiter(this, void 0, void 0, function* () {
389
- var _a, _b;
390
- const errors = {};
391
- // TODO: find stake account in the main acc when synced
392
- const { uiState } = model;
393
- // TODO: use all amount
394
- if (tx.amount.lte(0)) {
395
- errors.amount = new errors_1.AmountRequired();
334
+ async function deriveStakeWithdrawCommandDescriptor(mainAccount, tx, model, api) {
335
+ const errors = {};
336
+ const { uiState } = model;
337
+ const stake = validateAndTryGetStakeAccount(mainAccount, uiState.stakeAccAddr, errors);
338
+ if (!errors.stakeAccAddr && stake !== undefined) {
339
+ if (!stake.hasWithdrawAuth) {
340
+ errors.stakeAccAddr = new errors_2.SolanaStakeNoWithdrawAuth();
396
341
  }
397
- // TODO: else if amount > stake balance
398
- if (!(0, logic_1.isValidBase58Address)(uiState.stakeAccAddr)) {
399
- errors.stakeAccAddr = new errors_1.InvalidAddress("", {
400
- currencyName: mainAccount.currency.name,
401
- });
342
+ else if (stake.withdrawable <= 0) {
343
+ errors.stakeAccAddr = new errors_2.SolanaStakeAccountNothingToWithdraw();
402
344
  }
403
- (_b = (_a = mainAccount.solanaResources) === null || _a === void 0 ? void 0 : _a.stakes) !== null && _b !== void 0 ? _b : [];
404
- const commandFees = yield (0, web3_1.getStakeAccountMinimumBalanceForRentExemption)(api);
405
- const splitStakeAccAddrSeed = `stake:${Math.random().toString()}`;
406
- const splitStakeAccAddr = yield (0, web3_1.getStakeAccountAddressWithSeed)({
407
- fromAddress: mainAccount.freshAddress,
408
- seed: splitStakeAccAddrSeed,
345
+ }
346
+ const { fee } = await (0, estimateMaxSpendable_1.estimateFeeAndSpendable)(api, mainAccount, tx);
347
+ if (mainAccount.solanaResources.unstakeReserve.lt(fee)) {
348
+ errors.fee = new errors_1.NotEnoughBalance();
349
+ }
350
+ return {
351
+ command: {
352
+ kind: "stake.withdraw",
353
+ authorizedAccAddr: mainAccount.freshAddress,
354
+ stakeAccAddr: uiState.stakeAccAddr,
355
+ amount: stake?.withdrawable ?? 0,
356
+ toAccAddr: mainAccount.freshAddress,
357
+ },
358
+ fee,
359
+ warnings: {},
360
+ errors,
361
+ };
362
+ }
363
+ async function deriveStakeSplitCommandDescriptor(mainAccount, tx, model, api) {
364
+ const errors = {};
365
+ // TODO: find stake account in the main acc when synced
366
+ const { uiState } = model;
367
+ // TODO: use all amount
368
+ if (tx.amount.lte(0)) {
369
+ errors.amount = new errors_1.AmountRequired();
370
+ }
371
+ // TODO: else if amount > stake balance
372
+ if (!(0, logic_1.isValidBase58Address)(uiState.stakeAccAddr)) {
373
+ errors.stakeAccAddr = new errors_1.InvalidAddress("", {
374
+ currencyName: mainAccount.currency.name,
409
375
  });
410
- return {
411
- command: {
412
- kind: "stake.split",
413
- authorizedAccAddr: mainAccount.freshAddress,
414
- stakeAccAddr: uiState.stakeAccAddr,
415
- amount: tx.amount.toNumber(),
416
- seed: splitStakeAccAddrSeed,
417
- splitStakeAccAddr,
418
- },
419
- fee: commandFees,
420
- warnings: {},
421
- errors: {},
422
- };
376
+ }
377
+ mainAccount.solanaResources?.stakes ?? [];
378
+ const commandFees = await (0, web3_1.getStakeAccountMinimumBalanceForRentExemption)(api);
379
+ const splitStakeAccAddrSeed = `stake:${Math.random().toString()}`;
380
+ const splitStakeAccAddr = await (0, web3_1.getStakeAccountAddressWithSeed)({
381
+ fromAddress: mainAccount.freshAddress,
382
+ seed: splitStakeAccAddrSeed,
423
383
  });
384
+ return {
385
+ command: {
386
+ kind: "stake.split",
387
+ authorizedAccAddr: mainAccount.freshAddress,
388
+ stakeAccAddr: uiState.stakeAccAddr,
389
+ amount: tx.amount.toNumber(),
390
+ seed: splitStakeAccAddrSeed,
391
+ splitStakeAccAddr,
392
+ },
393
+ fee: commandFees,
394
+ warnings: {},
395
+ errors: {},
396
+ };
424
397
  }
425
398
  // if subaccountid present - it's a token transfer
426
399
  function updateModelIfSubAccountIdPresent(tx) {
427
400
  if (tx.subAccountId) {
428
- return Object.assign(Object.assign({}, tx), { model: {
401
+ return {
402
+ ...tx,
403
+ model: {
429
404
  kind: "token.transfer",
430
- uiState: Object.assign(Object.assign({}, tx.model.uiState), { subAccountId: tx.subAccountId }),
431
- } });
405
+ uiState: {
406
+ ...tx.model.uiState,
407
+ subAccountId: tx.subAccountId,
408
+ },
409
+ },
410
+ };
432
411
  }
433
412
  return tx;
434
413
  }
435
- function isAccountFunded(address, api) {
436
- return __awaiter(this, void 0, void 0, function* () {
437
- const balance = yield api.getBalance(address);
438
- return balance > 0;
439
- });
414
+ async function isAccountFunded(address, api) {
415
+ const balance = await api.getBalance(address);
416
+ return balance > 0;
440
417
  }
441
- function validateRecipientCommon(mainAccount, tx, errors, warnings, api, allowATA) {
442
- return __awaiter(this, void 0, void 0, function* () {
443
- if (!tx.recipient) {
444
- errors.recipient = new errors_1.RecipientRequired();
445
- }
446
- else if (mainAccount.freshAddress === tx.recipient) {
447
- errors.recipient = new errors_1.InvalidAddressBecauseDestinationIsAlsoSource();
448
- }
449
- else if (!(0, logic_1.isValidBase58Address)(tx.recipient)) {
450
- errors.recipient = new errors_1.InvalidAddress("", {
451
- currencyName: mainAccount.currency.name,
452
- });
418
+ async function validateRecipientCommon(mainAccount, tx, errors, warnings, api, allowATA) {
419
+ if (!tx.recipient) {
420
+ errors.recipient = new errors_1.RecipientRequired();
421
+ }
422
+ else if (mainAccount.freshAddress === tx.recipient) {
423
+ errors.recipient = new errors_1.InvalidAddressBecauseDestinationIsAlsoSource();
424
+ }
425
+ else if (!(0, logic_1.isValidBase58Address)(tx.recipient)) {
426
+ errors.recipient = new errors_1.InvalidAddress("", {
427
+ currencyName: mainAccount.currency.name,
428
+ });
429
+ }
430
+ else {
431
+ const recipientWalletIsUnfunded = !(await isAccountFunded(tx.recipient, api));
432
+ const recipientTokenAccount = await (0, web3_1.getMaybeTokenAccount)(tx.recipient, api);
433
+ if (recipientTokenAccount instanceof Error) {
434
+ throw recipientTokenAccount;
453
435
  }
454
- else {
455
- const recipientWalletIsUnfunded = !(yield isAccountFunded(tx.recipient, api));
456
- const recipientTokenAccount = yield (0, web3_1.getMaybeTokenAccount)(tx.recipient, api);
457
- if (recipientTokenAccount instanceof Error) {
458
- throw recipientTokenAccount;
459
- }
460
- if (recipientTokenAccount) {
461
- if (allowATA) {
462
- if ((0, logic_1.isEd25519Address)(tx.recipient)) {
463
- errors.recipient = new errors_2.SolanaTokenAccountNotAllowed();
464
- }
465
- else {
466
- warnings.recipient = new errors_2.SolanaTokenAccountWarning();
467
- }
436
+ if (recipientTokenAccount) {
437
+ if (allowATA) {
438
+ if ((0, logic_1.isEd25519Address)(tx.recipient)) {
439
+ errors.recipient = new errors_2.SolanaTokenAccountNotAllowed();
468
440
  }
469
441
  else {
470
- errors.recipient = new errors_2.SolanaTokenAccountNotAllowed();
442
+ warnings.recipient = new errors_2.SolanaTokenAccountWarning();
471
443
  }
472
444
  }
473
- const mintTokenAccount = yield (0, web3_1.getMaybeMintAccount)(tx.recipient, api);
474
- if (mintTokenAccount instanceof Error) {
475
- throw recipientTokenAccount;
476
- }
477
- if (mintTokenAccount) {
478
- errors.recipient = new errors_2.SolanaMintAccountNotAllowed();
479
- }
480
- if (recipientWalletIsUnfunded) {
481
- warnings.recipient = new errors_2.SolanaAccountNotFunded();
482
- }
483
- if (!(0, logic_1.isEd25519Address)(tx.recipient)) {
484
- warnings.recipientOffCurve = new errors_2.SolanaAddressOffEd25519();
445
+ else {
446
+ errors.recipient = new errors_2.SolanaTokenAccountNotAllowed();
485
447
  }
486
448
  }
487
- });
449
+ const mintTokenAccount = await (0, web3_1.getMaybeMintAccount)(tx.recipient, api);
450
+ if (mintTokenAccount instanceof Error) {
451
+ throw recipientTokenAccount;
452
+ }
453
+ if (mintTokenAccount) {
454
+ errors.recipient = new errors_2.SolanaMintAccountNotAllowed();
455
+ }
456
+ if (recipientWalletIsUnfunded) {
457
+ warnings.recipient = new errors_2.SolanaAccountNotFunded();
458
+ }
459
+ if (!(0, logic_1.isEd25519Address)(tx.recipient)) {
460
+ warnings.recipientOffCurve = new errors_2.SolanaAddressOffEd25519();
461
+ }
462
+ }
488
463
  }
489
464
  function validateMemoCommon(memo, errors) {
490
465
  const memoBytes = Buffer.from(memo, "utf-8");
@@ -496,26 +471,23 @@ function validateMemoCommon(memo, errors) {
496
471
  errors.transaction = errors.memo;
497
472
  }
498
473
  }
499
- function validateValidatorCommon(addr, errors, api) {
500
- return __awaiter(this, void 0, void 0, function* () {
501
- if (addr.length === 0) {
502
- errors.voteAccAddr = new errors_2.SolanaValidatorRequired();
503
- }
504
- else if (!(0, logic_1.isValidBase58Address)(addr)) {
505
- errors.voteAccAddr = new errors_1.InvalidAddress("", {
506
- currencyName: "Solana",
507
- });
508
- }
509
- else {
510
- const voteAcc = yield (0, web3_1.getMaybeVoteAccount)(addr, api);
511
- if (voteAcc instanceof Error || voteAcc === undefined) {
512
- errors.voteAccAddr = new errors_2.SolanaInvalidValidator();
513
- }
474
+ async function validateValidatorCommon(addr, errors, api) {
475
+ if (addr.length === 0) {
476
+ errors.voteAccAddr = new errors_2.SolanaValidatorRequired();
477
+ }
478
+ else if (!(0, logic_1.isValidBase58Address)(addr)) {
479
+ errors.voteAccAddr = new errors_1.InvalidAddress("", {
480
+ currencyName: "Solana",
481
+ });
482
+ }
483
+ else {
484
+ const voteAcc = await (0, web3_1.getMaybeVoteAccount)(addr, api);
485
+ if (voteAcc instanceof Error || voteAcc === undefined) {
486
+ errors.voteAccAddr = new errors_2.SolanaInvalidValidator();
514
487
  }
515
- });
488
+ }
516
489
  }
517
490
  function validateAndTryGetStakeAccount(account, stakeAccAddr, errors) {
518
- var _a;
519
491
  if (stakeAccAddr.length === 0) {
520
492
  errors.stakeAccAddr = new errors_2.SolanaStakeAccountRequired();
521
493
  }
@@ -525,7 +497,7 @@ function validateAndTryGetStakeAccount(account, stakeAccAddr, errors) {
525
497
  });
526
498
  }
527
499
  if (!errors.stakeAccAddr) {
528
- const stake = (_a = account.solanaResources) === null || _a === void 0 ? void 0 : _a.stakes.find(stake => stake.stakeAccAddr === stakeAccAddr);
500
+ const stake = account.solanaResources?.stakes.find(stake => stake.stakeAccAddr === stakeAccAddr);
529
501
  if (stake === undefined) {
530
502
  errors.stakeAccAddr = new errors_2.SolanaStakeAccountNotFound();
531
503
  }