@ledgerhq/coin-sui 0.11.0 → 0.12.0-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.
Files changed (187) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.unimportedrc.json +1 -0
  3. package/CHANGELOG.md +11 -0
  4. package/index.d.ts +0 -1
  5. package/jest.config.js +1 -1
  6. package/lib/bridge/broadcast.d.ts.map +1 -1
  7. package/lib/bridge/broadcast.js +3 -0
  8. package/lib/bridge/broadcast.js.map +1 -1
  9. package/lib/bridge/buildOptimisticOperation.js +31 -0
  10. package/lib/bridge/buildOptimisticOperation.js.map +1 -1
  11. package/lib/bridge/buildTransaction.d.ts +1 -1
  12. package/lib/bridge/buildTransaction.d.ts.map +1 -1
  13. package/lib/bridge/buildTransaction.js +3 -1
  14. package/lib/bridge/buildTransaction.js.map +1 -1
  15. package/lib/bridge/buildTransaction.test.js +4 -0
  16. package/lib/bridge/buildTransaction.test.js.map +1 -1
  17. package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -1
  18. package/lib/bridge/estimateMaxSpendable.js +15 -3
  19. package/lib/bridge/estimateMaxSpendable.js.map +1 -1
  20. package/lib/bridge/estimateMaxSpendable.test.js +27 -0
  21. package/lib/bridge/estimateMaxSpendable.test.js.map +1 -1
  22. package/lib/bridge/getFeesForTransaction.d.ts.map +1 -1
  23. package/lib/bridge/getFeesForTransaction.js +13 -1
  24. package/lib/bridge/getFeesForTransaction.js.map +1 -1
  25. package/lib/bridge/getOperationExtra.d.ts +2 -0
  26. package/lib/bridge/getOperationExtra.d.ts.map +1 -0
  27. package/lib/bridge/getOperationExtra.js +6 -0
  28. package/lib/bridge/getOperationExtra.js.map +1 -0
  29. package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
  30. package/lib/bridge/getTransactionStatus.js +45 -20
  31. package/lib/bridge/getTransactionStatus.js.map +1 -1
  32. package/lib/bridge/preload.d.ts.map +1 -1
  33. package/lib/bridge/preload.js +5 -3
  34. package/lib/bridge/preload.js.map +1 -1
  35. package/lib/bridge/preload.test.js +13 -217
  36. package/lib/bridge/preload.test.js.map +1 -1
  37. package/lib/bridge/prepareTransaction.js +1 -1
  38. package/lib/bridge/prepareTransaction.js.map +1 -1
  39. package/lib/bridge/synchronisation.d.ts.map +1 -1
  40. package/lib/bridge/synchronisation.js +5 -2
  41. package/lib/bridge/synchronisation.js.map +1 -1
  42. package/lib/bridge/synchronisation.test.js +355 -7
  43. package/lib/bridge/synchronisation.test.js.map +1 -1
  44. package/lib/bridge/utils.d.ts +1 -1
  45. package/lib/bridge/utils.d.ts.map +1 -1
  46. package/lib/bridge/utils.js +22 -0
  47. package/lib/bridge/utils.js.map +1 -1
  48. package/lib/constants.d.ts +4 -0
  49. package/lib/constants.d.ts.map +1 -0
  50. package/lib/constants.js +7 -0
  51. package/lib/constants.js.map +1 -0
  52. package/lib/errors.d.ts +13 -0
  53. package/lib/errors.d.ts.map +1 -0
  54. package/lib/errors.js +21 -0
  55. package/lib/errors.js.map +1 -0
  56. package/lib/logic/craftTransaction.d.ts +5 -10
  57. package/lib/logic/craftTransaction.d.ts.map +1 -1
  58. package/lib/logic/craftTransaction.js +2 -1
  59. package/lib/logic/craftTransaction.js.map +1 -1
  60. package/lib/logic/estimateFees.d.ts +1 -1
  61. package/lib/logic/estimateFees.d.ts.map +1 -1
  62. package/lib/logic/estimateFees.js +14 -2
  63. package/lib/logic/estimateFees.js.map +1 -1
  64. package/lib/logic/index.d.ts +2 -1
  65. package/lib/logic/index.d.ts.map +1 -1
  66. package/lib/logic/index.js +3 -1
  67. package/lib/logic/index.js.map +1 -1
  68. package/lib/logic/stake.d.ts +3 -0
  69. package/lib/logic/stake.d.ts.map +1 -0
  70. package/lib/logic/stake.js +12 -0
  71. package/lib/logic/stake.js.map +1 -0
  72. package/lib/network/index.d.ts +5 -4
  73. package/lib/network/index.d.ts.map +1 -1
  74. package/lib/network/index.js +5 -3
  75. package/lib/network/index.js.map +1 -1
  76. package/lib/network/sdk.d.ts +5 -3
  77. package/lib/network/sdk.d.ts.map +1 -1
  78. package/lib/network/sdk.js +148 -26
  79. package/lib/network/sdk.js.map +1 -1
  80. package/lib/network/sdk.test.js +491 -6
  81. package/lib/network/sdk.test.js.map +1 -1
  82. package/lib/types/bridge.d.ts +33 -6
  83. package/lib/types/bridge.d.ts.map +1 -1
  84. package/lib-es/bridge/broadcast.d.ts.map +1 -1
  85. package/lib-es/bridge/broadcast.js +3 -0
  86. package/lib-es/bridge/broadcast.js.map +1 -1
  87. package/lib-es/bridge/buildOptimisticOperation.js +31 -0
  88. package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
  89. package/lib-es/bridge/buildTransaction.d.ts +1 -1
  90. package/lib-es/bridge/buildTransaction.d.ts.map +1 -1
  91. package/lib-es/bridge/buildTransaction.js +3 -1
  92. package/lib-es/bridge/buildTransaction.js.map +1 -1
  93. package/lib-es/bridge/buildTransaction.test.js +4 -0
  94. package/lib-es/bridge/buildTransaction.test.js.map +1 -1
  95. package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -1
  96. package/lib-es/bridge/estimateMaxSpendable.js +15 -3
  97. package/lib-es/bridge/estimateMaxSpendable.js.map +1 -1
  98. package/lib-es/bridge/estimateMaxSpendable.test.js +27 -0
  99. package/lib-es/bridge/estimateMaxSpendable.test.js.map +1 -1
  100. package/lib-es/bridge/getFeesForTransaction.d.ts.map +1 -1
  101. package/lib-es/bridge/getFeesForTransaction.js +13 -1
  102. package/lib-es/bridge/getFeesForTransaction.js.map +1 -1
  103. package/lib-es/bridge/getOperationExtra.d.ts +2 -0
  104. package/lib-es/bridge/getOperationExtra.d.ts.map +1 -0
  105. package/lib-es/bridge/getOperationExtra.js +2 -0
  106. package/lib-es/bridge/getOperationExtra.js.map +1 -0
  107. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
  108. package/lib-es/bridge/getTransactionStatus.js +46 -21
  109. package/lib-es/bridge/getTransactionStatus.js.map +1 -1
  110. package/lib-es/bridge/preload.d.ts.map +1 -1
  111. package/lib-es/bridge/preload.js +5 -3
  112. package/lib-es/bridge/preload.js.map +1 -1
  113. package/lib-es/bridge/preload.test.js +14 -218
  114. package/lib-es/bridge/preload.test.js.map +1 -1
  115. package/lib-es/bridge/prepareTransaction.js +1 -1
  116. package/lib-es/bridge/prepareTransaction.js.map +1 -1
  117. package/lib-es/bridge/synchronisation.d.ts.map +1 -1
  118. package/lib-es/bridge/synchronisation.js +6 -3
  119. package/lib-es/bridge/synchronisation.js.map +1 -1
  120. package/lib-es/bridge/synchronisation.test.js +332 -7
  121. package/lib-es/bridge/synchronisation.test.js.map +1 -1
  122. package/lib-es/bridge/utils.d.ts +1 -1
  123. package/lib-es/bridge/utils.d.ts.map +1 -1
  124. package/lib-es/bridge/utils.js +22 -0
  125. package/lib-es/bridge/utils.js.map +1 -1
  126. package/lib-es/constants.d.ts +4 -0
  127. package/lib-es/constants.d.ts.map +1 -0
  128. package/lib-es/constants.js +4 -0
  129. package/lib-es/constants.js.map +1 -0
  130. package/lib-es/errors.d.ts +13 -0
  131. package/lib-es/errors.d.ts.map +1 -0
  132. package/lib-es/errors.js +18 -0
  133. package/lib-es/errors.js.map +1 -0
  134. package/lib-es/logic/craftTransaction.d.ts +5 -10
  135. package/lib-es/logic/craftTransaction.d.ts.map +1 -1
  136. package/lib-es/logic/craftTransaction.js +2 -1
  137. package/lib-es/logic/craftTransaction.js.map +1 -1
  138. package/lib-es/logic/estimateFees.d.ts +1 -1
  139. package/lib-es/logic/estimateFees.d.ts.map +1 -1
  140. package/lib-es/logic/estimateFees.js +14 -2
  141. package/lib-es/logic/estimateFees.js.map +1 -1
  142. package/lib-es/logic/index.d.ts +2 -1
  143. package/lib-es/logic/index.d.ts.map +1 -1
  144. package/lib-es/logic/index.js +1 -0
  145. package/lib-es/logic/index.js.map +1 -1
  146. package/lib-es/logic/stake.d.ts +3 -0
  147. package/lib-es/logic/stake.d.ts.map +1 -0
  148. package/lib-es/logic/stake.js +8 -0
  149. package/lib-es/logic/stake.js.map +1 -0
  150. package/lib-es/network/index.d.ts +5 -4
  151. package/lib-es/network/index.d.ts.map +1 -1
  152. package/lib-es/network/index.js +4 -3
  153. package/lib-es/network/index.js.map +1 -1
  154. package/lib-es/network/sdk.d.ts +5 -3
  155. package/lib-es/network/sdk.d.ts.map +1 -1
  156. package/lib-es/network/sdk.js +144 -25
  157. package/lib-es/network/sdk.js.map +1 -1
  158. package/lib-es/network/sdk.test.js +491 -6
  159. package/lib-es/network/sdk.test.js.map +1 -1
  160. package/lib-es/types/bridge.d.ts +33 -6
  161. package/lib-es/types/bridge.d.ts.map +1 -1
  162. package/package.json +17 -9
  163. package/src/bridge/broadcast.ts +3 -0
  164. package/src/bridge/buildOptimisticOperation.ts +47 -4
  165. package/src/bridge/buildTransaction.test.ts +4 -0
  166. package/src/bridge/buildTransaction.ts +3 -1
  167. package/src/bridge/estimateMaxSpendable.test.ts +33 -0
  168. package/src/bridge/estimateMaxSpendable.ts +17 -3
  169. package/src/bridge/getFeesForTransaction.ts +14 -1
  170. package/src/bridge/getOperationExtra.ts +1 -0
  171. package/src/bridge/getTransactionStatus.ts +53 -21
  172. package/src/bridge/preload.test.ts +13 -279
  173. package/src/bridge/preload.ts +5 -3
  174. package/src/bridge/prepareTransaction.ts +1 -1
  175. package/src/bridge/synchronisation.test.ts +389 -7
  176. package/src/bridge/synchronisation.ts +6 -3
  177. package/src/bridge/utils.ts +25 -1
  178. package/src/constants.ts +4 -0
  179. package/src/errors.ts +21 -0
  180. package/src/logic/craftTransaction.ts +6 -9
  181. package/src/logic/estimateFees.ts +16 -1
  182. package/src/logic/index.ts +2 -1
  183. package/src/logic/stake.ts +9 -0
  184. package/src/network/index.ts +6 -3
  185. package/src/network/sdk.test.ts +538 -10
  186. package/src/network/sdk.ts +179 -31
  187. package/src/types/bridge.ts +32 -6
@@ -8,11 +8,13 @@ import {
8
8
  SuiClient,
9
9
  SuiHTTPTransport,
10
10
  SuiTransactionBlockResponse,
11
+ SuiTransaction,
12
+ SuiTransactionBlockKind,
13
+ TransactionEffects,
11
14
  SuiTransactionBlockResponseOptions,
12
15
  DelegatedStake,
13
16
  StakeObject,
14
17
  TransactionBlockData,
15
- TransactionEffects,
16
18
  } from "@mysten/sui/client";
17
19
  import { Transaction } from "@mysten/sui/transactions";
18
20
  import { BigNumber } from "bignumber.js";
@@ -31,15 +33,16 @@ import uniqBy from "lodash/unionBy";
31
33
  import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
32
34
  import { log } from "@ledgerhq/logs";
33
35
  import { makeLRUCache, minutes } from "@ledgerhq/live-network/cache";
34
- import type { Transaction as TransactionType } from "../types";
35
- import type { CreateExtrinsicArg } from "../logic/craftTransaction";
36
+ import type { Transaction as TransactionType, SuiValidator, CreateExtrinsicArg } from "../types";
36
37
  import { ensureAddressFormat } from "../utils";
37
38
  import coinConfig from "../config";
38
39
  import { getEnv } from "@ledgerhq/live-env";
39
-
40
- type AsyncApiFunction<T> = (api: SuiClient) => Promise<T>;
40
+ import { SUI_SYSTEM_STATE_OBJECT_ID } from "@mysten/sui/utils";
41
+ import { getCurrentSuiPreloadData } from "../bridge/preload";
42
+ import { ONE_SUI } from "../constants";
41
43
 
42
44
  const apiMap: Record<string, SuiClient> = {};
45
+ type AsyncApiFunction<T> = (api: SuiClient) => Promise<T>;
43
46
 
44
47
  export const TRANSACTIONS_LIMIT_PER_QUERY = 50;
45
48
  export const TRANSACTIONS_LIMIT = 300;
@@ -58,10 +61,12 @@ type GenericInput<T> = T extends (...args: infer K) => unknown ? K : never;
58
61
  type Inputs = GenericInput<typeof fetch>;
59
62
 
60
63
  const fetcher = (url: Inputs[0], options: Inputs[1], retry = 3): Promise<Response> => {
64
+ const version = getEnv("LEDGER_CLIENT_VERSION") || "";
65
+ const isCI = version.includes("ll-ci") || version === "";
61
66
  if (options) {
62
67
  options.headers = {
63
68
  ...options.headers,
64
- "X-Ledger-Client-Version": getEnv("LEDGER_CLIENT_VERSION"),
69
+ "X-Ledger-Client-Version": isCI ? "lld/2.124.0-dev" : version, // for integration cli tests
65
70
  };
66
71
  }
67
72
  if (retry === 1) return fetch(url, options);
@@ -96,6 +101,33 @@ export const getAllBalancesCached = makeLRUCache(
96
101
  (owner: string) => owner,
97
102
  minutes(1),
98
103
  );
104
+ function isStaking(block?: SuiTransactionBlockKind): block is {
105
+ inputs: SuiCallArg[];
106
+ kind: "ProgrammableTransaction";
107
+ transactions: SuiTransaction[];
108
+ } {
109
+ if (!block) return false;
110
+ if (block.kind === "ProgrammableTransaction") {
111
+ const move = block.transactions.find(item => "MoveCall" in item) as any;
112
+ return move?.MoveCall.function === "request_add_stake";
113
+ }
114
+ return false;
115
+ }
116
+
117
+ function isUnstaking(block?: SuiTransactionBlockKind): block is {
118
+ inputs: SuiCallArg[];
119
+ kind: "ProgrammableTransaction";
120
+ transactions: SuiTransaction[];
121
+ } {
122
+ if (!block) return false;
123
+ if (block.kind === "ProgrammableTransaction") {
124
+ const move = block.transactions.find(
125
+ item => "MoveCall" in item && item["MoveCall"].function === "request_withdraw_stake",
126
+ ) as any;
127
+ return Boolean(move);
128
+ }
129
+ return false;
130
+ }
99
131
 
100
132
  /**
101
133
  * Get account balance (native and tokens)
@@ -119,8 +151,20 @@ export function isSender(addr: string, transaction?: TransactionBlockData): bool
119
151
  /**
120
152
  * Map transaction to an Operation Type
121
153
  */
122
- export function getOperationType(addr: string, transaction?: TransactionBlockData): OperationType {
123
- return isSender(addr, transaction) ? "OUT" : "IN";
154
+ export function getOperationType(
155
+ addr: string,
156
+ { transaction }: SuiTransactionBlockResponse,
157
+ ): OperationType {
158
+ if (!isSender(addr, transaction?.data)) {
159
+ return "IN";
160
+ }
161
+ if (isStaking(transaction?.data.transaction)) {
162
+ return "DELEGATE";
163
+ }
164
+ if (isUnstaking(transaction?.data.transaction)) {
165
+ return "UNDELEGATE";
166
+ }
167
+ return "OUT";
124
168
  }
125
169
 
126
170
  /**
@@ -134,14 +178,17 @@ export const getOperationSenders = (transaction?: TransactionBlockData): string[
134
178
  * Extract recipients from transaction
135
179
  */
136
180
  export const getOperationRecipients = (transaction?: TransactionBlockData): string[] => {
137
- if (transaction?.transaction.kind === "ProgrammableTransaction") {
138
- if (!transaction?.transaction?.inputs) return [];
181
+ if (!transaction) return [];
182
+
183
+ if (transaction.transaction.kind === "ProgrammableTransaction") {
184
+ if (!transaction.transaction.inputs) return [];
139
185
  const recipients: string[] = [];
140
186
  transaction.transaction.inputs.forEach((input: SuiCallArg) => {
141
187
  if ("valueType" in input && input.valueType === "address") {
142
188
  recipients.push(String(input.value));
143
189
  }
144
190
  });
191
+ if (isUnstaking(transaction.transaction) || isStaking(transaction.transaction)) return [];
145
192
  return recipients;
146
193
  }
147
194
  return [];
@@ -157,6 +204,14 @@ export const getOperationAmount = (
157
204
  ): BigNumber => {
158
205
  let amount = new BigNumber(0);
159
206
  if (!transaction?.balanceChanges) return amount;
207
+ if (
208
+ isStaking(transaction.transaction?.data.transaction) ||
209
+ isUnstaking(transaction.transaction?.data.transaction)
210
+ ) {
211
+ const balanceChange = transaction.balanceChanges[0];
212
+ return amount.minus(balanceChange?.amount || 0);
213
+ }
214
+
160
215
  for (const balanceChange of transaction.balanceChanges) {
161
216
  if (
162
217
  typeof balanceChange.owner !== "string" &&
@@ -186,6 +241,39 @@ export const getOperationFee = (transaction: SuiTransactionBlockResponse): BigNu
186
241
  return computationCost.plus(storageCost).minus(storageRebate);
187
242
  };
188
243
 
244
+ export const getOperationExtra = (digest: string): Promise<Record<string, string>> =>
245
+ withApi(async api => {
246
+ const response = await api.getTransactionBlock({
247
+ digest,
248
+ options: {
249
+ showInput: true,
250
+ showBalanceChanges: true,
251
+ showEffects: true,
252
+ showEvents: true,
253
+ },
254
+ });
255
+ const tx = response.transaction?.data?.transaction;
256
+ if (isStaking(tx)) {
257
+ const inputs = tx.inputs;
258
+ const pure = inputs.filter(x => x.type === "pure") as { valueType: string; value: string }[];
259
+ const amount = pure.find(x => x.valueType === "u64")?.value as string;
260
+ const address = pure.find(x => x.valueType === "address")?.value as string;
261
+ const name = getCurrentSuiPreloadData().validators.find(x => x.suiAddress === address)?.name;
262
+ return { amount, address, name: name || "" };
263
+ }
264
+
265
+ if (isUnstaking(response.transaction?.data?.transaction)) {
266
+ const { principal_amount: amount, validator_address: address } = response.events?.find(
267
+ e => e.type === "0x3::validator::UnstakingRequestEvent",
268
+ )?.parsedJson as Record<string, string>;
269
+ const name = getCurrentSuiPreloadData().validators.find(x => x.suiAddress === address)?.name;
270
+
271
+ return { amount, address, name: name || "" };
272
+ }
273
+
274
+ return {};
275
+ });
276
+
189
277
  /**
190
278
  * Extract date from transaction
191
279
  */
@@ -193,6 +281,11 @@ export const getOperationDate = (transaction: SuiTransactionBlockResponse): Date
193
281
  return new Date(parseInt(transaction.timestampMs!));
194
282
  };
195
283
 
284
+ export const getStakesRaw = (owner: string) =>
285
+ withApi(async api => {
286
+ return api.getStakes({ owner });
287
+ });
288
+
196
289
  /**
197
290
  * Extract operation coin type from transaction
198
291
  */
@@ -217,7 +310,7 @@ export function transactionToOperation(
217
310
  address: string,
218
311
  transaction: SuiTransactionBlockResponse,
219
312
  ): Operation {
220
- const type = getOperationType(address, transaction.transaction?.data);
313
+ const type = getOperationType(address, transaction);
221
314
 
222
315
  const coinType = getOperationCoinType(transaction);
223
316
  const hash = transaction.digest;
@@ -232,7 +325,7 @@ export function transactionToOperation(
232
325
  coinType,
233
326
  },
234
327
  fee: getOperationFee(transaction),
235
- hasFailed: transaction.effects?.status.status != "success",
328
+ hasFailed: transaction.effects?.status.status !== "success",
236
329
  hash,
237
330
  recipients: getOperationRecipients(transaction.transaction?.data),
238
331
  senders: getOperationSenders(transaction.transaction?.data),
@@ -242,7 +335,7 @@ export function transactionToOperation(
242
335
  }
243
336
 
244
337
  export function transactionToOp(address: string, transaction: SuiTransactionBlockResponse): Op {
245
- const type = getOperationType(address, transaction.transaction?.data);
338
+ const type = getOperationType(address, transaction);
246
339
  const coinType = getOperationCoinType(transaction);
247
340
  const hash = transaction.digest;
248
341
  return {
@@ -278,7 +371,7 @@ export function toBlockInfo(checkpoint: Checkpoint): BlockInfo {
278
371
  time: new Date(parseInt(checkpoint.timestampMs)),
279
372
  };
280
373
 
281
- if (typeof checkpoint.previousDigest == "string")
374
+ if (typeof checkpoint.previousDigest === "string")
282
375
  return {
283
376
  ...info,
284
377
  parent: {
@@ -303,7 +396,7 @@ export function toBlockInfo(checkpoint: Checkpoint): BlockInfo {
303
396
  export function toBlockTransaction(transaction: SuiTransactionBlockResponse): BlockTransaction {
304
397
  return {
305
398
  hash: transaction.digest,
306
- failed: transaction.effects?.status.status != "success",
399
+ failed: transaction.effects?.status.status !== "success",
307
400
  operations: transaction.balanceChanges?.flatMap(toBlockOperation) || [],
308
401
  fees: BigInt(getOperationFee(transaction).toString()),
309
402
  feesPayer: transaction.transaction?.data.sender || "",
@@ -316,7 +409,7 @@ export function toBlockTransaction(transaction: SuiTransactionBlockResponse): Bl
316
409
  * @param change balance change
317
410
  */
318
411
  export function toBlockOperation(change: BalanceChange): BlockOperation[] {
319
- if (typeof change.owner == "string" || !("AddressOwner" in change.owner)) return [];
412
+ if (typeof change.owner === "string" || !("AddressOwner" in change.owner)) return [];
320
413
  return [
321
414
  {
322
415
  type: "transfer",
@@ -537,27 +630,65 @@ export const createTransaction = async (address: string, transaction: CreateExtr
537
630
  withApi(async api => {
538
631
  const tx = new Transaction();
539
632
  tx.setSender(ensureAddressFormat(address));
633
+ const { mode, amount } = transaction;
634
+ switch (mode) {
635
+ case "delegate": {
636
+ const coins = tx.splitCoins(tx.gas, [amount.toNumber()]);
637
+ tx.moveCall({
638
+ target: "0x3::sui_system::request_add_stake",
639
+ arguments: [
640
+ tx.object(SUI_SYSTEM_STATE_OBJECT_ID),
641
+ coins,
642
+ tx.pure.address(transaction.recipient),
643
+ ],
644
+ });
645
+
646
+ tx.setGasBudgetIfNotSet(ONE_SUI / 10);
647
+ break;
648
+ }
649
+ case "undelegate": {
650
+ if (transaction.useAllAmount) {
651
+ tx.moveCall({
652
+ target: "0x3::sui_system::request_withdraw_stake",
653
+ arguments: [tx.object(SUI_SYSTEM_STATE_OBJECT_ID), tx.object(transaction.stakedSuiId!)],
654
+ });
655
+ } else {
656
+ const res = tx.moveCall({
657
+ target: "0x3::staking_pool::split",
658
+ arguments: [tx.object(transaction.stakedSuiId!), tx.pure.u64(amount.toString())],
659
+ });
660
+ tx.moveCall({
661
+ target: "0x3::sui_system::request_withdraw_stake",
662
+ arguments: [tx.object(SUI_SYSTEM_STATE_OBJECT_ID), res],
663
+ });
664
+ }
665
+
666
+ tx.setGasBudgetIfNotSet(ONE_SUI / 10);
667
+ break;
668
+ }
669
+ default: {
670
+ if (transaction.coinType !== DEFAULT_COIN_TYPE) {
671
+ const requiredAmount = transaction.amount.toNumber();
540
672
 
541
- if (transaction.coinType !== DEFAULT_COIN_TYPE) {
542
- const requiredAmount = transaction.amount.toNumber();
673
+ const coins = await getCoinsForAmount(api, address, transaction.coinType, requiredAmount);
543
674
 
544
- const coins = await getCoinsForAmount(api, address, transaction.coinType, requiredAmount);
675
+ if (coins.length === 0) {
676
+ throw new Error(`No coins found for type ${transaction.coinType}`);
677
+ }
545
678
 
546
- if (coins.length === 0) {
547
- throw new Error(`No coins found for type ${transaction.coinType}`);
548
- }
679
+ const coinObjects = coins.map(coin => tx.object(coin.coinObjectId));
549
680
 
550
- const coinObjects = coins.map(coin => tx.object(coin.coinObjectId));
681
+ if (coinObjects.length > 1) {
682
+ tx.mergeCoins(coinObjects[0], coinObjects.slice(1));
683
+ }
551
684
 
552
- if (coinObjects.length > 1) {
553
- tx.mergeCoins(coinObjects[0], coinObjects.slice(1));
685
+ const [coin] = tx.splitCoins(coinObjects[0], [transaction.amount.toNumber()]);
686
+ tx.transferObjects([coin], transaction.recipient);
687
+ } else {
688
+ const [coin] = tx.splitCoins(tx.gas, [transaction.amount.toNumber()]);
689
+ tx.transferObjects([coin], transaction.recipient);
690
+ }
554
691
  }
555
-
556
- const [coin] = tx.splitCoins(coinObjects[0], [transaction.amount.toNumber()]);
557
- tx.transferObjects([coin], transaction.recipient);
558
- } else {
559
- const [coin] = tx.splitCoins(tx.gas, [transaction.amount.toNumber()]);
560
- tx.transferObjects([coin], transaction.recipient);
561
692
  }
562
693
 
563
694
  return tx.build({ client: api });
@@ -726,3 +857,20 @@ export const toStakeAmounts = (stake: StakeObject): { deposited: bigint; rewarde
726
857
  return { deposited: BigInt(stake.principal), rewarded: 0n }; // note: we lose reward information in unstaked state here
727
858
  }
728
859
  };
860
+
861
+ export const getValidators = (): Promise<SuiValidator[]> =>
862
+ withApi(async api => {
863
+ const [{ activeValidators }, { apys }] = await Promise.all([
864
+ api.getLatestSuiSystemState(),
865
+ api.getValidatorsApy(),
866
+ ]);
867
+ const hash = apys.reduce(
868
+ (acc, item) => {
869
+ acc[item.address] = item.apy;
870
+ return acc;
871
+ },
872
+ {} as Record<string, number>,
873
+ );
874
+
875
+ return activeValidators.map(item => ({ ...item, apy: hash[item.suiAddress] }));
876
+ });
@@ -8,18 +8,29 @@ import type {
8
8
  OperationRaw,
9
9
  } from "@ledgerhq/types-live";
10
10
  import type { Account, AccountRaw } from "@ledgerhq/types-live";
11
+ import { DelegatedStake, StakeObject, SuiValidatorSummary } from "@mysten/sui/client";
12
+
13
+ export type MappedStake = StakeObject & {
14
+ rank: number;
15
+ validator: SuiValidator;
16
+ stakedSuiId: string;
17
+ formattedAmount: string;
18
+ };
11
19
 
12
20
  /**
13
21
  * Sui account resources
14
22
  */
15
- export type SuiResources = object;
23
+ export type SuiResources = {
24
+ stakes?: DelegatedStake[];
25
+ cachedOps?: Record<string, Record<string, string>>;
26
+ };
16
27
 
17
28
  /**
18
29
  * Sui account resources from raw JSON
19
30
  */
20
31
  export type SuiResourcesRaw = object;
21
32
 
22
- export type SuiTransactionMode = "send" | "token.send";
33
+ export type SuiTransactionMode = "send" | "token.send" | "delegate" | "undelegate";
23
34
 
24
35
  /**
25
36
  * Sui transaction
@@ -29,12 +40,22 @@ export type Transaction = TransactionCommon & {
29
40
  family: "sui";
30
41
  amount: BigNumber | null;
31
42
  fees?: BigNumber | null;
32
- errors: Record<string, Error>;
43
+ errors?: Record<string, Error>;
33
44
  skipVerify?: boolean;
34
45
  coinType: string;
46
+ stakedSuiId?: string;
35
47
  // add here all transaction-specific fields when implement other modes than "send"
36
48
  };
37
49
 
50
+ export type CreateExtrinsicArg = {
51
+ amount: BigNumber;
52
+ coinType: string;
53
+ mode: SuiTransactionMode;
54
+ recipient: string;
55
+ useAllAmount?: boolean;
56
+ stakedSuiId?: string;
57
+ };
58
+
38
59
  /**
39
60
  * Sui transaction from a raw JSON
40
61
  */
@@ -46,12 +67,17 @@ export type TransactionRaw = TransactionCommonRaw & {
46
67
  // also the transaction fields as raw JSON data
47
68
  };
48
69
 
70
+ /**
71
+ * Sui validator metadata
72
+ */
73
+ export type SuiValidator = SuiValidatorSummary & { apy: number };
74
+
49
75
  /**
50
76
  * Sui currency data that will be preloaded.
51
77
  * You can for instance add a list of validators for Proof-of-Stake blockchains,
52
78
  * or any volatile data that could not be set as constants in the code (staking progress, fee estimation variables, etc.)
53
79
  */
54
- export type SuiPreloadData = object;
80
+ export type SuiPreloadData = { validators: SuiValidator[] };
55
81
 
56
82
  export type SuiAccount = Account & {
57
83
  // On some blockchain, an account can have resources (gained, delegated, ...)
@@ -84,14 +110,14 @@ export type SuiSignedOperation = {
84
110
  };
85
111
 
86
112
  export type TransferCommand = {
87
- kind: "send";
113
+ kind: SuiTransactionMode;
88
114
  sender: string;
89
115
  recipient: string;
90
116
  amount: number;
91
117
  };
92
118
 
93
119
  export type TokenTransferCommand = {
94
- kind: "token.send";
120
+ kind: string;
95
121
  sender: string;
96
122
  recipient: string;
97
123
  amount: number;