@ledgerhq/coin-solana 0.29.0 → 0.29.1-nightly.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/CHANGELOG.md +7 -0
- package/lib/bridge.integration.test.js +1 -0
- package/lib/bridge.integration.test.js.map +1 -1
- package/lib/buildTransaction.d.ts.map +1 -1
- package/lib/buildTransaction.js +5 -0
- package/lib/buildTransaction.js.map +1 -1
- package/lib/getTransactionStatus.d.ts.map +1 -1
- package/lib/getTransactionStatus.js +2 -0
- package/lib/getTransactionStatus.js.map +1 -1
- package/lib/prepareTransaction.d.ts.map +1 -1
- package/lib/prepareTransaction.js +4 -61
- package/lib/prepareTransaction.js.map +1 -1
- package/lib/prepareTransaction.test.js +37 -52
- package/lib/prepareTransaction.test.js.map +1 -1
- package/lib/rawTransaction.d.ts +5 -0
- package/lib/rawTransaction.d.ts.map +1 -0
- package/lib/rawTransaction.js +52 -0
- package/lib/rawTransaction.js.map +1 -0
- package/lib/signOperation.d.ts.map +1 -1
- package/lib/signOperation.js +16 -0
- package/lib/signOperation.js.map +1 -1
- package/lib/specs.d.ts.map +1 -1
- package/lib/specs.js +1 -0
- package/lib/specs.js.map +1 -1
- package/lib/transaction.d.ts.map +1 -1
- package/lib/transaction.js +14 -20
- package/lib/transaction.js.map +1 -1
- package/lib/tx-fees.js +1 -0
- package/lib/tx-fees.js.map +1 -1
- package/lib/types.d.ts +10 -2
- package/lib/types.d.ts.map +1 -1
- package/lib-es/bridge.integration.test.js +1 -0
- package/lib-es/bridge.integration.test.js.map +1 -1
- package/lib-es/buildTransaction.d.ts.map +1 -1
- package/lib-es/buildTransaction.js +5 -0
- package/lib-es/buildTransaction.js.map +1 -1
- package/lib-es/getTransactionStatus.d.ts.map +1 -1
- package/lib-es/getTransactionStatus.js +2 -0
- package/lib-es/getTransactionStatus.js.map +1 -1
- package/lib-es/prepareTransaction.d.ts.map +1 -1
- package/lib-es/prepareTransaction.js +3 -60
- package/lib-es/prepareTransaction.js.map +1 -1
- package/lib-es/prepareTransaction.test.js +37 -52
- package/lib-es/prepareTransaction.test.js.map +1 -1
- package/lib-es/rawTransaction.d.ts +5 -0
- package/lib-es/rawTransaction.d.ts.map +1 -0
- package/lib-es/rawTransaction.js +44 -0
- package/lib-es/rawTransaction.js.map +1 -0
- package/lib-es/signOperation.d.ts.map +1 -1
- package/lib-es/signOperation.js +16 -0
- package/lib-es/signOperation.js.map +1 -1
- package/lib-es/specs.d.ts.map +1 -1
- package/lib-es/specs.js +1 -0
- package/lib-es/specs.js.map +1 -1
- package/lib-es/transaction.d.ts.map +1 -1
- package/lib-es/transaction.js +14 -20
- package/lib-es/transaction.js.map +1 -1
- package/lib-es/tx-fees.js +1 -0
- package/lib-es/tx-fees.js.map +1 -1
- package/lib-es/types.d.ts +10 -2
- package/lib-es/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/bridge.integration.test.ts +1 -0
- package/src/buildTransaction.ts +5 -0
- package/src/getTransactionStatus.ts +2 -0
- package/src/prepareTransaction.test.ts +31 -71
- package/src/prepareTransaction.ts +3 -100
- package/src/rawTransaction.ts +59 -0
- package/src/signOperation.ts +24 -0
- package/src/specs.ts +1 -0
- package/src/transaction.ts +17 -20
- package/src/tx-fees.ts +1 -0
- package/src/types.ts +13 -1
|
@@ -79,15 +79,7 @@ import { estimateFeeAndSpendable, estimateTokenMaxSpendable } from "./estimateMa
|
|
|
79
79
|
import { MemoTransferExt, TransferFeeConfigExt } from "./network/chain/account/tokenExtensions";
|
|
80
80
|
import { calculateToken2022TransferFees } from "./helpers/token";
|
|
81
81
|
import { TokenAccountInfo } from "./network/chain/account/token";
|
|
82
|
-
import {
|
|
83
|
-
DecodedTransferInstruction,
|
|
84
|
-
MessageCompiledInstruction,
|
|
85
|
-
PublicKey,
|
|
86
|
-
SystemInstruction,
|
|
87
|
-
SystemProgram,
|
|
88
|
-
VersionedMessage,
|
|
89
|
-
VersionedTransaction,
|
|
90
|
-
} from "@solana/web3.js";
|
|
82
|
+
import { deriveRawCommandDescriptor, toLiveTransaction } from "./rawTransaction";
|
|
91
83
|
import BigNumber from "bignumber.js";
|
|
92
84
|
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/formatCurrencyUnit";
|
|
93
85
|
|
|
@@ -118,102 +110,13 @@ async function deriveCommandDescriptor(
|
|
|
118
110
|
return deriveStakeWithdrawCommandDescriptor(mainAccount, tx, model, api);
|
|
119
111
|
case "stake.split":
|
|
120
112
|
return deriveStakeSplitCommandDescriptor(mainAccount, tx, model, api);
|
|
113
|
+
case "raw":
|
|
114
|
+
return deriveRawCommandDescriptor(tx, api);
|
|
121
115
|
default:
|
|
122
116
|
return assertUnreachable(model);
|
|
123
117
|
}
|
|
124
118
|
}
|
|
125
119
|
|
|
126
|
-
function fromBigIntToBigNumber(bigInt: bigint): BigNumber {
|
|
127
|
-
return BigNumber(bigInt.toString());
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function toSolanaTransaction(serializedTransaction: string): VersionedTransaction {
|
|
131
|
-
return VersionedTransaction.deserialize(Buffer.from(serializedTransaction, "base64"));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function findInstruction(
|
|
135
|
-
compiledInstructions: MessageCompiledInstruction[],
|
|
136
|
-
staticAccountKeys: PublicKey[],
|
|
137
|
-
): MessageCompiledInstruction | undefined {
|
|
138
|
-
return compiledInstructions.find(instruction => {
|
|
139
|
-
return (
|
|
140
|
-
staticAccountKeys[instruction.programIdIndex].toString() ===
|
|
141
|
-
SystemProgram.programId.toString()
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function decodeInstruction(
|
|
147
|
-
message: VersionedMessage,
|
|
148
|
-
instruction: MessageCompiledInstruction,
|
|
149
|
-
): DecodedTransferInstruction {
|
|
150
|
-
return SystemInstruction.decodeTransfer({
|
|
151
|
-
data: Buffer.from(instruction.data),
|
|
152
|
-
programId: SystemProgram.programId,
|
|
153
|
-
keys: instruction.accountKeyIndexes.map(index => {
|
|
154
|
-
return {
|
|
155
|
-
pubkey: message.staticAccountKeys[index],
|
|
156
|
-
isSigner: message.isAccountSigner(index),
|
|
157
|
-
isWritable: message.isAccountWritable(index),
|
|
158
|
-
};
|
|
159
|
-
}),
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function buildTransferTransaction(
|
|
164
|
-
raw: string,
|
|
165
|
-
lamports: bigint,
|
|
166
|
-
fromPubkey: PublicKey,
|
|
167
|
-
toPubkey: PublicKey,
|
|
168
|
-
estimatedFees: number | null,
|
|
169
|
-
): Transaction {
|
|
170
|
-
return {
|
|
171
|
-
raw,
|
|
172
|
-
family: "solana",
|
|
173
|
-
amount: fromBigIntToBigNumber(lamports),
|
|
174
|
-
recipient: String(toPubkey),
|
|
175
|
-
model: {
|
|
176
|
-
kind: "transfer",
|
|
177
|
-
uiState: {},
|
|
178
|
-
commandDescriptor: {
|
|
179
|
-
command: {
|
|
180
|
-
kind: "transfer",
|
|
181
|
-
amount: fromBigIntToBigNumber(lamports).toNumber(),
|
|
182
|
-
sender: String(fromPubkey),
|
|
183
|
-
recipient: String(toPubkey),
|
|
184
|
-
},
|
|
185
|
-
fee: estimatedFees ?? 0,
|
|
186
|
-
warnings: {},
|
|
187
|
-
errors: {},
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async function toLiveTransaction(
|
|
194
|
-
api: ChainAPI,
|
|
195
|
-
serializedTransaction: string,
|
|
196
|
-
): Promise<Transaction> {
|
|
197
|
-
const solanaTransaction = toSolanaTransaction(serializedTransaction);
|
|
198
|
-
const message = solanaTransaction.message;
|
|
199
|
-
const instruction = findInstruction(message.compiledInstructions, message.staticAccountKeys);
|
|
200
|
-
|
|
201
|
-
if (!instruction) {
|
|
202
|
-
throw new Error("No supported instructions found on Solana transaction");
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const decodedInstruction = decodeInstruction(message, instruction);
|
|
206
|
-
const estimatedFees = await api.getFeeForMessage(message);
|
|
207
|
-
|
|
208
|
-
return buildTransferTransaction(
|
|
209
|
-
serializedTransaction,
|
|
210
|
-
decodedInstruction.lamports,
|
|
211
|
-
decodedInstruction.fromPubkey,
|
|
212
|
-
decodedInstruction.toPubkey,
|
|
213
|
-
estimatedFees,
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
120
|
const prepareTransaction = async (
|
|
218
121
|
mainAccount: SolanaAccount,
|
|
219
122
|
tx: Transaction,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ChainAPI } from "./network";
|
|
2
|
+
import { Transaction } from "./types";
|
|
3
|
+
import { VersionedTransaction } from "@solana/web3.js";
|
|
4
|
+
import BigNumber from "bignumber.js";
|
|
5
|
+
|
|
6
|
+
function buildRawTransaction(raw: string, estimatedFees: number | null): Transaction {
|
|
7
|
+
return {
|
|
8
|
+
raw,
|
|
9
|
+
family: "solana",
|
|
10
|
+
amount: BigNumber(0),
|
|
11
|
+
recipient: "",
|
|
12
|
+
model: {
|
|
13
|
+
kind: "raw",
|
|
14
|
+
uiState: {},
|
|
15
|
+
commandDescriptor: {
|
|
16
|
+
command: {
|
|
17
|
+
kind: "raw",
|
|
18
|
+
raw,
|
|
19
|
+
},
|
|
20
|
+
fee: estimatedFees ?? 0,
|
|
21
|
+
warnings: {},
|
|
22
|
+
errors: {},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function toLiveTransaction(
|
|
29
|
+
api: ChainAPI,
|
|
30
|
+
serializedTransaction: string,
|
|
31
|
+
): Promise<Transaction> {
|
|
32
|
+
const solanaTransaction = VersionedTransaction.deserialize(
|
|
33
|
+
Buffer.from(serializedTransaction, "base64"),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const estimatedFees = await api.getFeeForMessage(solanaTransaction.message);
|
|
37
|
+
|
|
38
|
+
return buildRawTransaction(serializedTransaction, estimatedFees);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function deriveRawCommandDescriptor(tx: Transaction, api: ChainAPI) {
|
|
42
|
+
if (!tx.raw) {
|
|
43
|
+
throw new Error("Raw transaction is required to derive command descriptor");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const liveTx = await toLiveTransaction(api, tx.raw);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
liveTx.model.commandDescriptor || {
|
|
50
|
+
command: {
|
|
51
|
+
kind: "raw",
|
|
52
|
+
raw: tx.raw,
|
|
53
|
+
},
|
|
54
|
+
fee: tx.model.commandDescriptor?.fee ?? 0,
|
|
55
|
+
warnings: {},
|
|
56
|
+
errors: {},
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
package/src/signOperation.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Account, AccountBridge, OperationType } from "@ledgerhq/types-live
|
|
|
3
3
|
import type {
|
|
4
4
|
Command,
|
|
5
5
|
CommandDescriptor,
|
|
6
|
+
RawCommand,
|
|
6
7
|
SolanaOperation,
|
|
7
8
|
SolanaOperationExtra,
|
|
8
9
|
StakeCreateAccountCommand,
|
|
@@ -168,10 +169,32 @@ function buildOptimisticOperationForCommand(
|
|
|
168
169
|
return optimisticOpForStakeWithdraw(account, command, commandDescriptor);
|
|
169
170
|
case "stake.split":
|
|
170
171
|
return optimisticOpForStakeSplit(account, command, commandDescriptor);
|
|
172
|
+
case "raw":
|
|
173
|
+
return optimisticOpForRaw(account, transaction, command, commandDescriptor);
|
|
171
174
|
default:
|
|
172
175
|
return assertUnreachable(command);
|
|
173
176
|
}
|
|
174
177
|
}
|
|
178
|
+
|
|
179
|
+
function optimisticOpForRaw(
|
|
180
|
+
account: Account,
|
|
181
|
+
transaction: Transaction,
|
|
182
|
+
command: RawCommand,
|
|
183
|
+
commandDescriptor: CommandDescriptor,
|
|
184
|
+
): SolanaOperation {
|
|
185
|
+
const commons = optimisticOpcommons(commandDescriptor);
|
|
186
|
+
return {
|
|
187
|
+
...commons,
|
|
188
|
+
id: encodeOperationId(account.id, "", "OUT"),
|
|
189
|
+
type: "OUT",
|
|
190
|
+
accountId: account.id,
|
|
191
|
+
senders: [account.freshAddress],
|
|
192
|
+
recipients: [transaction.recipient],
|
|
193
|
+
value: new BigNumber(commons.fee ?? 0),
|
|
194
|
+
extra: getOpExtras(command),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
175
198
|
function optimisticOpForTransfer(
|
|
176
199
|
account: Account,
|
|
177
200
|
transaction: Transaction,
|
|
@@ -307,6 +330,7 @@ function getOpExtras(command: Command): SolanaOperationExtra {
|
|
|
307
330
|
case "stake.undelegate":
|
|
308
331
|
case "stake.withdraw":
|
|
309
332
|
case "stake.split":
|
|
333
|
+
case "raw":
|
|
310
334
|
break;
|
|
311
335
|
default:
|
|
312
336
|
return assertUnreachable(command);
|
package/src/specs.ts
CHANGED
package/src/transaction.ts
CHANGED
|
@@ -88,6 +88,8 @@ function formatCommand(mainAccount: Account, tx: Transaction, command: Command)
|
|
|
88
88
|
return formatStakeWithdraw(mainAccount, tx, command);
|
|
89
89
|
case "stake.split":
|
|
90
90
|
return formatStakeSplit(mainAccount, tx, command);
|
|
91
|
+
case "raw":
|
|
92
|
+
return formatRaw(tx);
|
|
91
93
|
default:
|
|
92
94
|
return assertUnreachable(command);
|
|
93
95
|
}
|
|
@@ -105,9 +107,7 @@ function formatStakeCreateAccount(
|
|
|
105
107
|
` AMOUNT: ${amount}${tx.useAllAmount ? " (ALL)" : ""}`,
|
|
106
108
|
` SEED: ${command.seed}`,
|
|
107
109
|
` VALIDATOR: ${command.delegate.voteAccAddress}`,
|
|
108
|
-
]
|
|
109
|
-
.filter(Boolean)
|
|
110
|
-
.join("\n");
|
|
110
|
+
].join("\n");
|
|
111
111
|
|
|
112
112
|
return "\n" + str;
|
|
113
113
|
}
|
|
@@ -157,7 +157,7 @@ function formatCreateATA(mainAccount: Account, command: TokenCreateATACommand) {
|
|
|
157
157
|
if (!token) {
|
|
158
158
|
throw new Error(`token for mint "${command.mint}" not found`);
|
|
159
159
|
}
|
|
160
|
-
const str = [` OPT IN TOKEN: ${token.ticker}`].
|
|
160
|
+
const str = [` OPT IN TOKEN: ${token.ticker}`].join("\n");
|
|
161
161
|
return "\n" + str;
|
|
162
162
|
}
|
|
163
163
|
|
|
@@ -186,9 +186,7 @@ function formatCreateApprove(
|
|
|
186
186
|
` APPROVE: ${command.account}`,
|
|
187
187
|
` DELEGATE: ${command.recipientDescriptor.walletAddress}`,
|
|
188
188
|
` AMOUNT: ${amount}${tx.useAllAmount ? " (ALL)" : ""}`,
|
|
189
|
-
]
|
|
190
|
-
.filter(Boolean)
|
|
191
|
-
.join("\n");
|
|
189
|
+
].join("\n");
|
|
192
190
|
return "\n" + str;
|
|
193
191
|
}
|
|
194
192
|
|
|
@@ -205,21 +203,17 @@ function formatCreateRevoke(
|
|
|
205
203
|
throw new Error("token subaccount expected");
|
|
206
204
|
}
|
|
207
205
|
|
|
208
|
-
const str = [` OWNER: ${command.owner}`, ` REVOKE: ${command.account}`]
|
|
209
|
-
.filter(Boolean)
|
|
210
|
-
.join("\n");
|
|
206
|
+
const str = [` OWNER: ${command.owner}`, ` REVOKE: ${command.account}`].join("\n");
|
|
211
207
|
return "\n" + str;
|
|
212
208
|
}
|
|
213
209
|
|
|
214
210
|
function formatStakeDelegate(command: StakeDelegateCommand) {
|
|
215
|
-
const str = [` DELEGATE: ${command.stakeAccAddr}`, ` TO: ${command.voteAccAddr}`]
|
|
216
|
-
.filter(Boolean)
|
|
217
|
-
.join("\n");
|
|
211
|
+
const str = [` DELEGATE: ${command.stakeAccAddr}`, ` TO: ${command.voteAccAddr}`].join("\n");
|
|
218
212
|
return "\n" + str;
|
|
219
213
|
}
|
|
220
214
|
|
|
221
215
|
function formatStakeUndelegate(command: StakeUndelegateCommand) {
|
|
222
|
-
const str = [` UNDELEGATE: ${command.stakeAccAddr}`].
|
|
216
|
+
const str = [` UNDELEGATE: ${command.stakeAccAddr}`].join("\n");
|
|
223
217
|
return "\n" + str;
|
|
224
218
|
}
|
|
225
219
|
|
|
@@ -229,9 +223,7 @@ function formatStakeWithdraw(mainAccount: Account, tx: Transaction, command: Sta
|
|
|
229
223
|
` WITHDRAW FROM: ${command.stakeAccAddr}`,
|
|
230
224
|
` AMOUNT: ${amount}${tx.useAllAmount ? " (ALL)" : ""}`,
|
|
231
225
|
` TO: ${command.toAccAddr}`,
|
|
232
|
-
]
|
|
233
|
-
.filter(Boolean)
|
|
234
|
-
.join("\n");
|
|
226
|
+
].join("\n");
|
|
235
227
|
return "\n" + str;
|
|
236
228
|
}
|
|
237
229
|
|
|
@@ -241,9 +233,14 @@ function formatStakeSplit(mainAccount: Account, tx: Transaction, command: StakeS
|
|
|
241
233
|
` SPLIT: ${command.stakeAccAddr}`,
|
|
242
234
|
` AMOUNT: ${amount}${tx.useAllAmount ? " (ALL)" : ""}`,
|
|
243
235
|
` TO: ${command.splitStakeAccAddr}`,
|
|
244
|
-
]
|
|
245
|
-
|
|
246
|
-
|
|
236
|
+
].join("\n");
|
|
237
|
+
return "\n" + str;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function formatRaw(tx: Transaction) {
|
|
241
|
+
const str = [` SEND RAW: ${tx.useAllAmount ? " (ALL)" : ""}`, ` TO: ${tx.recipient}`].join(
|
|
242
|
+
"\n",
|
|
243
|
+
);
|
|
247
244
|
return "\n" + str;
|
|
248
245
|
}
|
|
249
246
|
|
package/src/tx-fees.ts
CHANGED
|
@@ -58,6 +58,7 @@ const createDummyTx = (address: string, kind: TransactionModel["kind"]) => {
|
|
|
58
58
|
return createDummyTokenRevokeTx(address);
|
|
59
59
|
case "stake.split":
|
|
60
60
|
case "token.createATA":
|
|
61
|
+
case "raw":
|
|
61
62
|
throw new Error(`not implemented for <${kind}>`);
|
|
62
63
|
default:
|
|
63
64
|
return assertUnreachable(kind);
|
package/src/types.ts
CHANGED
|
@@ -121,6 +121,11 @@ export type TokenTransferCommand = {
|
|
|
121
121
|
};
|
|
122
122
|
};
|
|
123
123
|
|
|
124
|
+
export type RawCommand = {
|
|
125
|
+
kind: "raw";
|
|
126
|
+
raw: string;
|
|
127
|
+
};
|
|
128
|
+
|
|
124
129
|
export type Command =
|
|
125
130
|
| TransferCommand
|
|
126
131
|
| TokenTransferCommand
|
|
@@ -131,7 +136,8 @@ export type Command =
|
|
|
131
136
|
| StakeDelegateCommand
|
|
132
137
|
| StakeUndelegateCommand
|
|
133
138
|
| StakeWithdrawCommand
|
|
134
|
-
| StakeSplitCommand
|
|
139
|
+
| StakeSplitCommand
|
|
140
|
+
| RawCommand;
|
|
135
141
|
|
|
136
142
|
export type CommandDescriptor = {
|
|
137
143
|
command: Command;
|
|
@@ -214,6 +220,11 @@ export type StakeSplitTransaction = {
|
|
|
214
220
|
};
|
|
215
221
|
};
|
|
216
222
|
|
|
223
|
+
export type RawTransaction = {
|
|
224
|
+
kind: "raw";
|
|
225
|
+
uiState: object;
|
|
226
|
+
};
|
|
227
|
+
|
|
217
228
|
export type TransactionModel = { commandDescriptor?: CommandDescriptor } & (
|
|
218
229
|
| TransferTransaction
|
|
219
230
|
| TokenTransferTransaction
|
|
@@ -225,6 +236,7 @@ export type TransactionModel = { commandDescriptor?: CommandDescriptor } & (
|
|
|
225
236
|
| StakeUndelegateTransaction
|
|
226
237
|
| StakeWithdrawTransaction
|
|
227
238
|
| StakeSplitTransaction
|
|
239
|
+
| RawTransaction
|
|
228
240
|
);
|
|
229
241
|
|
|
230
242
|
export type Transaction = TransactionCommon & {
|