@ledgerhq/coin-internet_computer 1.9.0-nightly.8 → 1.9.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 (106) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +20 -73
  3. package/lib/api/api.d.ts +11 -6
  4. package/lib/api/api.d.ts.map +1 -1
  5. package/lib/api/api.js +64 -84
  6. package/lib/api/api.js.map +1 -1
  7. package/lib/bridge/bridgeHelpers/account.d.ts.map +1 -1
  8. package/lib/bridge/bridgeHelpers/account.js +33 -52
  9. package/lib/bridge/bridgeHelpers/account.js.map +1 -1
  10. package/lib/bridge/bridgeHelpers/addresses.d.ts +6 -0
  11. package/lib/bridge/bridgeHelpers/addresses.d.ts.map +1 -1
  12. package/lib/bridge/bridgeHelpers/addresses.js +29 -1
  13. package/lib/bridge/bridgeHelpers/addresses.js.map +1 -1
  14. package/lib/bridge/bridgeHelpers/icpRosetta/index.d.ts +30 -0
  15. package/lib/bridge/bridgeHelpers/icpRosetta/index.d.ts.map +1 -0
  16. package/lib/bridge/bridgeHelpers/icpRosetta/index.js +88 -0
  17. package/lib/bridge/bridgeHelpers/icpRosetta/index.js.map +1 -0
  18. package/lib/bridge/bridgeHelpers/icpRosetta/types.d.ts +145 -0
  19. package/lib/bridge/bridgeHelpers/icpRosetta/types.d.ts.map +1 -0
  20. package/lib/bridge/bridgeHelpers/icpRosetta/types.js +3 -0
  21. package/lib/bridge/bridgeHelpers/icpRosetta/types.js.map +1 -0
  22. package/lib/bridge/bridgeHelpers/icpRosetta/utils.d.ts +17 -0
  23. package/lib/bridge/bridgeHelpers/icpRosetta/utils.d.ts.map +1 -0
  24. package/lib/bridge/bridgeHelpers/icpRosetta/utils.js +155 -0
  25. package/lib/bridge/bridgeHelpers/icpRosetta/utils.js.map +1 -0
  26. package/lib/bridge/broadcast.d.ts.map +1 -1
  27. package/lib/bridge/broadcast.js +6 -22
  28. package/lib/bridge/broadcast.js.map +1 -1
  29. package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
  30. package/lib/bridge/getTransactionStatus.js +3 -4
  31. package/lib/bridge/getTransactionStatus.js.map +1 -1
  32. package/lib/bridge/prepareTransaction.d.ts.map +1 -1
  33. package/lib/bridge/prepareTransaction.js +1 -2
  34. package/lib/bridge/prepareTransaction.js.map +1 -1
  35. package/lib/bridge/signOperation.d.ts +2 -2
  36. package/lib/bridge/signOperation.d.ts.map +1 -1
  37. package/lib/bridge/signOperation.js +13 -44
  38. package/lib/bridge/signOperation.js.map +1 -1
  39. package/lib/consts.d.ts +0 -2
  40. package/lib/consts.d.ts.map +1 -1
  41. package/lib/consts.js +1 -8
  42. package/lib/consts.js.map +1 -1
  43. package/lib/hw-signMessage.d.ts.map +1 -1
  44. package/lib/hw-signMessage.js +2 -1
  45. package/lib/hw-signMessage.js.map +1 -1
  46. package/lib/types/signer.d.ts +1 -1
  47. package/lib/types/signer.d.ts.map +1 -1
  48. package/lib-es/api/api.d.ts +11 -6
  49. package/lib-es/api/api.d.ts.map +1 -1
  50. package/lib-es/api/api.js +60 -81
  51. package/lib-es/api/api.js.map +1 -1
  52. package/lib-es/bridge/bridgeHelpers/account.d.ts.map +1 -1
  53. package/lib-es/bridge/bridgeHelpers/account.js +33 -52
  54. package/lib-es/bridge/bridgeHelpers/account.js.map +1 -1
  55. package/lib-es/bridge/bridgeHelpers/addresses.d.ts +6 -0
  56. package/lib-es/bridge/bridgeHelpers/addresses.d.ts.map +1 -1
  57. package/lib-es/bridge/bridgeHelpers/addresses.js +23 -0
  58. package/lib-es/bridge/bridgeHelpers/addresses.js.map +1 -1
  59. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.d.ts +30 -0
  60. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.d.ts.map +1 -0
  61. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.js +76 -0
  62. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.js.map +1 -0
  63. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.d.ts +145 -0
  64. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.d.ts.map +1 -0
  65. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.js +2 -0
  66. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.js.map +1 -0
  67. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.d.ts +17 -0
  68. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.d.ts.map +1 -0
  69. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.js +123 -0
  70. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.js.map +1 -0
  71. package/lib-es/bridge/broadcast.d.ts.map +1 -1
  72. package/lib-es/bridge/broadcast.js +6 -19
  73. package/lib-es/bridge/broadcast.js.map +1 -1
  74. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
  75. package/lib-es/bridge/getTransactionStatus.js +1 -2
  76. package/lib-es/bridge/getTransactionStatus.js.map +1 -1
  77. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
  78. package/lib-es/bridge/prepareTransaction.js +1 -2
  79. package/lib-es/bridge/prepareTransaction.js.map +1 -1
  80. package/lib-es/bridge/signOperation.d.ts +2 -2
  81. package/lib-es/bridge/signOperation.d.ts.map +1 -1
  82. package/lib-es/bridge/signOperation.js +13 -41
  83. package/lib-es/bridge/signOperation.js.map +1 -1
  84. package/lib-es/consts.d.ts +0 -2
  85. package/lib-es/consts.d.ts.map +1 -1
  86. package/lib-es/consts.js +0 -3
  87. package/lib-es/consts.js.map +1 -1
  88. package/lib-es/hw-signMessage.d.ts.map +1 -1
  89. package/lib-es/hw-signMessage.js +2 -1
  90. package/lib-es/hw-signMessage.js.map +1 -1
  91. package/lib-es/types/signer.d.ts +1 -1
  92. package/lib-es/types/signer.d.ts.map +1 -1
  93. package/package.json +13 -7
  94. package/src/api/api.ts +71 -126
  95. package/src/bridge/bridgeHelpers/account.ts +43 -70
  96. package/src/bridge/bridgeHelpers/addresses.ts +25 -0
  97. package/src/bridge/bridgeHelpers/icpRosetta/index.ts +154 -0
  98. package/src/bridge/bridgeHelpers/icpRosetta/types.ts +166 -0
  99. package/src/bridge/bridgeHelpers/icpRosetta/utils.ts +151 -0
  100. package/src/bridge/broadcast.ts +6 -31
  101. package/src/bridge/getTransactionStatus.ts +1 -2
  102. package/src/bridge/prepareTransaction.ts +1 -2
  103. package/src/bridge/signOperation.ts +18 -68
  104. package/src/consts.ts +0 -10
  105. package/src/hw-signMessage.ts +6 -1
  106. package/src/types/signer.ts +1 -1
@@ -0,0 +1,154 @@
1
+ import { Account } from "@ledgerhq/types-live";
2
+ import { Transaction } from "../../../types";
3
+ import { constructionInvoke, getICPRosettaNetworkIdentifier } from "../../../api";
4
+ import {
5
+ ICPRosettaConstructionCombineRequest,
6
+ ICPRosettaConstructionCombineResponse,
7
+ ICPRosettaConstructionHashRequest,
8
+ ICPRosettaConstructionHashResponse,
9
+ ICPRosettaConstructionPayloadsRequest,
10
+ ICPRosettaConstructionPayloadsResponse,
11
+ ICPRosettaConstructionSubmitRequest,
12
+ ICPRosettaConstructionSubmitResponse,
13
+ ICPRosettaConstructionDeriveRequest,
14
+ ICPRosettaConstructionDeriveResponse,
15
+ } from "./types";
16
+ import { ingressExpiry, generateOperations, generateSignaturesPayload } from "./utils";
17
+ import { Cbor } from "@dfinity/agent";
18
+ import { Principal } from "@dfinity/principal";
19
+ import BigNumber from "bignumber.js";
20
+ import { ICP_SEND_TXN_TYPE } from "../../../consts";
21
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
22
+ import { ICPSigner } from "../../../types";
23
+
24
+ export const getUnsignedTransaction = async (
25
+ transaction: Transaction,
26
+ account: Account,
27
+ ): Promise<{
28
+ unsignedTxn: string;
29
+ payloads: ICPRosettaConstructionPayloadsResponse["payloads"];
30
+ }> => {
31
+ const ops = generateOperations(transaction, account);
32
+ const pubkeys = [
33
+ {
34
+ hex_bytes: account.xpub ?? "",
35
+ curve_type: "secp256k1",
36
+ },
37
+ ];
38
+
39
+ const reqOpts: ICPRosettaConstructionPayloadsRequest = {
40
+ ...getICPRosettaNetworkIdentifier(),
41
+ operations: ops,
42
+ public_keys: pubkeys,
43
+ metadata: {
44
+ memo: parseInt(transaction.memo ?? "0"),
45
+ },
46
+ };
47
+ const { payloads, unsigned_transaction } = await constructionInvoke<
48
+ ICPRosettaConstructionPayloadsRequest,
49
+ ICPRosettaConstructionPayloadsResponse
50
+ >(reqOpts, "payloads");
51
+
52
+ return { unsignedTxn: unsigned_transaction, payloads };
53
+ };
54
+
55
+ export const signICPTransaction = async ({
56
+ signerContext,
57
+ deviceId,
58
+ unsignedTxn,
59
+ path,
60
+ payloads,
61
+ pubkey,
62
+ }: {
63
+ signerContext: SignerContext<ICPSigner>;
64
+ deviceId: string;
65
+ unsignedTxn: string;
66
+ path: string;
67
+ payloads: ICPRosettaConstructionPayloadsResponse["payloads"];
68
+ pubkey: string;
69
+ }): Promise<{
70
+ signatures: { txnSig: string; readSig: string };
71
+ signedTxn: string;
72
+ }> => {
73
+ const decodedTxn: any = Cbor.decode(Buffer.from(unsignedTxn, "hex"));
74
+ const txnReqFromCbor = decodedTxn.updates[0][1];
75
+ const expiry = new ingressExpiry(BigNumber(decodedTxn.ingress_expiries[0].toString()));
76
+
77
+ const submitReq = {
78
+ request_type: "call",
79
+ canister_id: Principal.fromUint8Array(txnReqFromCbor.canister_id),
80
+ method_name: txnReqFromCbor.method_name,
81
+ arg: txnReqFromCbor.arg,
82
+ sender: Principal.fromUint8Array(txnReqFromCbor.sender),
83
+ ingress_expiry: expiry,
84
+ };
85
+
86
+ const txnBlobToSign = Cbor.encode({
87
+ content: submitReq,
88
+ });
89
+
90
+ const { r } = await signerContext(deviceId, async signer => {
91
+ const r = await signer.sign(path, Buffer.from(txnBlobToSign), ICP_SEND_TXN_TYPE);
92
+ return { r };
93
+ });
94
+
95
+ const result = {
96
+ signatures: {
97
+ readSig: "",
98
+ txnSig: Buffer.from(r.signatureRS ?? "").toString("hex"),
99
+ },
100
+ };
101
+
102
+ const signaturesPayload = generateSignaturesPayload(result.signatures, payloads, pubkey);
103
+
104
+ const { signed_transaction: signedTxn } = await constructionInvoke<
105
+ ICPRosettaConstructionCombineRequest,
106
+ ICPRosettaConstructionCombineResponse
107
+ >(
108
+ {
109
+ ...getICPRosettaNetworkIdentifier(),
110
+ signatures: signaturesPayload,
111
+ unsigned_transaction: unsignedTxn,
112
+ },
113
+ "combine",
114
+ );
115
+
116
+ return { ...result, signedTxn };
117
+ };
118
+
119
+ export const getTxnMetadata = async (signedTxn: string): Promise<{ hash: string }> => {
120
+ const {
121
+ transaction_identifier: { hash },
122
+ } = await constructionInvoke<
123
+ ICPRosettaConstructionHashRequest,
124
+ ICPRosettaConstructionHashResponse
125
+ >({ ...getICPRosettaNetworkIdentifier(), signed_transaction: signedTxn }, "hash");
126
+
127
+ return { hash };
128
+ };
129
+
130
+ export const getTxnExpirationDate = (_unsignedTxn: string): Date => {
131
+ return new Date();
132
+ };
133
+
134
+ export const broadcastTxn = async (signedTxn: string) => {
135
+ await constructionInvoke<
136
+ ICPRosettaConstructionSubmitRequest,
137
+ ICPRosettaConstructionSubmitResponse
138
+ >({ ...getICPRosettaNetworkIdentifier(), signed_transaction: signedTxn }, "submit");
139
+ };
140
+
141
+ export const deriveAddressFromPubkey = async (pubkey: string) => {
142
+ const res = await constructionInvoke<
143
+ ICPRosettaConstructionDeriveRequest,
144
+ ICPRosettaConstructionDeriveResponse
145
+ >(
146
+ {
147
+ ...getICPRosettaNetworkIdentifier(),
148
+ public_key: { curve_type: "secp256k1", hex_bytes: pubkey },
149
+ },
150
+ "derive",
151
+ );
152
+
153
+ return res.account_identifier.address;
154
+ };
@@ -0,0 +1,166 @@
1
+ import { SubmitResponse } from "@dfinity/agent";
2
+
3
+ export interface ICPRosettaBlockHeightResponse {
4
+ current_block_identifier: ICPRosettaBlockIdentifier;
5
+ current_block_timestamp: number;
6
+ genesis_block_identifier: ICPRosettaBlockIdentifier;
7
+ sync_status: ICPRosettaSyncstatus;
8
+ peers: any[];
9
+ }
10
+
11
+ interface ICPRosettaBlockIdentifier {
12
+ index: number;
13
+ hash: string;
14
+ }
15
+
16
+ export interface ICPRosettaGetBalancesResponse {
17
+ block_identifier: ICPRosettaBlockIdentifier;
18
+ balances: ICPRosettaBalance[];
19
+ details?: { error_message: string };
20
+ }
21
+
22
+ interface ICPRosettaBalance {
23
+ value: string;
24
+ currency: ICPRosettaCurrency;
25
+ }
26
+
27
+ interface ICPRosettaCurrency {
28
+ symbol: string;
29
+ decimals: number;
30
+ }
31
+
32
+ interface ICPRosettaSyncstatus {
33
+ current_index: number;
34
+ target_index: number;
35
+ }
36
+
37
+ export interface ICPRosettaGetTxnsHistoryResponse {
38
+ transactions: {
39
+ block_identifier: ICPRosettaBlockIdentifier;
40
+ transaction: {
41
+ transaction_identifier: ICPRosettaTransactionidentifier;
42
+ operations: ICPRosettaICPRosettaOperation[];
43
+ metadata: {
44
+ block_height: number;
45
+ memo: number;
46
+ timestamp: number;
47
+ };
48
+ };
49
+ }[];
50
+ total_count: number;
51
+ }
52
+
53
+ export interface ICPRosettaICPRosettaOperation {
54
+ operation_identifier: {
55
+ index: number;
56
+ };
57
+ type: string;
58
+ status?: string;
59
+ account: ICPRosettaAccountIdentifier;
60
+ amount: ICPRosettaBalance;
61
+ metadata?: {
62
+ block_index: number;
63
+ transaction_identifier: ICPRosettaTransactionidentifier;
64
+ };
65
+ }
66
+
67
+ export interface ICPRosettaConstructionPayloadsRequest {
68
+ network_identifier: ICPRosettaNetworkIdentifier;
69
+ operations: ICPRosettaICPRosettaOperation[];
70
+ metadata?: ICPRosettaMetadata;
71
+ public_keys: ICPRosettaPublickey[];
72
+ }
73
+
74
+ export interface ICPRosettaPublickey {
75
+ hex_bytes: string;
76
+ curve_type: string;
77
+ }
78
+
79
+ export interface ICPRosettaMetadata {
80
+ memo?: number;
81
+ created_at?: number;
82
+ ingress_end?: number;
83
+ ingress_start?: number;
84
+ }
85
+
86
+ interface ICPRosettaCurrency {
87
+ symbol: string;
88
+ decimals: number;
89
+ }
90
+
91
+ interface ICPRosettaNetworkIdentifier {
92
+ blockchain: string;
93
+ network: string;
94
+ }
95
+
96
+ export interface ICPRosettaConstructionPayloadsResponse {
97
+ unsigned_transaction: string;
98
+ payloads: {
99
+ account_identifier: ICPRosettaAccountIdentifier;
100
+ hex_bytes: string;
101
+ signature_type: string;
102
+ }[];
103
+ }
104
+
105
+ interface ICPRosettaAccountIdentifier {
106
+ address: string;
107
+ }
108
+
109
+ export interface ICPRosettaConstructionCombineRequest {
110
+ network_identifier: ICPRosettaNetworkIdentifier;
111
+ unsigned_transaction: string; // cbor
112
+ signatures: ICPRosettaSignature[];
113
+ }
114
+
115
+ export interface ICPRosettaSignature {
116
+ signing_payload: {
117
+ account_identifier: ICPRosettaAccountIdentifier;
118
+ hex_bytes: string;
119
+ signature_type: string;
120
+ };
121
+ public_key: ICPRosettaPublickey;
122
+ signature_type: string;
123
+ hex_bytes: string;
124
+ }
125
+
126
+ export interface ICPRosettaConstructionCombineResponse {
127
+ signed_transaction: string;
128
+ }
129
+
130
+ export interface ICPRosettaConstructionSubmitRequest {
131
+ network_identifier: ICPRosettaNetworkIdentifier;
132
+ signed_transaction: string;
133
+ }
134
+ export interface ICPRosettaConstructionSubmitResponse {
135
+ transaction_identifier: ICPRosettaTransactionidentifier;
136
+ metadata: {
137
+ operations: ICPRosettaICPRosettaOperation[];
138
+ };
139
+ }
140
+
141
+ interface ICPRosettaTransactionidentifier {
142
+ hash: string;
143
+ }
144
+
145
+ export interface ICPRosettaConstructionHashRequest {
146
+ network_identifier: ICPRosettaNetworkIdentifier;
147
+ signed_transaction: string;
148
+ }
149
+
150
+ export interface ICPRosettaConstructionHashResponse {
151
+ transaction_identifier: ICPRosettaTransactionidentifier;
152
+ }
153
+
154
+ export interface ICPRosettaBroadcastResult extends SubmitResponse {
155
+ txnHash?: string;
156
+ blockHeight?: string;
157
+ }
158
+
159
+ export interface ICPRosettaConstructionDeriveRequest {
160
+ network_identifier: ICPRosettaNetworkIdentifier;
161
+ public_key: ICPRosettaPublickey;
162
+ }
163
+
164
+ export interface ICPRosettaConstructionDeriveResponse {
165
+ account_identifier: ICPRosettaAccountIdentifier;
166
+ }
@@ -0,0 +1,151 @@
1
+ import * as cbor from "simple-cbor";
2
+ import {
3
+ ICPRosettaConstructionCombineRequest,
4
+ ICPRosettaConstructionPayloadsResponse,
5
+ ICPRosettaICPRosettaOperation,
6
+ } from "./types";
7
+ import { PipeArrayBuffer } from "@dfinity/candid";
8
+ import BigInteger from "big-integer";
9
+ import { Transaction } from "../../../types";
10
+ import { Account } from "@ledgerhq/types-live";
11
+ import { getAddress } from "../addresses";
12
+ import BigNumber from "bignumber.js";
13
+
14
+ export const generateOperations = (
15
+ tr: Transaction,
16
+ a: Account,
17
+ ): ICPRosettaICPRosettaOperation[] => {
18
+ const { address } = getAddress(a);
19
+ const currency = {
20
+ symbol: "ICP",
21
+ decimals: 8,
22
+ };
23
+ const type = "TRANSACTION";
24
+ const operations: ICPRosettaICPRosettaOperation[] = [];
25
+ operations.push({
26
+ operation_identifier: {
27
+ index: 0,
28
+ },
29
+ type,
30
+ account: {
31
+ address,
32
+ },
33
+ amount: {
34
+ value: `-${tr.amount}`,
35
+ currency,
36
+ },
37
+ });
38
+
39
+ operations.push({
40
+ operation_identifier: {
41
+ index: 1,
42
+ },
43
+ type,
44
+ account: {
45
+ address: tr.recipient,
46
+ },
47
+ amount: {
48
+ value: `${tr.amount}`,
49
+ currency,
50
+ },
51
+ });
52
+
53
+ operations.push({
54
+ operation_identifier: {
55
+ index: 2,
56
+ },
57
+ type: "FEE",
58
+ account: {
59
+ address,
60
+ },
61
+ amount: {
62
+ value: `-${tr.fees}`,
63
+ currency,
64
+ },
65
+ });
66
+
67
+ return operations;
68
+ };
69
+
70
+ function expiryEncode(val: BigNumber): ArrayBuffer {
71
+ let value = BigInteger(val.toString());
72
+
73
+ if (value < BigInteger(0)) {
74
+ throw new Error("Cannot leb encode negative values.");
75
+ }
76
+
77
+ const byteLength = (value === BigInteger(0) ? 0 : Math.ceil(Math.log2(Number(value)))) + 1;
78
+ const pipe = new PipeArrayBuffer(new ArrayBuffer(byteLength), 0);
79
+ // eslint-disable-next-line no-constant-condition
80
+ while (true) {
81
+ const i = Number(value.and(BigInteger(0x7f)));
82
+ value = value.divide(BigInteger(0x80));
83
+ if (value.eq(BigInteger(0))) {
84
+ pipe.write(new Uint8Array([i]));
85
+ break;
86
+ } else {
87
+ pipe.write(new Uint8Array([i | 0x80]));
88
+ }
89
+ }
90
+
91
+ return pipe.buffer;
92
+ }
93
+
94
+ export class ingressExpiry {
95
+ value: BigNumber;
96
+
97
+ constructor(value: BigNumber) {
98
+ // Use bigint because it can overflow the maximum number allowed in a double float.
99
+ this.value = value;
100
+ }
101
+
102
+ public toCBOR(): cbor.CborValue {
103
+ return cbor.value.u64(this.value.toString(16), 16);
104
+ }
105
+
106
+ public toHash(): ArrayBuffer {
107
+ return expiryEncode(this.value);
108
+ }
109
+ }
110
+
111
+ export const generateSignaturesPayload = (
112
+ signs: { txnSig: string; readSig: string },
113
+ payloads: ICPRosettaConstructionPayloadsResponse["payloads"],
114
+ pubkey: string,
115
+ ): ICPRosettaConstructionCombineRequest["signatures"] => {
116
+ const signatures: ICPRosettaConstructionCombineRequest["signatures"] = [];
117
+ const [txnPayload, readStatePayload] = payloads;
118
+ signatures.push({
119
+ signing_payload: {
120
+ account_identifier: {
121
+ address: txnPayload.account_identifier.address,
122
+ },
123
+ hex_bytes: txnPayload.hex_bytes,
124
+ signature_type: txnPayload.signature_type,
125
+ },
126
+ public_key: {
127
+ hex_bytes: pubkey,
128
+ curve_type: "secp256k1",
129
+ },
130
+ signature_type: "ecdsa",
131
+ hex_bytes: signs.txnSig,
132
+ });
133
+
134
+ signatures.push({
135
+ signing_payload: {
136
+ account_identifier: {
137
+ address: readStatePayload.account_identifier.address,
138
+ },
139
+ hex_bytes: readStatePayload.hex_bytes,
140
+ signature_type: readStatePayload.signature_type,
141
+ },
142
+ public_key: {
143
+ hex_bytes: pubkey,
144
+ curve_type: "secp256k1",
145
+ },
146
+ signature_type: "ecdsa",
147
+ hex_bytes: signs.readSig,
148
+ });
149
+
150
+ return signatures;
151
+ };
@@ -1,40 +1,15 @@
1
1
  import { AccountBridge } from "@ledgerhq/types-live";
2
- import { broadcastTxn } from "../api";
2
+ import { broadcastTxn } from "./bridgeHelpers/icpRosetta";
3
3
  import { Transaction } from "../types";
4
- import { log } from "@ledgerhq/logs";
5
- import invariant from "invariant";
6
- import { MAINNET_LEDGER_CANISTER_ID } from "../consts";
7
4
 
8
- // Interface to structure raw data for broadcasting transactions
9
- interface BroadcastRawData {
10
- encodedSignedCallBlob: string;
11
- }
12
-
13
- // Type guard to validate rawData shape
14
- function isBroadcastRawData(data: unknown): data is BroadcastRawData {
15
- return (
16
- typeof data === "object" &&
17
- data !== null &&
18
- "encodedSignedCallBlob" in data &&
19
- typeof (data as any).encodedSignedCallBlob === "string"
20
- );
21
- }
22
-
23
- // Main broadcast function for handling Internet Computer transactions
24
5
  export const broadcast: AccountBridge<Transaction>["broadcast"] = async ({
25
- signedOperation: { operation, rawData },
6
+ signedOperation: { signature, operation },
26
7
  }) => {
27
- log("debug", "[broadcast] Internet Computer transaction broadcast initiated");
8
+ // log("debug", "[broadcast] start fn");
28
9
 
29
- // Validate rawData with type guard
30
- invariant(isBroadcastRawData(rawData), "[ICP](broadcast) Invalid rawData format");
31
- invariant(operation.extra, "[ICP](broadcast) Missing operation extra");
10
+ await broadcastTxn(signature);
32
11
 
33
- await broadcastTxn(
34
- Buffer.from(rawData.encodedSignedCallBlob, "hex"),
35
- MAINNET_LEDGER_CANISTER_ID,
36
- "call",
37
- );
12
+ const result = { ...operation };
38
13
 
39
- return operation;
14
+ return result;
40
15
  };
@@ -7,8 +7,7 @@ import {
7
7
  } from "@ledgerhq/errors";
8
8
  import BigNumber from "bignumber.js";
9
9
  import { AccountBridge } from "@ledgerhq/types-live";
10
- import { getAddress } from "./bridgeHelpers/addresses";
11
- import { validateAddress, validateMemo } from "@zondax/ledger-live-icp/utils";
10
+ import { getAddress, validateAddress, validateMemo } from "./bridgeHelpers/addresses";
12
11
  import { Transaction, TransactionStatus } from "../types";
13
12
  import { InvalidMemoICP } from "../errors";
14
13
 
@@ -1,7 +1,6 @@
1
1
  import { AccountBridge } from "@ledgerhq/types-live";
2
2
  import { Transaction } from "../types";
3
- import { getAddress } from "./bridgeHelpers/addresses";
4
- import { validateAddress } from "@zondax/ledger-live-icp";
3
+ import { getAddress, validateAddress } from "./bridgeHelpers/addresses";
5
4
 
6
5
  export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"] = async (
7
6
  account,
@@ -1,103 +1,53 @@
1
1
  import { Observable } from "rxjs";
2
- import { Account, AccountBridge, DeviceId } from "@ledgerhq/types-live";
2
+ import { Account, AccountBridge } from "@ledgerhq/types-live";
3
3
  import { getAddress } from "./bridgeHelpers/addresses";
4
4
  import {
5
- UnsignedTransaction,
6
- createUnsignedSendTransaction,
7
- hashTransaction,
8
- pubkeyToDer,
9
- } from "@zondax/ledger-live-icp/utils";
10
- import { Cbor } from "@zondax/ledger-live-icp/agent";
5
+ getTxnExpirationDate,
6
+ getTxnMetadata,
7
+ getUnsignedTransaction,
8
+ signICPTransaction,
9
+ } from "./bridgeHelpers/icpRosetta";
11
10
  import { buildOptimisticOperation } from "./buildOptimisticOperation";
12
11
  import { Transaction } from "../types";
13
12
  import { SignerContext } from "@ledgerhq/coin-framework/signer";
14
13
  import { ICPSigner } from "../types";
15
14
  import { getPath } from "../common-logic";
16
- import { log } from "@ledgerhq/logs";
17
- import invariant from "invariant";
18
-
19
- const signICPTransaction = async (
20
- unsignedTxn: UnsignedTransaction,
21
- derivationPath: string,
22
- signerContext: SignerContext<ICPSigner>,
23
- account: Account,
24
- deviceId: DeviceId,
25
- ) => {
26
- const blob = Cbor.encode({ content: unsignedTxn });
27
- log("debug", "[signICPTransaction] blob", Buffer.from(blob).toString("hex"));
28
- const signatures = await signerContext(deviceId, signer =>
29
- signer.sign(derivationPath, Buffer.from(blob)),
30
- );
31
-
32
- invariant(signatures.signatureRS, "[ICP](signICPTransaction) Signature not found");
33
- invariant(account.xpub, "[ICP](signICPTransaction) Account xpub is required");
34
- return {
35
- signature: Buffer.from(signatures.signatureRS).toString("hex"),
36
- callBody: {
37
- content: unsignedTxn,
38
- sender_pubkey: pubkeyToDer(account.xpub),
39
- sender_sig: signatures.signatureRS,
40
- },
41
- };
42
- };
43
15
 
44
16
  export const buildSignOperation =
45
- (signerContext: SignerContext<ICPSigner>): AccountBridge<Transaction>["signOperation"] =>
17
+ (signerContext: SignerContext<ICPSigner>): AccountBridge<Transaction, Account>["signOperation"] =>
46
18
  ({ account, transaction, deviceId }) =>
47
19
  new Observable(o => {
48
20
  async function main() {
49
- log("debug", "[signOperation] icp start fn");
50
- log("debug", "[signOperation] transaction", transaction);
51
-
52
21
  const { xpub } = account;
53
- invariant(xpub, "[ICP](signOperation) Account xpub is required");
54
-
55
22
  const { derivationPath } = getAddress(account);
56
-
57
- const { unsignedTransaction, transferRawRequest } = createUnsignedSendTransaction(
58
- transaction,
59
- xpub,
60
- );
23
+ const { unsignedTxn, payloads } = await getUnsignedTransaction(transaction, account);
61
24
 
62
25
  o.next({
63
26
  type: "device-signature-requested",
64
27
  });
65
28
 
66
- let signature: string = "";
67
- let encodedSignedCallBlob: string = "";
68
- const res = await signICPTransaction(
69
- unsignedTransaction,
70
- getPath(derivationPath),
29
+ const { signedTxn } = await signICPTransaction({
71
30
  signerContext,
72
- account,
73
31
  deviceId,
74
- );
75
- signature = res.signature;
76
- encodedSignedCallBlob = Buffer.from(Cbor.encode(res.callBody)).toString("hex");
77
- invariant(signature, "[ICP](signOperation) Signature not found");
32
+ unsignedTxn,
33
+ path: getPath(derivationPath),
34
+ payloads,
35
+ pubkey: xpub ?? "",
36
+ });
78
37
 
79
38
  o.next({
80
39
  type: "device-signature-granted",
81
40
  });
82
41
 
83
- const hash = hashTransaction({
84
- from: account.freshAddress,
85
- to: transaction.recipient,
86
- amount: transferRawRequest.amount.e8s,
87
- fee: transferRawRequest.fee.e8s,
88
- memo: transferRawRequest.memo,
89
- created_at_time: transferRawRequest.created_at_time[0]["timestamp_nanos"],
90
- });
91
-
42
+ const { hash } = await getTxnMetadata(signedTxn);
92
43
  const operation = await buildOptimisticOperation(account, transaction, hash);
44
+
93
45
  o.next({
94
46
  type: "signed",
95
47
  signedOperation: {
96
48
  operation,
97
- signature,
98
- rawData: {
99
- encodedSignedCallBlob,
100
- },
49
+ signature: signedTxn,
50
+ expirationDate: getTxnExpirationDate(unsignedTxn),
101
51
  },
102
52
  });
103
53
  }
package/src/consts.ts CHANGED
@@ -9,13 +9,3 @@ export const ICP_FEES = 1e4;
9
9
 
10
10
  // Max Memo value on ICP network
11
11
  export const MAX_MEMO_VALUE = Number.MAX_SAFE_INTEGER;
12
-
13
- // API limits
14
- export const FETCH_TXNS_LIMIT = 100;
15
-
16
- export {
17
- MAINNET_GOVERNANCE_CANISTER_ID,
18
- MAINNET_LEDGER_CANISTER_ID,
19
- MAINNET_INDEX_CANISTER_ID,
20
- ICP_NETWORK_URL,
21
- } from "@zondax/ledger-live-icp/neurons";
@@ -1,5 +1,6 @@
1
1
  import { log } from "@ledgerhq/logs";
2
2
  import { getBufferFromString } from "./common-logic/utils";
3
+ import { ICP_SEND_TXN_TYPE } from "./consts";
3
4
  import { SignerContext } from "@ledgerhq/coin-framework/signer";
4
5
  import { ICPSigner } from "./types";
5
6
  import { Account, AnyMessage } from "@ledgerhq/types-live";
@@ -18,7 +19,11 @@ export const signMessage =
18
19
  if (typeof message !== "string") throw new Error("Message must be a string");
19
20
 
20
21
  const { r } = await signerContext(deviceId, async signer => {
21
- const r = await signer.sign(account.freshAddressPath, getBufferFromString(message));
22
+ const r = await signer.sign(
23
+ account.freshAddressPath,
24
+ getBufferFromString(message),
25
+ ICP_SEND_TXN_TYPE,
26
+ );
22
27
  return { r };
23
28
  });
24
29