@ledgerhq/coin-tezos 0.4.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 (325) hide show
  1. package/.eslintrc.js +20 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/.unimportedrc.json +39 -0
  4. package/CHANGELOG.md +12 -0
  5. package/LICENSE.txt +21 -0
  6. package/jest.config.js +6 -0
  7. package/lib/api/bakers.d.ts +14 -0
  8. package/lib/api/bakers.d.ts.map +1 -0
  9. package/lib/api/bakers.integration.test.d.ts +2 -0
  10. package/lib/api/bakers.integration.test.d.ts.map +1 -0
  11. package/lib/api/bakers.integration.test.js +61 -0
  12. package/lib/api/bakers.integration.test.js.map +1 -0
  13. package/lib/api/bakers.js +141 -0
  14. package/lib/api/bakers.js.map +1 -0
  15. package/lib/api/bakers.test.d.ts +2 -0
  16. package/lib/api/bakers.test.d.ts.map +1 -0
  17. package/lib/api/bakers.test.js +146 -0
  18. package/lib/api/bakers.test.js.map +1 -0
  19. package/lib/api/bakers.whitelist-default.d.ts +4 -0
  20. package/lib/api/bakers.whitelist-default.d.ts.map +1 -0
  21. package/lib/api/bakers.whitelist-default.js +34 -0
  22. package/lib/api/bakers.whitelist-default.js.map +1 -0
  23. package/lib/api/index.d.ts +3 -0
  24. package/lib/api/index.d.ts.map +1 -0
  25. package/lib/api/index.js +19 -0
  26. package/lib/api/index.js.map +1 -0
  27. package/lib/api/tzkt.d.ts +81 -0
  28. package/lib/api/tzkt.d.ts.map +1 -0
  29. package/lib/api/tzkt.js +52 -0
  30. package/lib/api/tzkt.js.map +1 -0
  31. package/lib/bridge/broadcast.d.ts +6 -0
  32. package/lib/bridge/broadcast.d.ts.map +1 -0
  33. package/lib/bridge/broadcast.js +22 -0
  34. package/lib/bridge/broadcast.js.map +1 -0
  35. package/lib/bridge/broadcast.test.d.ts +2 -0
  36. package/lib/bridge/broadcast.test.d.ts.map +1 -0
  37. package/lib/bridge/broadcast.test.js +40 -0
  38. package/lib/bridge/broadcast.test.js.map +1 -0
  39. package/lib/bridge/createTransaction.d.ts +3 -0
  40. package/lib/bridge/createTransaction.d.ts.map +1 -0
  41. package/lib/bridge/createTransaction.js +23 -0
  42. package/lib/bridge/createTransaction.js.map +1 -0
  43. package/lib/bridge/deviceTransactionConfig.d.ts +19 -0
  44. package/lib/bridge/deviceTransactionConfig.d.ts.map +1 -0
  45. package/lib/bridge/deviceTransactionConfig.js +44 -0
  46. package/lib/bridge/deviceTransactionConfig.js.map +1 -0
  47. package/lib/bridge/estimateMaxSpendable.d.ts +10 -0
  48. package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -0
  49. package/lib/bridge/estimateMaxSpendable.js +29 -0
  50. package/lib/bridge/estimateMaxSpendable.js.map +1 -0
  51. package/lib/bridge/getAccountShape.d.ts +5 -0
  52. package/lib/bridge/getAccountShape.d.ts.map +1 -0
  53. package/lib/bridge/getAccountShape.js +253 -0
  54. package/lib/bridge/getAccountShape.js.map +1 -0
  55. package/lib/bridge/getAccountShape.test.d.ts +2 -0
  56. package/lib/bridge/getAccountShape.test.d.ts.map +1 -0
  57. package/lib/bridge/getAccountShape.test.js +33 -0
  58. package/lib/bridge/getAccountShape.test.js.map +1 -0
  59. package/lib/bridge/index.d.ts +8 -0
  60. package/lib/bridge/index.d.ts.map +1 -0
  61. package/lib/bridge/index.js +58 -0
  62. package/lib/bridge/index.js.map +1 -0
  63. package/lib/bridge/preload.d.ts +9 -0
  64. package/lib/bridge/preload.d.ts.map +1 -0
  65. package/lib/bridge/preload.js +32 -0
  66. package/lib/bridge/preload.js.map +1 -0
  67. package/lib/bridge/prepareTransaction.d.ts +9 -0
  68. package/lib/bridge/prepareTransaction.d.ts.map +1 -0
  69. package/lib/bridge/prepareTransaction.js +157 -0
  70. package/lib/bridge/prepareTransaction.js.map +1 -0
  71. package/lib/bridge/serialization.d.ts +7 -0
  72. package/lib/bridge/serialization.d.ts.map +1 -0
  73. package/lib/bridge/serialization.js +27 -0
  74. package/lib/bridge/serialization.js.map +1 -0
  75. package/lib/bridge/signOperation.d.ts +19 -0
  76. package/lib/bridge/signOperation.d.ts.map +1 -0
  77. package/lib/bridge/signOperation.js +147 -0
  78. package/lib/bridge/signOperation.js.map +1 -0
  79. package/lib/bridge/signOperation.test.d.ts +2 -0
  80. package/lib/bridge/signOperation.test.d.ts.map +1 -0
  81. package/lib/bridge/signOperation.test.js +223 -0
  82. package/lib/bridge/signOperation.test.js.map +1 -0
  83. package/lib/bridge/transaction.d.ts +15 -0
  84. package/lib/bridge/transaction.d.ts.map +1 -0
  85. package/lib/bridge/transaction.js +52 -0
  86. package/lib/bridge/transaction.js.map +1 -0
  87. package/lib/bridge/transactionStatus.d.ts +3 -0
  88. package/lib/bridge/transactionStatus.d.ts.map +1 -0
  89. package/lib/bridge/transactionStatus.js +114 -0
  90. package/lib/bridge/transactionStatus.js.map +1 -0
  91. package/lib/datasets/tezos.scanAccounts.1.d.ts +7 -0
  92. package/lib/datasets/tezos.scanAccounts.1.d.ts.map +1 -0
  93. package/lib/datasets/tezos.scanAccounts.1.js +38 -0
  94. package/lib/datasets/tezos.scanAccounts.1.js.map +1 -0
  95. package/lib/index.d.ts +3 -0
  96. package/lib/index.d.ts.map +1 -0
  97. package/lib/index.js +21 -0
  98. package/lib/index.js.map +1 -0
  99. package/lib/signer/getAddress.d.ts +6 -0
  100. package/lib/signer/getAddress.d.ts.map +1 -0
  101. package/lib/signer/getAddress.js +19 -0
  102. package/lib/signer/getAddress.js.map +1 -0
  103. package/lib/signer/index.d.ts +6 -0
  104. package/lib/signer/index.d.ts.map +1 -0
  105. package/lib/signer/index.js +11 -0
  106. package/lib/signer/index.js.map +1 -0
  107. package/lib/test/bot-deviceActions.d.ts +4 -0
  108. package/lib/test/bot-deviceActions.d.ts.map +1 -0
  109. package/lib/test/bot-deviceActions.js +74 -0
  110. package/lib/test/bot-deviceActions.js.map +1 -0
  111. package/lib/test/bot-specs.d.ts +7 -0
  112. package/lib/test/bot-specs.d.ts.map +1 -0
  113. package/lib/test/bot-specs.js +154 -0
  114. package/lib/test/bot-specs.js.map +1 -0
  115. package/lib/test/bridgeDatasetTest.d.ts +5 -0
  116. package/lib/test/bridgeDatasetTest.d.ts.map +1 -0
  117. package/lib/test/bridgeDatasetTest.js +99 -0
  118. package/lib/test/bridgeDatasetTest.js.map +1 -0
  119. package/lib/test/cli.d.ts +78 -0
  120. package/lib/test/cli.d.ts.map +1 -0
  121. package/lib/test/cli.js +97 -0
  122. package/lib/test/cli.js.map +1 -0
  123. package/lib/test/index.d.ts +2 -0
  124. package/lib/test/index.d.ts.map +1 -0
  125. package/lib/test/index.js +18 -0
  126. package/lib/test/index.js.map +1 -0
  127. package/lib/types/errors.d.ts +4 -0
  128. package/lib/types/errors.d.ts.map +1 -0
  129. package/lib/types/errors.js +6 -0
  130. package/lib/types/errors.js.map +1 -0
  131. package/lib/types/index.d.ts +4 -0
  132. package/lib/types/index.d.ts.map +1 -0
  133. package/lib/types/index.js +20 -0
  134. package/lib/types/index.js.map +1 -0
  135. package/lib/types/model.d.ts +92 -0
  136. package/lib/types/model.d.ts.map +1 -0
  137. package/lib/types/model.fixture.d.ts +5 -0
  138. package/lib/types/model.fixture.d.ts.map +1 -0
  139. package/lib/types/model.fixture.js +85 -0
  140. package/lib/types/model.fixture.js.map +1 -0
  141. package/lib/types/model.js +8 -0
  142. package/lib/types/model.js.map +1 -0
  143. package/lib/types/signer.d.ts +37 -0
  144. package/lib/types/signer.d.ts.map +1 -0
  145. package/lib/types/signer.js +3 -0
  146. package/lib/types/signer.js.map +1 -0
  147. package/lib-es/api/bakers.d.ts +14 -0
  148. package/lib-es/api/bakers.d.ts.map +1 -0
  149. package/lib-es/api/bakers.integration.test.d.ts +2 -0
  150. package/lib-es/api/bakers.integration.test.d.ts.map +1 -0
  151. package/lib-es/api/bakers.integration.test.js +56 -0
  152. package/lib-es/api/bakers.integration.test.js.map +1 -0
  153. package/lib-es/api/bakers.js +125 -0
  154. package/lib-es/api/bakers.js.map +1 -0
  155. package/lib-es/api/bakers.test.d.ts +2 -0
  156. package/lib-es/api/bakers.test.d.ts.map +1 -0
  157. package/lib-es/api/bakers.test.js +141 -0
  158. package/lib-es/api/bakers.test.js.map +1 -0
  159. package/lib-es/api/bakers.whitelist-default.d.ts +4 -0
  160. package/lib-es/api/bakers.whitelist-default.d.ts.map +1 -0
  161. package/lib-es/api/bakers.whitelist-default.js +31 -0
  162. package/lib-es/api/bakers.whitelist-default.js.map +1 -0
  163. package/lib-es/api/index.d.ts +3 -0
  164. package/lib-es/api/index.d.ts.map +1 -0
  165. package/lib-es/api/index.js +3 -0
  166. package/lib-es/api/index.js.map +1 -0
  167. package/lib-es/api/tzkt.d.ts +81 -0
  168. package/lib-es/api/tzkt.d.ts.map +1 -0
  169. package/lib-es/api/tzkt.js +47 -0
  170. package/lib-es/api/tzkt.js.map +1 -0
  171. package/lib-es/bridge/broadcast.d.ts +6 -0
  172. package/lib-es/bridge/broadcast.d.ts.map +1 -0
  173. package/lib-es/bridge/broadcast.js +20 -0
  174. package/lib-es/bridge/broadcast.js.map +1 -0
  175. package/lib-es/bridge/broadcast.test.d.ts +2 -0
  176. package/lib-es/bridge/broadcast.test.d.ts.map +1 -0
  177. package/lib-es/bridge/broadcast.test.js +35 -0
  178. package/lib-es/bridge/broadcast.test.js.map +1 -0
  179. package/lib-es/bridge/createTransaction.d.ts +3 -0
  180. package/lib-es/bridge/createTransaction.d.ts.map +1 -0
  181. package/lib-es/bridge/createTransaction.js +17 -0
  182. package/lib-es/bridge/createTransaction.js.map +1 -0
  183. package/lib-es/bridge/deviceTransactionConfig.d.ts +19 -0
  184. package/lib-es/bridge/deviceTransactionConfig.d.ts.map +1 -0
  185. package/lib-es/bridge/deviceTransactionConfig.js +42 -0
  186. package/lib-es/bridge/deviceTransactionConfig.js.map +1 -0
  187. package/lib-es/bridge/estimateMaxSpendable.d.ts +10 -0
  188. package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -0
  189. package/lib-es/bridge/estimateMaxSpendable.js +24 -0
  190. package/lib-es/bridge/estimateMaxSpendable.js.map +1 -0
  191. package/lib-es/bridge/getAccountShape.d.ts +5 -0
  192. package/lib-es/bridge/getAccountShape.d.ts.map +1 -0
  193. package/lib-es/bridge/getAccountShape.js +245 -0
  194. package/lib-es/bridge/getAccountShape.js.map +1 -0
  195. package/lib-es/bridge/getAccountShape.test.d.ts +2 -0
  196. package/lib-es/bridge/getAccountShape.test.d.ts.map +1 -0
  197. package/lib-es/bridge/getAccountShape.test.js +31 -0
  198. package/lib-es/bridge/getAccountShape.test.js.map +1 -0
  199. package/lib-es/bridge/index.d.ts +8 -0
  200. package/lib-es/bridge/index.d.ts.map +1 -0
  201. package/lib-es/bridge/index.js +51 -0
  202. package/lib-es/bridge/index.js.map +1 -0
  203. package/lib-es/bridge/preload.d.ts +9 -0
  204. package/lib-es/bridge/preload.d.ts.map +1 -0
  205. package/lib-es/bridge/preload.js +26 -0
  206. package/lib-es/bridge/preload.js.map +1 -0
  207. package/lib-es/bridge/prepareTransaction.d.ts +9 -0
  208. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -0
  209. package/lib-es/bridge/prepareTransaction.js +150 -0
  210. package/lib-es/bridge/prepareTransaction.js.map +1 -0
  211. package/lib-es/bridge/serialization.d.ts +7 -0
  212. package/lib-es/bridge/serialization.d.ts.map +1 -0
  213. package/lib-es/bridge/serialization.js +20 -0
  214. package/lib-es/bridge/serialization.js.map +1 -0
  215. package/lib-es/bridge/signOperation.d.ts +19 -0
  216. package/lib-es/bridge/signOperation.d.ts.map +1 -0
  217. package/lib-es/bridge/signOperation.js +143 -0
  218. package/lib-es/bridge/signOperation.js.map +1 -0
  219. package/lib-es/bridge/signOperation.test.d.ts +2 -0
  220. package/lib-es/bridge/signOperation.test.d.ts.map +1 -0
  221. package/lib-es/bridge/signOperation.test.js +195 -0
  222. package/lib-es/bridge/signOperation.test.js.map +1 -0
  223. package/lib-es/bridge/transaction.d.ts +15 -0
  224. package/lib-es/bridge/transaction.d.ts.map +1 -0
  225. package/lib-es/bridge/transaction.js +46 -0
  226. package/lib-es/bridge/transaction.js.map +1 -0
  227. package/lib-es/bridge/transactionStatus.d.ts +3 -0
  228. package/lib-es/bridge/transactionStatus.d.ts.map +1 -0
  229. package/lib-es/bridge/transactionStatus.js +107 -0
  230. package/lib-es/bridge/transactionStatus.js.map +1 -0
  231. package/lib-es/datasets/tezos.scanAccounts.1.d.ts +7 -0
  232. package/lib-es/datasets/tezos.scanAccounts.1.d.ts.map +1 -0
  233. package/lib-es/datasets/tezos.scanAccounts.1.js +36 -0
  234. package/lib-es/datasets/tezos.scanAccounts.1.js.map +1 -0
  235. package/lib-es/index.d.ts +3 -0
  236. package/lib-es/index.d.ts.map +1 -0
  237. package/lib-es/index.js +3 -0
  238. package/lib-es/index.js.map +1 -0
  239. package/lib-es/signer/getAddress.d.ts +6 -0
  240. package/lib-es/signer/getAddress.d.ts.map +1 -0
  241. package/lib-es/signer/getAddress.js +17 -0
  242. package/lib-es/signer/getAddress.js.map +1 -0
  243. package/lib-es/signer/index.d.ts +6 -0
  244. package/lib-es/signer/index.d.ts.map +1 -0
  245. package/lib-es/signer/index.js +6 -0
  246. package/lib-es/signer/index.js.map +1 -0
  247. package/lib-es/test/bot-deviceActions.d.ts +4 -0
  248. package/lib-es/test/bot-deviceActions.d.ts.map +1 -0
  249. package/lib-es/test/bot-deviceActions.js +71 -0
  250. package/lib-es/test/bot-deviceActions.js.map +1 -0
  251. package/lib-es/test/bot-specs.d.ts +7 -0
  252. package/lib-es/test/bot-specs.d.ts.map +1 -0
  253. package/lib-es/test/bot-specs.js +149 -0
  254. package/lib-es/test/bot-specs.js.map +1 -0
  255. package/lib-es/test/bridgeDatasetTest.d.ts +5 -0
  256. package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -0
  257. package/lib-es/test/bridgeDatasetTest.js +93 -0
  258. package/lib-es/test/bridgeDatasetTest.js.map +1 -0
  259. package/lib-es/test/cli.d.ts +78 -0
  260. package/lib-es/test/cli.d.ts.map +1 -0
  261. package/lib-es/test/cli.js +91 -0
  262. package/lib-es/test/cli.js.map +1 -0
  263. package/lib-es/test/index.d.ts +2 -0
  264. package/lib-es/test/index.d.ts.map +1 -0
  265. package/lib-es/test/index.js +2 -0
  266. package/lib-es/test/index.js.map +1 -0
  267. package/lib-es/types/errors.d.ts +4 -0
  268. package/lib-es/types/errors.d.ts.map +1 -0
  269. package/lib-es/types/errors.js +3 -0
  270. package/lib-es/types/errors.js.map +1 -0
  271. package/lib-es/types/index.d.ts +4 -0
  272. package/lib-es/types/index.d.ts.map +1 -0
  273. package/lib-es/types/index.js +4 -0
  274. package/lib-es/types/index.js.map +1 -0
  275. package/lib-es/types/model.d.ts +92 -0
  276. package/lib-es/types/model.d.ts.map +1 -0
  277. package/lib-es/types/model.fixture.d.ts +5 -0
  278. package/lib-es/types/model.fixture.d.ts.map +1 -0
  279. package/lib-es/types/model.fixture.js +76 -0
  280. package/lib-es/types/model.fixture.js.map +1 -0
  281. package/lib-es/types/model.js +4 -0
  282. package/lib-es/types/model.js.map +1 -0
  283. package/lib-es/types/signer.d.ts +37 -0
  284. package/lib-es/types/signer.d.ts.map +1 -0
  285. package/lib-es/types/signer.js +2 -0
  286. package/lib-es/types/signer.js.map +1 -0
  287. package/package.json +116 -0
  288. package/src/README.md +29 -0
  289. package/src/api/bakers.integration.test.ts +61 -0
  290. package/src/api/bakers.test.ts +140 -0
  291. package/src/api/bakers.ts +139 -0
  292. package/src/api/bakers.whitelist-default.ts +33 -0
  293. package/src/api/index.ts +2 -0
  294. package/src/api/tzkt.ts +112 -0
  295. package/src/bridge/broadcast.test.ts +30 -0
  296. package/src/bridge/broadcast.ts +18 -0
  297. package/src/bridge/createTransaction.ts +18 -0
  298. package/src/bridge/deviceTransactionConfig.ts +74 -0
  299. package/src/bridge/estimateMaxSpendable.ts +32 -0
  300. package/src/bridge/getAccountShape.test.ts +22 -0
  301. package/src/bridge/getAccountShape.ts +289 -0
  302. package/src/bridge/index.ts +65 -0
  303. package/src/bridge/preload.ts +18 -0
  304. package/src/bridge/prepareTransaction.ts +160 -0
  305. package/src/bridge/serialization.ts +27 -0
  306. package/src/bridge/signOperation.test.ts +211 -0
  307. package/src/bridge/signOperation.ts +213 -0
  308. package/src/bridge/transaction.ts +94 -0
  309. package/src/bridge/transactionStatus.ts +130 -0
  310. package/src/datasets/tezos.scanAccounts.1.ts +35 -0
  311. package/src/index.ts +3 -0
  312. package/src/signer/getAddress.ts +13 -0
  313. package/src/signer/index.ts +7 -0
  314. package/src/test/bot-deviceActions.ts +79 -0
  315. package/src/test/bot-specs.ts +152 -0
  316. package/src/test/bridgeDatasetTest.ts +132 -0
  317. package/src/test/cli.ts +137 -0
  318. package/src/test/index.ts +1 -0
  319. package/src/types/errors.ts +5 -0
  320. package/src/types/index.ts +3 -0
  321. package/src/types/model.fixture.ts +89 -0
  322. package/src/types/model.ts +123 -0
  323. package/src/types/signer.ts +48 -0
  324. package/tsconfig.json +13 -0
  325. package/types/@taquito/ledger-signer/index.d.ts +3 -0
@@ -0,0 +1,27 @@
1
+ import type { TezosAccount, TezosAccountRaw, TezosResources, TezosResourcesRaw } from "../types";
2
+ import { Account, AccountRaw } from "@ledgerhq/types-live";
3
+
4
+ export function toTezosResourcesRaw(r: TezosResources): TezosResourcesRaw {
5
+ const { revealed, counter } = r;
6
+ return { revealed, counter };
7
+ }
8
+
9
+ export function fromTezosResourcesRaw(r: TezosResourcesRaw): TezosResources {
10
+ const { revealed, counter } = r;
11
+ return { revealed, counter };
12
+ }
13
+
14
+ export function assignToAccountRaw(account: Account, accountRaw: AccountRaw) {
15
+ const tezosAccount = account as TezosAccount;
16
+ if (tezosAccount.tezosResources) {
17
+ (accountRaw as TezosAccountRaw).tezosResources = toTezosResourcesRaw(
18
+ tezosAccount.tezosResources,
19
+ );
20
+ }
21
+ }
22
+
23
+ export function assignFromAccountRaw(accountRaw: AccountRaw, account: Account) {
24
+ const tezosResourcesRaw = (accountRaw as TezosAccountRaw).tezosResources;
25
+ if (tezosResourcesRaw)
26
+ (account as TezosAccount).tezosResources = fromTezosResourcesRaw(tezosResourcesRaw);
27
+ }
@@ -0,0 +1,211 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { OpKind, TezosToolkit } from "@taquito/taquito";
3
+ import { SignOperationEvent } from "@ledgerhq/types-live";
4
+ import buildSignOperation, { getOperationContents } from "./signOperation";
5
+ import { TezosSigner } from "../types";
6
+ import { createFixtureAccount, createFixtureTransaction } from "../types/model.fixture";
7
+
8
+ const mockForgeOperations = jest.fn().mockResolvedValue("FORGED_OP");
9
+ jest.mock("@taquito/taquito", () => ({
10
+ ...jest.requireActual("@taquito/taquito"),
11
+ TezosToolkit: jest.fn().mockReturnValue({
12
+ setProvider: jest.fn(),
13
+ rpc: {
14
+ getBlock: jest.fn().mockResolvedValue({ hash: "hash" }),
15
+ getContract: jest.fn().mockResolvedValue({ counter: "12" }),
16
+ forgeOperations: () => mockForgeOperations(),
17
+ },
18
+ }),
19
+ }));
20
+
21
+ describe("signOperation", () => {
22
+ const mockSign = jest.fn().mockResolvedValue({
23
+ bytes: "SIG_BYTES",
24
+ sig: "SIG",
25
+ prefixSig: "PREFIX_SIG",
26
+ sbytes: "03SBYTES",
27
+ });
28
+ const fakeSigner = {
29
+ getAddress: jest.fn(),
30
+ signOperation: jest.fn(),
31
+ createLedgerSigner: () => ({
32
+ publicKey: () => Promise.resolve("PUBKEY"),
33
+ publicKeyHash: () => Promise.resolve("PUBKEYHASH"),
34
+ sign: () => mockSign(),
35
+ secretKey: () => Promise.resolve(undefined),
36
+ }),
37
+ };
38
+ const signerContext = <T>(_deviceId: string, fn: (signer: TezosSigner) => Promise<T>) =>
39
+ fn(fakeSigner);
40
+ const signOperation = buildSignOperation(signerContext);
41
+ const deviceId = "dummyDeviceId";
42
+
43
+ afterEach(() => {
44
+ mockForgeOperations.mockClear();
45
+ mockSign.mockClear();
46
+ });
47
+
48
+ it("returns events in the right order", done => {
49
+ // GIVEN
50
+ const account = createFixtureAccount();
51
+ const transaction = createFixtureTransaction({ fees: BigNumber(0) });
52
+
53
+ // WHEN & THEN
54
+ const expectedEvent = [
55
+ {
56
+ type: "device-signature-requested",
57
+ },
58
+ {
59
+ type: "device-signature-granted",
60
+ },
61
+ {
62
+ type: "signed",
63
+ },
64
+ ];
65
+ let eventIdx = 0;
66
+ signOperation({ account, deviceId, transaction }).forEach(e => {
67
+ try {
68
+ expect(e.type).toEqual(expectedEvent[eventIdx].type);
69
+ eventIdx++;
70
+
71
+ if (eventIdx === expectedEvent.length) {
72
+ done();
73
+ }
74
+ } catch (err) {
75
+ done(err);
76
+ }
77
+ });
78
+ });
79
+
80
+ it("returns signature value from LedgerSigner", done => {
81
+ // GIVEN
82
+ const account = createFixtureAccount();
83
+ const transaction = createFixtureTransaction({ fees: new BigNumber(0) });
84
+
85
+ // WHEN & THEN
86
+ const subscriber = signOperation({ account, deviceId, transaction }).subscribe(
87
+ (e: SignOperationEvent) => {
88
+ if (e.type === "signed") {
89
+ const signature = e.signedOperation.signature;
90
+ expect(signature).toEqual("SBYTES");
91
+ expect(mockSign).toHaveBeenCalledTimes(1);
92
+ expect(mockForgeOperations).toHaveBeenCalledTimes(1);
93
+
94
+ // Cleanup
95
+ subscriber.unsubscribe();
96
+ done();
97
+ }
98
+ },
99
+ );
100
+ });
101
+ });
102
+
103
+ describe("getOperationContents - revealed account", () => {
104
+ const tezos = new TezosToolkit("MOCK_API_KEY");
105
+ const account = createFixtureAccount({ freshAddress: "tz1addr" });
106
+
107
+ it("mode - send", async () => {
108
+ const transaction = createFixtureTransaction({
109
+ family: "tezos",
110
+ amount: new BigNumber(0),
111
+ recipient: "RECIPIENT_ADD",
112
+ fees: new BigNumber(0),
113
+ mode: "send",
114
+ gasLimit: new BigNumber(0),
115
+ storageLimit: new BigNumber(0),
116
+ });
117
+
118
+ const { type, contents } = await getOperationContents({
119
+ account,
120
+ transaction,
121
+ tezos,
122
+ counter: 0,
123
+ public_key: "pk",
124
+ public_key_hash: "pkh",
125
+ });
126
+
127
+ expect(type).toBe("OUT");
128
+ expect(contents.length).toEqual(1);
129
+ expect(contents).toStrictEqual([
130
+ {
131
+ kind: OpKind.TRANSACTION,
132
+ amount: transaction.amount.toString(),
133
+ destination: transaction.recipient,
134
+ source: "tz1addr",
135
+ counter: "1",
136
+ fee: new BigNumber(0).toString(),
137
+ gas_limit: new BigNumber(0).toString(),
138
+ storage_limit: new BigNumber(0).toString(),
139
+ },
140
+ ]);
141
+ });
142
+
143
+ it("mode - delegate", async () => {
144
+ const transaction = createFixtureTransaction({
145
+ family: "tezos",
146
+ amount: new BigNumber(0),
147
+ recipient: "RECIPIENT_ADD",
148
+ fees: new BigNumber(0),
149
+ mode: "delegate",
150
+ gasLimit: new BigNumber(0),
151
+ storageLimit: new BigNumber(0),
152
+ });
153
+
154
+ const { type, contents } = await getOperationContents({
155
+ account,
156
+ transaction,
157
+ tezos,
158
+ counter: 0,
159
+ public_key: "pk",
160
+ public_key_hash: "pkh",
161
+ });
162
+
163
+ expect(type).toBe("DELEGATE");
164
+ expect(contents.length).toEqual(1);
165
+ expect(contents).toStrictEqual([
166
+ {
167
+ kind: OpKind.DELEGATION,
168
+ source: "tz1addr",
169
+ counter: "1",
170
+ fee: new BigNumber(0).toString(),
171
+ gas_limit: new BigNumber(0).toString(),
172
+ storage_limit: new BigNumber(0).toString(),
173
+ delegate: transaction.recipient,
174
+ },
175
+ ]);
176
+ });
177
+
178
+ it("mode - undelegate", async () => {
179
+ const transaction = createFixtureTransaction({
180
+ family: "tezos",
181
+ amount: new BigNumber(0),
182
+ recipient: "",
183
+ fees: new BigNumber(0),
184
+ mode: "undelegate",
185
+ gasLimit: new BigNumber(0),
186
+ storageLimit: new BigNumber(0),
187
+ });
188
+
189
+ const { type, contents } = await getOperationContents({
190
+ account,
191
+ transaction,
192
+ tezos,
193
+ counter: 0,
194
+ public_key: "pk",
195
+ public_key_hash: "pkh",
196
+ });
197
+
198
+ expect(type).toBe("UNDELEGATE");
199
+ expect(contents.length).toEqual(1);
200
+ expect(contents).toStrictEqual([
201
+ {
202
+ kind: OpKind.DELEGATION,
203
+ source: "tz1addr",
204
+ counter: "1",
205
+ fee: new BigNumber(0).toString(),
206
+ gas_limit: new BigNumber(0).toString(),
207
+ storage_limit: new BigNumber(0).toString(),
208
+ },
209
+ ]);
210
+ });
211
+ });
@@ -0,0 +1,213 @@
1
+ import { Observable } from "rxjs";
2
+ import { DEFAULT_FEE, OpKind, TezosToolkit } from "@taquito/taquito";
3
+ import { type OperationContents } from "@taquito/rpc";
4
+ import type {
5
+ OperationType,
6
+ SignOperationEvent,
7
+ SignOperationFnSignature,
8
+ } from "@ledgerhq/types-live";
9
+ import { getEnv } from "@ledgerhq/live-env";
10
+ import { FeeNotLoaded } from "@ledgerhq/errors";
11
+ import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
12
+ import type { TezosAccount, TezosOperation, TezosSigner, Transaction } from "../types";
13
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
14
+
15
+ export async function getOperationContents({
16
+ account,
17
+ transaction,
18
+ tezos,
19
+ counter,
20
+ public_key,
21
+ public_key_hash,
22
+ }: {
23
+ account: TezosAccount;
24
+ transaction: Transaction;
25
+ tezos: TezosToolkit;
26
+ counter: number;
27
+ public_key: string;
28
+ public_key_hash: string;
29
+ }) {
30
+ let type: OperationType = "NONE";
31
+ const { freshAddress } = account;
32
+
33
+ const transactionFees = {
34
+ fee: (transaction.fees || 0).toString(),
35
+ gas_limit: (transaction.gasLimit || 0).toString(),
36
+ storage_limit: (transaction.storageLimit || 0).toString(),
37
+ };
38
+
39
+ const contents: OperationContents[] = [];
40
+
41
+ if (!account.tezosResources.revealed) {
42
+ const revealFees = await tezos.estimate.reveal();
43
+
44
+ contents.push({
45
+ kind: OpKind.REVEAL,
46
+ fee: DEFAULT_FEE.REVEAL.toString(),
47
+ gas_limit: (revealFees?.gasLimit || 0).toString(),
48
+ storage_limit: (revealFees?.storageLimit || 0).toString(),
49
+ source: public_key_hash,
50
+ counter: (counter + 1).toString(),
51
+ public_key,
52
+ });
53
+ }
54
+
55
+ switch (transaction.mode) {
56
+ case "send": {
57
+ type = "OUT";
58
+
59
+ contents.push({
60
+ kind: OpKind.TRANSACTION,
61
+ amount: transaction.amount.toString(),
62
+ destination: transaction.recipient,
63
+ source: freshAddress,
64
+ counter: (counter + 1 + contents.length).toString(),
65
+ ...transactionFees,
66
+ });
67
+
68
+ break;
69
+ }
70
+ case "delegate": {
71
+ type = "DELEGATE";
72
+
73
+ contents.push({
74
+ kind: OpKind.DELEGATION,
75
+ source: freshAddress,
76
+ counter: (counter + 1 + contents.length).toString(),
77
+ delegate: transaction.recipient,
78
+ ...transactionFees,
79
+ });
80
+
81
+ break;
82
+ }
83
+ case "undelegate": {
84
+ type = "UNDELEGATE";
85
+
86
+ // we undelegate as there's no "delegate" field
87
+ // OpKind is still "DELEGATION"
88
+ contents.push({
89
+ kind: OpKind.DELEGATION,
90
+ source: freshAddress,
91
+ counter: (counter + 1 + contents.length).toString(),
92
+ ...transactionFees,
93
+ });
94
+
95
+ break;
96
+ }
97
+ default:
98
+ throw new Error("not supported");
99
+ }
100
+
101
+ return { type, contents };
102
+ }
103
+
104
+ const buildSignOperation =
105
+ (signerContext: SignerContext<TezosSigner>): SignOperationFnSignature<Transaction> =>
106
+ ({ account, deviceId, transaction }): Observable<SignOperationEvent> =>
107
+ new Observable(o => {
108
+ let cancelled = false;
109
+
110
+ async function main() {
111
+ const { fees } = transaction;
112
+ if (!fees) throw new FeeNotLoaded();
113
+
114
+ const { freshAddressPath, freshAddress } = account;
115
+
116
+ const tezos = new TezosToolkit(getEnv("API_TEZOS_NODE"));
117
+
118
+ const signedInfo = await signerContext(deviceId, async signer => {
119
+ const ledgerSigner = signer.createLedgerSigner(freshAddressPath, false, 0);
120
+
121
+ tezos.setProvider({ signer: ledgerSigner });
122
+
123
+ const publicKey = await ledgerSigner.publicKey();
124
+ const publicKeyHash = await ledgerSigner.publicKeyHash();
125
+
126
+ const { rpc } = tezos;
127
+ const block = await rpc.getBlock();
128
+ const sourceData = await rpc.getContract(freshAddress);
129
+
130
+ o.next({ type: "device-signature-requested" });
131
+
132
+ if (cancelled) {
133
+ return;
134
+ }
135
+
136
+ const { type, contents } = await getOperationContents({
137
+ account: account as TezosAccount,
138
+ transaction,
139
+ tezos,
140
+ counter: Number(sourceData.counter),
141
+ public_key: publicKey,
142
+ public_key_hash: publicKeyHash,
143
+ });
144
+
145
+ const forgedBytes = await rpc.forgeOperations({
146
+ branch: block.hash,
147
+ contents,
148
+ });
149
+
150
+ // 0x03 is a conventional prefix (aka a watermark) for tezos transactions
151
+ const signature = await ledgerSigner.sign(
152
+ Buffer.concat([Buffer.from("03", "hex"), Buffer.from(forgedBytes, "hex")]).toString(
153
+ "hex",
154
+ ),
155
+ );
156
+
157
+ return {
158
+ type,
159
+ signature,
160
+ };
161
+ });
162
+
163
+ if (!signedInfo) {
164
+ return;
165
+ }
166
+ const { type, signature } = signedInfo;
167
+
168
+ o.next({ type: "device-signature-granted" });
169
+
170
+ // build optimistic operation
171
+ const txHash = ""; // resolved at broadcast time
172
+ const senders = [freshAddress];
173
+ const recipients = [transaction.recipient];
174
+ const accountId = account.id;
175
+
176
+ // currently, all mode are always at least one OUT tx on ETH parent
177
+ const operation: TezosOperation = {
178
+ id: encodeOperationId(accountId, txHash, type),
179
+ hash: txHash,
180
+ type,
181
+ value: transaction.amount,
182
+ fee: fees,
183
+ extra: {},
184
+ blockHash: null,
185
+ blockHeight: null,
186
+ senders,
187
+ recipients,
188
+ accountId,
189
+ date: new Date(),
190
+ };
191
+
192
+ o.next({
193
+ type: "signed",
194
+ signedOperation: {
195
+ operation,
196
+ // we slice the signature to remove the `03` prefix
197
+ // which souldn't be included in the signature
198
+ signature: signature.sbytes.slice(2),
199
+ },
200
+ });
201
+ }
202
+
203
+ main().then(
204
+ () => o.complete(),
205
+ e => o.error(e),
206
+ );
207
+
208
+ return () => {
209
+ cancelled = true;
210
+ };
211
+ });
212
+
213
+ export default buildSignOperation;
@@ -0,0 +1,94 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import type { Transaction, TransactionRaw } from "../types";
3
+ import { formatTransactionStatus } from "@ledgerhq/coin-framework/formatters";
4
+ import {
5
+ fromTransactionCommonRaw,
6
+ fromTransactionStatusRawCommon as fromTransactionStatusRaw,
7
+ toTransactionCommonRaw,
8
+ toTransactionStatusRawCommon as toTransactionStatusRaw,
9
+ } from "@ledgerhq/coin-framework/serialization";
10
+ import type { Account } from "@ledgerhq/types-live";
11
+ import { getAccountCurrency } from "@ledgerhq/coin-framework/account/index";
12
+ import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
13
+
14
+ export const formatTransaction = (
15
+ {
16
+ mode,
17
+ subAccountId,
18
+ amount,
19
+ recipient,
20
+ gasLimit,
21
+ storageLimit,
22
+ fees,
23
+ useAllAmount,
24
+ estimatedFees,
25
+ }: Transaction,
26
+ mainAccount: Account,
27
+ ): string => {
28
+ const account =
29
+ (subAccountId && (mainAccount.subAccounts || []).find(a => a.id === subAccountId)) ||
30
+ mainAccount;
31
+ return `
32
+ ${mode.toUpperCase()} ${
33
+ useAllAmount
34
+ ? "MAX"
35
+ : formatCurrencyUnit(getAccountCurrency(account).units[0], amount, {
36
+ showCode: true,
37
+ disableRounding: true,
38
+ })
39
+ }
40
+ TO ${recipient}
41
+ with fees=${!fees ? "?" : formatCurrencyUnit(mainAccount.currency.units[0], fees)}
42
+ with gasLimit=${!gasLimit ? "?" : gasLimit.toString()}
43
+ with storageLimit=${!storageLimit ? "?" : storageLimit.toString()}
44
+ (estimatedFees ${
45
+ !estimatedFees ? "?" : formatCurrencyUnit(mainAccount.currency.units[0], estimatedFees)
46
+ })`;
47
+ };
48
+
49
+ export const fromTransactionRaw = (tr: TransactionRaw): Transaction => {
50
+ const common = fromTransactionCommonRaw(tr);
51
+ const { networkInfo } = tr;
52
+ return {
53
+ ...common,
54
+ family: tr.family,
55
+ mode: tr.mode,
56
+ networkInfo: networkInfo && {
57
+ family: networkInfo.family,
58
+ fees: new BigNumber(networkInfo.fees),
59
+ },
60
+ fees: tr.fees ? new BigNumber(tr.fees) : null,
61
+ gasLimit: tr.gasLimit ? new BigNumber(tr.gasLimit) : null,
62
+ storageLimit: tr.storageLimit ? new BigNumber(tr.storageLimit) : null,
63
+ estimatedFees: tr.estimatedFees ? new BigNumber(tr.estimatedFees) : null,
64
+ taquitoError: tr.taquitoError,
65
+ };
66
+ };
67
+
68
+ export const toTransactionRaw = (t: Transaction): TransactionRaw => {
69
+ const common = toTransactionCommonRaw(t);
70
+ const { networkInfo } = t;
71
+ return {
72
+ ...common,
73
+ family: t.family,
74
+ mode: t.mode,
75
+ networkInfo: networkInfo && {
76
+ family: networkInfo.family,
77
+ fees: networkInfo.fees.toString(),
78
+ },
79
+ fees: t.fees ? t.fees.toString() : null,
80
+ gasLimit: t.gasLimit ? t.gasLimit.toString() : null,
81
+ storageLimit: t.storageLimit ? t.storageLimit.toString() : null,
82
+ estimatedFees: t.estimatedFees ? t.estimatedFees.toString() : null,
83
+ taquitoError: t.taquitoError,
84
+ };
85
+ };
86
+
87
+ export default {
88
+ formatTransaction,
89
+ fromTransactionRaw,
90
+ toTransactionRaw,
91
+ fromTransactionStatusRaw,
92
+ toTransactionStatusRaw,
93
+ formatTransactionStatus,
94
+ };
@@ -0,0 +1,130 @@
1
+ import BigNumber from "bignumber.js";
2
+ import {
3
+ AmountRequired,
4
+ FeeTooHigh,
5
+ InvalidAddressBecauseDestinationIsAlsoSource,
6
+ NotEnoughBalance,
7
+ NotEnoughBalanceBecauseDestinationNotCreated,
8
+ NotEnoughBalanceToDelegate,
9
+ RecommendUndelegation,
10
+ } from "@ledgerhq/errors";
11
+ import { log } from "@ledgerhq/logs";
12
+ import { TezosAccount, Transaction, TransactionStatus } from "../types";
13
+ import { InvalidAddressBecauseAlreadyDelegated } from "../types/errors";
14
+ import api from "../api/tzkt";
15
+ import { isAccountDelegating } from "../api/bakers";
16
+ import { validateRecipient } from "./prepareTransaction";
17
+
18
+ const EXISTENTIAL_DEPOSIT = new BigNumber(275000);
19
+
20
+ export const getTransactionStatus = async (
21
+ account: TezosAccount,
22
+ t: Transaction,
23
+ ): Promise<TransactionStatus> => {
24
+ const errors: {
25
+ recipient?: Error;
26
+ amount?: Error;
27
+ fees?: Error;
28
+ } = {};
29
+
30
+ const warnings: {
31
+ amount?: Error;
32
+ feeTooHigh?: Error;
33
+ recipient?: Error;
34
+ } = {};
35
+ let resetTotalSpent = false;
36
+
37
+ // Recipient validation logic
38
+ if (t.mode !== "undelegate") {
39
+ if (account.freshAddress === t.recipient) {
40
+ errors.recipient = new InvalidAddressBecauseDestinationIsAlsoSource();
41
+ } else {
42
+ const { recipientError, recipientWarning } = await validateRecipient(
43
+ account.currency,
44
+ t.recipient,
45
+ );
46
+ if (recipientError) {
47
+ errors.recipient = recipientError;
48
+ }
49
+ if (recipientWarning) {
50
+ warnings.recipient = recipientWarning;
51
+ }
52
+ }
53
+ }
54
+
55
+ // Pre validation of amount field
56
+ const estimatedFees = t.estimatedFees || new BigNumber(0);
57
+ if (t.mode === "send") {
58
+ if (!errors.amount && t.amount.eq(0) && !t.useAllAmount) {
59
+ resetTotalSpent = true;
60
+ errors.amount = new AmountRequired();
61
+ } else if (t.amount.gt(0) && estimatedFees.times(10).gt(t.amount)) {
62
+ warnings.feeTooHigh = new FeeTooHigh();
63
+ }
64
+ const thresholdWarning = 0.5 * 10 ** account.currency.units[0].magnitude;
65
+ if (
66
+ !errors.amount &&
67
+ account.balance.minus(t.amount).minus(estimatedFees).lt(thresholdWarning)
68
+ ) {
69
+ if (isAccountDelegating(account)) {
70
+ if (t.useAllAmount) {
71
+ errors.amount = new RecommendUndelegation();
72
+ } else {
73
+ warnings.amount = new RecommendUndelegation();
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ // effective amount
80
+ // if we also have taquitoError, we interprete them and they override the previously inferred errors
81
+ if (t.taquitoError) {
82
+ log("taquitoerror", String(t.taquitoError));
83
+
84
+ // remap taquito errors
85
+ if (
86
+ t.taquitoError.endsWith("balance_too_low") ||
87
+ t.taquitoError.endsWith("subtraction_underflow")
88
+ ) {
89
+ if (t.mode === "send") {
90
+ resetTotalSpent = true;
91
+ errors.amount = new NotEnoughBalance();
92
+ } else {
93
+ errors.amount = new NotEnoughBalanceToDelegate();
94
+ }
95
+ } else if (t.taquitoError.endsWith("delegate.unchanged")) {
96
+ errors.recipient = new InvalidAddressBecauseAlreadyDelegated();
97
+ } else if (!errors.amount) {
98
+ // unidentified error case
99
+ errors.amount = new Error(t.taquitoError);
100
+ resetTotalSpent = true;
101
+ }
102
+ }
103
+
104
+ if (!errors.amount && account.balance.lte(0)) {
105
+ resetTotalSpent = true;
106
+ errors.amount = new NotEnoughBalance();
107
+ }
108
+
109
+ // Catch a specific case that requires a minimum amount
110
+ if (
111
+ !errors.amount &&
112
+ t.mode === "send" &&
113
+ t.amount.lt(EXISTENTIAL_DEPOSIT) &&
114
+ (await api.getAccountByAddress(t.recipient)).type === "empty"
115
+ ) {
116
+ resetTotalSpent = true;
117
+ errors.amount = new NotEnoughBalanceBecauseDestinationNotCreated("", {
118
+ minimalAmount: "0.275 XTZ",
119
+ });
120
+ }
121
+
122
+ const result = {
123
+ errors,
124
+ warnings,
125
+ estimatedFees,
126
+ amount: t.amount,
127
+ totalSpent: resetTotalSpent ? new BigNumber(0) : t.amount.plus(estimatedFees),
128
+ };
129
+ return Promise.resolve(result);
130
+ };