@ledgerhq/hw-app-multiversx 6.22.0-next.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.
@@ -0,0 +1,4 @@
1
+
2
+ > @ledgerhq/hw-app-multiversx@6.21.1 build /home/runner/work/ledger-live/ledger-live/libs/ledgerjs/packages/hw-app-multiversx
3
+ > tsc && tsc -m esnext --moduleResolution bundler --outDir lib-es
4
+
@@ -0,0 +1,5 @@
1
+ {
2
+ "entry": ["src/MultiversX.ts"],
3
+ "ignoreUnimported": [],
4
+ "ignoreUnused": ["axios"]
5
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # @ledgerhq/hw-app-elrond
2
+
3
+ ## 6.22.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#8757](https://github.com/LedgerHQ/ledger-live/pull/8757) [`1461449`](https://github.com/LedgerHQ/ledger-live/commit/146144941c13e60182da8d79592f706d12a6f00e) Thanks [@Wozacosta](https://github.com/Wozacosta)! - chore: Rebranding from 'Elrond' to 'MultiversX'
8
+
9
+ ## 6.21.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#7750](https://github.com/LedgerHQ/ledger-live/pull/7750) [`8679584`](https://github.com/LedgerHQ/ledger-live/commit/86795841982e06058294528bd8d2847fc4f62513) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Multiversx/Elrond to its own module
14
+
15
+ - Updated dependencies []:
16
+ - @ledgerhq/hw-transport@6.31.4
17
+
18
+ ## 6.21.1-next.0
19
+
20
+ ### Patch Changes
21
+
22
+ - [#7750](https://github.com/LedgerHQ/ledger-live/pull/7750) [`8679584`](https://github.com/LedgerHQ/ledger-live/commit/86795841982e06058294528bd8d2847fc4f62513) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Multiversx/Elrond to its own module
23
+
24
+ - Updated dependencies []:
25
+ - @ledgerhq/hw-transport@6.31.4-next.0
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2017-present Ledger https://www.ledger.com/
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ <img src="https://user-images.githubusercontent.com/4631227/191834116-59cf590e-25cc-4956-ae5c-812ea464f324.png" height="100" />
2
+
3
+ [GitHub](https://github.com/LedgerHQ/ledger-live/),
4
+ [Ledger Devs Discord](https://developers.ledger.com/discord-pro),
5
+ [Developer Portal](https://developers.ledger.com/)
6
+
7
+ ## @ledgerhq/hw-app-multiversx
8
+
9
+ Ledger Hardware Wallet Multiversx JavaScript bindings.
10
+
11
+ ***
12
+
13
+ ## Are you adding Ledger support to your software wallet?
14
+
15
+ You may be using this package to communicate with the Multiversx Nano App.
16
+
17
+ For a smooth and quick integration:
18
+
19
+ * See the developers’ documentation on the [Developer Portal](https://developers.ledger.com/docs/transport/overview/) and
20
+ * Go on [Discord](https://developers.ledger.com/discord-pro/) to chat with developer support and the developer community.
21
+
22
+ ***
23
+
24
+ ## API
25
+
26
+ <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
27
+
28
+ #### Table of Contents
29
+
30
+ * [MultiversX](#multiversx)
31
+ * [Parameters](#parameters)
32
+ * [Examples](#examples)
33
+ * [getAppConfiguration](#getappconfiguration)
34
+ * [Examples](#examples-1)
35
+ * [getAddress](#getaddress)
36
+ * [Parameters](#parameters-1)
37
+ * [Examples](#examples-2)
38
+ * [setAddress](#setaddress)
39
+ * [Parameters](#parameters-2)
40
+ * [Examples](#examples-3)
41
+
42
+ ### MultiversX
43
+
44
+ MultiversX API
45
+
46
+ #### Parameters
47
+
48
+ * `transport` **Transport**&#x20;
49
+ * `scrambleKey` (optional, default `"eGLD"`)
50
+
51
+ #### Examples
52
+
53
+ ```javascript
54
+ import MultiversX from "@ledgerhq/hw-app-multiversx";
55
+ const multiversx = new MultiversX(transport)
56
+ ```
57
+
58
+ #### getAppConfiguration
59
+
60
+ Get MultiversX app configuration.
61
+
62
+ ##### Examples
63
+
64
+ ```javascript
65
+ const result = await multiversx.getAppConfiguration();
66
+ const { contractData, accountIndex, addressIndex, version } = result;
67
+ ```
68
+
69
+ Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<any>** an object with a contractData, accountIndex, addressIndex, version
70
+
71
+ #### getAddress
72
+
73
+ Get MultiversX address for a given BIP 32 path.
74
+
75
+ ##### Parameters
76
+
77
+ * `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** a path in BIP 32 format
78
+ * `boolDisplay` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** optionally enable or not the display
79
+
80
+ ##### Examples
81
+
82
+ ```javascript
83
+ const result = await multiversx.getAddress("44'/508'/0'/0'/0'");
84
+ const { publicKey, address } = result;
85
+ ```
86
+
87
+ Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{publicKey: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), address: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>** an object with a address
88
+
89
+ #### setAddress
90
+
91
+ Set MultiversX address for a given BIP 32 path.
92
+
93
+ ##### Parameters
94
+
95
+ * `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** a path in BIP 32 format
96
+ * `display` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** optionally enable or not the display
97
+
98
+ ##### Examples
99
+
100
+ ```javascript
101
+ const result = await multiversx.setAddress("44'/508'/0'/0/0");
102
+ result : Buffer;
103
+ ```
104
+
105
+ Returns **any** an object with a address
package/jest.config.ts ADDED
@@ -0,0 +1,6 @@
1
+ import baseConfig from "../../jest.config";
2
+
3
+ export default {
4
+ ...baseConfig,
5
+ rootDir: __dirname,
6
+ };
@@ -0,0 +1,56 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import type Transport from "@ledgerhq/hw-transport";
4
+ /**
5
+ * MultiversX API
6
+ *
7
+ * @example
8
+ * import MultiversX from "@ledgerhq/hw-app-multiversx";
9
+ * const multiversx = new MultiversX(transport)
10
+ */
11
+ export default class MultiversX {
12
+ transport: Transport;
13
+ constructor(transport: Transport, scrambleKey?: string);
14
+ /**
15
+ * Get MultiversX app configuration.
16
+ *
17
+ * @return an object with a contractData, accountIndex, addressIndex, version
18
+ * @example
19
+ * const result = await multiversx.getAppConfiguration();
20
+ * const { contractData, accountIndex, addressIndex, version } = result;
21
+ */
22
+ getAppConfiguration(): Promise<any>;
23
+ serializePath(path: Array<number>): Buffer;
24
+ /**
25
+ * Get MultiversX address for a given BIP 32 path.
26
+ *
27
+ * @param path a path in BIP 32 format
28
+ * @param boolDisplay optionally enable or not the display
29
+ * @return an object with a address
30
+ * @example
31
+ * const result = await multiversx.getAddress("44'/508'/0'/0'/0'");
32
+ * const { publicKey, address } = result;
33
+ */
34
+ getAddress(path: string, boolDisplay?: boolean): Promise<{
35
+ publicKey: string;
36
+ address: string;
37
+ }>;
38
+ /**
39
+ * Set MultiversX address for a given BIP 32 path.
40
+ *
41
+ * @param path a path in BIP 32 format
42
+ * @param display optionally enable or not the display
43
+ * @return an object with a address
44
+ * @example
45
+ * const result = await multiversx.setAddress("44'/508'/0'/0/0");
46
+ * result : Buffer;
47
+ */
48
+ setAddress(path: string, display?: boolean): Promise<void>;
49
+ signTransaction(path: string, message: string): Promise<string>;
50
+ sign(path: string, message: string): Promise<{
51
+ signature: null | Buffer;
52
+ }>;
53
+ serializeESDTInfo(ticker: string, id: string, decimals: number, chainId: string, signature: string): Buffer;
54
+ provideESDTInfo(ticker?: string, id?: string, decimals?: number, chainId?: string, signature?: string): Promise<any>;
55
+ }
56
+ //# sourceMappingURL=MultiversX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultiversX.d.ts","sourceRoot":"","sources":["../src/MultiversX.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AAiBpD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,SAAS,EAAE,SAAS,CAAC;gBAET,SAAS,EAAE,SAAS,EAAE,WAAW,SAAS;IAgBtD;;;;;;;OAOG;IACG,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC;IAUzC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;IAOjC;;;;;;;;;OASG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAqBF;;;;;;;;;OASG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;IAS1C,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU/D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,IAAI,GAAG,MAAM,CAAA;KAAE,CAAC;IAuChF,iBAAiB,CACf,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,MAAM;IAsBH,eAAe,CACnB,MAAM,CAAC,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,GAAG,CAAC;CAShB"}
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const sdk_core_1 = require("@multiversx/sdk-core");
7
+ const bip32_path_1 = __importDefault(require("bip32-path"));
8
+ const CHUNK_SIZE = 150;
9
+ const CURVE_MASK = 0x80;
10
+ const CLA = 0xed;
11
+ const INS = {
12
+ GET_VERSION: 0x02,
13
+ GET_ADDRESS: 0x03,
14
+ SET_ADDRESS: 0x05,
15
+ PROVIDE_ESDT_INFO: 0x08,
16
+ };
17
+ const SIGN_HASH_TX_INS = 0x07;
18
+ const SW_OK = 0x9000;
19
+ const SW_CANCEL = 0x6986;
20
+ /**
21
+ * MultiversX API
22
+ *
23
+ * @example
24
+ * import MultiversX from "@ledgerhq/hw-app-multiversx";
25
+ * const multiversx = new MultiversX(transport)
26
+ */
27
+ class MultiversX {
28
+ transport;
29
+ constructor(transport, scrambleKey = "eGLD") {
30
+ this.transport = transport;
31
+ transport.decorateAppAPIMethods(this, [
32
+ "getAddress",
33
+ "setAddress",
34
+ "signTransaction",
35
+ "signMessage",
36
+ "getAppConfiguration",
37
+ "provideESDTInfo",
38
+ ], scrambleKey);
39
+ }
40
+ /**
41
+ * Get MultiversX app configuration.
42
+ *
43
+ * @return an object with a contractData, accountIndex, addressIndex, version
44
+ * @example
45
+ * const result = await multiversx.getAppConfiguration();
46
+ * const { contractData, accountIndex, addressIndex, version } = result;
47
+ */
48
+ async getAppConfiguration() {
49
+ const response = await this.transport.send(CLA, INS.GET_VERSION, 0x00, 0x00);
50
+ return {
51
+ contractData: response[0],
52
+ accountIndex: response[1],
53
+ addressIndex: response[2],
54
+ version: `${response[3]}.${response[4]}.${response[5]}`,
55
+ };
56
+ }
57
+ serializePath(path) {
58
+ const buf = Buffer.alloc(8);
59
+ buf.writeUInt32BE(path[3], 0);
60
+ buf.writeUInt32BE(path[2], 4);
61
+ return buf;
62
+ }
63
+ /**
64
+ * Get MultiversX address for a given BIP 32 path.
65
+ *
66
+ * @param path a path in BIP 32 format
67
+ * @param boolDisplay optionally enable or not the display
68
+ * @return an object with a address
69
+ * @example
70
+ * const result = await multiversx.getAddress("44'/508'/0'/0'/0'");
71
+ * const { publicKey, address } = result;
72
+ */
73
+ async getAddress(path, boolDisplay) {
74
+ const bipPath = bip32_path_1.default.fromString(path).toPathArray();
75
+ const data = this.serializePath(bipPath);
76
+ const response = await this.transport.send(CLA, INS.GET_ADDRESS, boolDisplay ? 0x01 : 0x00, 0x00, data, [SW_OK, SW_CANCEL]);
77
+ const addressLength = response[0];
78
+ const address = sdk_core_1.Address.newFromBech32(response.slice(1, 1 + addressLength).toString("ascii"));
79
+ return {
80
+ publicKey: address.toHex(),
81
+ address: address.toBech32(),
82
+ };
83
+ }
84
+ /**
85
+ * Set MultiversX address for a given BIP 32 path.
86
+ *
87
+ * @param path a path in BIP 32 format
88
+ * @param display optionally enable or not the display
89
+ * @return an object with a address
90
+ * @example
91
+ * const result = await multiversx.setAddress("44'/508'/0'/0/0");
92
+ * result : Buffer;
93
+ */
94
+ async setAddress(path, display) {
95
+ const bipPath = bip32_path_1.default.fromString(path).toPathArray();
96
+ const data = this.serializePath(bipPath);
97
+ await this.transport.send(CLA, INS.SET_ADDRESS, display ? 0x01 : 0x00, 0x00, data, [
98
+ SW_OK,
99
+ SW_CANCEL,
100
+ ]);
101
+ }
102
+ async signTransaction(path, message) {
103
+ const { signature } = await this.sign(path, message);
104
+ if (signature === null) {
105
+ throw new Error("null signature received");
106
+ }
107
+ return signature.toString("hex");
108
+ }
109
+ async sign(path, message) {
110
+ const chunks = [];
111
+ const buffer = Buffer.from(message);
112
+ for (let i = 0; i < buffer.length; i += CHUNK_SIZE) {
113
+ let end = i + CHUNK_SIZE;
114
+ if (i > buffer.length) {
115
+ end = buffer.length;
116
+ }
117
+ chunks.push(buffer.slice(i, end));
118
+ }
119
+ const apdus = [];
120
+ chunks.forEach((data, index) => {
121
+ const apdu = {
122
+ cla: CLA,
123
+ ins: SIGN_HASH_TX_INS,
124
+ p1: index === 0 ? 0x00 : CURVE_MASK,
125
+ p2: CURVE_MASK,
126
+ data,
127
+ };
128
+ apdus.push(apdu);
129
+ });
130
+ let response = {};
131
+ for (const apdu of apdus) {
132
+ response = await this.transport.send(apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.data);
133
+ }
134
+ if (response.length !== 67 || response[0] !== 64) {
135
+ throw new Error("invalid signature received from ledger device");
136
+ }
137
+ const signature = response.slice(1, response.length - 2).toString("hex");
138
+ return { signature };
139
+ }
140
+ serializeESDTInfo(ticker, id, decimals, chainId, signature) {
141
+ const tickerLengthBuffer = Buffer.from([ticker.length]);
142
+ const tickerBuffer = Buffer.from(ticker);
143
+ const idLengthBuffer = Buffer.from([id.length]);
144
+ const idBuffer = Buffer.from(id);
145
+ const decimalsBuffer = Buffer.from([decimals]);
146
+ const chainIdLengthBuffer = Buffer.from([chainId.length]);
147
+ const chainIdBuffer = Buffer.from(chainId);
148
+ const signatureBuffer = Buffer.from(signature, "hex");
149
+ const infoBuffer = [
150
+ tickerLengthBuffer,
151
+ tickerBuffer,
152
+ idLengthBuffer,
153
+ idBuffer,
154
+ decimalsBuffer,
155
+ chainIdLengthBuffer,
156
+ chainIdBuffer,
157
+ signatureBuffer,
158
+ ];
159
+ return Buffer.concat(infoBuffer);
160
+ }
161
+ async provideESDTInfo(ticker, id, decimals, chainId, signature) {
162
+ if (!ticker || !id || !decimals || !chainId || !signature) {
163
+ throw new Error("Invalid ESDT token credentials!");
164
+ }
165
+ const data = this.serializeESDTInfo(ticker, id, decimals, chainId, signature);
166
+ return await this.transport.send(CLA, INS.PROVIDE_ESDT_INFO, 0x00, 0x00, data);
167
+ }
168
+ }
169
+ exports.default = MultiversX;
170
+ //# sourceMappingURL=MultiversX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultiversX.js","sourceRoot":"","sources":["../src/MultiversX.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import type Transport from "@ledgerhq/hw-transport";
4
+ /**
5
+ * MultiversX API
6
+ *
7
+ * @example
8
+ * import MultiversX from "@ledgerhq/hw-app-multiversx";
9
+ * const multiversx = new MultiversX(transport)
10
+ */
11
+ export default class MultiversX {
12
+ transport: Transport;
13
+ constructor(transport: Transport, scrambleKey?: string);
14
+ /**
15
+ * Get MultiversX app configuration.
16
+ *
17
+ * @return an object with a contractData, accountIndex, addressIndex, version
18
+ * @example
19
+ * const result = await multiversx.getAppConfiguration();
20
+ * const { contractData, accountIndex, addressIndex, version } = result;
21
+ */
22
+ getAppConfiguration(): Promise<any>;
23
+ serializePath(path: Array<number>): Buffer;
24
+ /**
25
+ * Get MultiversX address for a given BIP 32 path.
26
+ *
27
+ * @param path a path in BIP 32 format
28
+ * @param boolDisplay optionally enable or not the display
29
+ * @return an object with a address
30
+ * @example
31
+ * const result = await multiversx.getAddress("44'/508'/0'/0'/0'");
32
+ * const { publicKey, address } = result;
33
+ */
34
+ getAddress(path: string, boolDisplay?: boolean): Promise<{
35
+ publicKey: string;
36
+ address: string;
37
+ }>;
38
+ /**
39
+ * Set MultiversX address for a given BIP 32 path.
40
+ *
41
+ * @param path a path in BIP 32 format
42
+ * @param display optionally enable or not the display
43
+ * @return an object with a address
44
+ * @example
45
+ * const result = await multiversx.setAddress("44'/508'/0'/0/0");
46
+ * result : Buffer;
47
+ */
48
+ setAddress(path: string, display?: boolean): Promise<void>;
49
+ signTransaction(path: string, message: string): Promise<string>;
50
+ sign(path: string, message: string): Promise<{
51
+ signature: null | Buffer;
52
+ }>;
53
+ serializeESDTInfo(ticker: string, id: string, decimals: number, chainId: string, signature: string): Buffer;
54
+ provideESDTInfo(ticker?: string, id?: string, decimals?: number, chainId?: string, signature?: string): Promise<any>;
55
+ }
56
+ //# sourceMappingURL=MultiversX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultiversX.d.ts","sourceRoot":"","sources":["../src/MultiversX.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AAiBpD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,SAAS,EAAE,SAAS,CAAC;gBAET,SAAS,EAAE,SAAS,EAAE,WAAW,SAAS;IAgBtD;;;;;;;OAOG;IACG,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC;IAUzC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;IAOjC;;;;;;;;;OASG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAqBF;;;;;;;;;OASG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;IAS1C,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU/D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,IAAI,GAAG,MAAM,CAAA;KAAE,CAAC;IAuChF,iBAAiB,CACf,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,MAAM;IAsBH,eAAe,CACnB,MAAM,CAAC,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,GAAG,CAAC;CAShB"}
@@ -0,0 +1,164 @@
1
+ import { Address } from "@multiversx/sdk-core";
2
+ import BIPPath from "bip32-path";
3
+ const CHUNK_SIZE = 150;
4
+ const CURVE_MASK = 0x80;
5
+ const CLA = 0xed;
6
+ const INS = {
7
+ GET_VERSION: 0x02,
8
+ GET_ADDRESS: 0x03,
9
+ SET_ADDRESS: 0x05,
10
+ PROVIDE_ESDT_INFO: 0x08,
11
+ };
12
+ const SIGN_HASH_TX_INS = 0x07;
13
+ const SW_OK = 0x9000;
14
+ const SW_CANCEL = 0x6986;
15
+ /**
16
+ * MultiversX API
17
+ *
18
+ * @example
19
+ * import MultiversX from "@ledgerhq/hw-app-multiversx";
20
+ * const multiversx = new MultiversX(transport)
21
+ */
22
+ export default class MultiversX {
23
+ transport;
24
+ constructor(transport, scrambleKey = "eGLD") {
25
+ this.transport = transport;
26
+ transport.decorateAppAPIMethods(this, [
27
+ "getAddress",
28
+ "setAddress",
29
+ "signTransaction",
30
+ "signMessage",
31
+ "getAppConfiguration",
32
+ "provideESDTInfo",
33
+ ], scrambleKey);
34
+ }
35
+ /**
36
+ * Get MultiversX app configuration.
37
+ *
38
+ * @return an object with a contractData, accountIndex, addressIndex, version
39
+ * @example
40
+ * const result = await multiversx.getAppConfiguration();
41
+ * const { contractData, accountIndex, addressIndex, version } = result;
42
+ */
43
+ async getAppConfiguration() {
44
+ const response = await this.transport.send(CLA, INS.GET_VERSION, 0x00, 0x00);
45
+ return {
46
+ contractData: response[0],
47
+ accountIndex: response[1],
48
+ addressIndex: response[2],
49
+ version: `${response[3]}.${response[4]}.${response[5]}`,
50
+ };
51
+ }
52
+ serializePath(path) {
53
+ const buf = Buffer.alloc(8);
54
+ buf.writeUInt32BE(path[3], 0);
55
+ buf.writeUInt32BE(path[2], 4);
56
+ return buf;
57
+ }
58
+ /**
59
+ * Get MultiversX address for a given BIP 32 path.
60
+ *
61
+ * @param path a path in BIP 32 format
62
+ * @param boolDisplay optionally enable or not the display
63
+ * @return an object with a address
64
+ * @example
65
+ * const result = await multiversx.getAddress("44'/508'/0'/0'/0'");
66
+ * const { publicKey, address } = result;
67
+ */
68
+ async getAddress(path, boolDisplay) {
69
+ const bipPath = BIPPath.fromString(path).toPathArray();
70
+ const data = this.serializePath(bipPath);
71
+ const response = await this.transport.send(CLA, INS.GET_ADDRESS, boolDisplay ? 0x01 : 0x00, 0x00, data, [SW_OK, SW_CANCEL]);
72
+ const addressLength = response[0];
73
+ const address = Address.newFromBech32(response.slice(1, 1 + addressLength).toString("ascii"));
74
+ return {
75
+ publicKey: address.toHex(),
76
+ address: address.toBech32(),
77
+ };
78
+ }
79
+ /**
80
+ * Set MultiversX address for a given BIP 32 path.
81
+ *
82
+ * @param path a path in BIP 32 format
83
+ * @param display optionally enable or not the display
84
+ * @return an object with a address
85
+ * @example
86
+ * const result = await multiversx.setAddress("44'/508'/0'/0/0");
87
+ * result : Buffer;
88
+ */
89
+ async setAddress(path, display) {
90
+ const bipPath = BIPPath.fromString(path).toPathArray();
91
+ const data = this.serializePath(bipPath);
92
+ await this.transport.send(CLA, INS.SET_ADDRESS, display ? 0x01 : 0x00, 0x00, data, [
93
+ SW_OK,
94
+ SW_CANCEL,
95
+ ]);
96
+ }
97
+ async signTransaction(path, message) {
98
+ const { signature } = await this.sign(path, message);
99
+ if (signature === null) {
100
+ throw new Error("null signature received");
101
+ }
102
+ return signature.toString("hex");
103
+ }
104
+ async sign(path, message) {
105
+ const chunks = [];
106
+ const buffer = Buffer.from(message);
107
+ for (let i = 0; i < buffer.length; i += CHUNK_SIZE) {
108
+ let end = i + CHUNK_SIZE;
109
+ if (i > buffer.length) {
110
+ end = buffer.length;
111
+ }
112
+ chunks.push(buffer.slice(i, end));
113
+ }
114
+ const apdus = [];
115
+ chunks.forEach((data, index) => {
116
+ const apdu = {
117
+ cla: CLA,
118
+ ins: SIGN_HASH_TX_INS,
119
+ p1: index === 0 ? 0x00 : CURVE_MASK,
120
+ p2: CURVE_MASK,
121
+ data,
122
+ };
123
+ apdus.push(apdu);
124
+ });
125
+ let response = {};
126
+ for (const apdu of apdus) {
127
+ response = await this.transport.send(apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.data);
128
+ }
129
+ if (response.length !== 67 || response[0] !== 64) {
130
+ throw new Error("invalid signature received from ledger device");
131
+ }
132
+ const signature = response.slice(1, response.length - 2).toString("hex");
133
+ return { signature };
134
+ }
135
+ serializeESDTInfo(ticker, id, decimals, chainId, signature) {
136
+ const tickerLengthBuffer = Buffer.from([ticker.length]);
137
+ const tickerBuffer = Buffer.from(ticker);
138
+ const idLengthBuffer = Buffer.from([id.length]);
139
+ const idBuffer = Buffer.from(id);
140
+ const decimalsBuffer = Buffer.from([decimals]);
141
+ const chainIdLengthBuffer = Buffer.from([chainId.length]);
142
+ const chainIdBuffer = Buffer.from(chainId);
143
+ const signatureBuffer = Buffer.from(signature, "hex");
144
+ const infoBuffer = [
145
+ tickerLengthBuffer,
146
+ tickerBuffer,
147
+ idLengthBuffer,
148
+ idBuffer,
149
+ decimalsBuffer,
150
+ chainIdLengthBuffer,
151
+ chainIdBuffer,
152
+ signatureBuffer,
153
+ ];
154
+ return Buffer.concat(infoBuffer);
155
+ }
156
+ async provideESDTInfo(ticker, id, decimals, chainId, signature) {
157
+ if (!ticker || !id || !decimals || !chainId || !signature) {
158
+ throw new Error("Invalid ESDT token credentials!");
159
+ }
160
+ const data = this.serializeESDTInfo(ticker, id, decimals, chainId, signature);
161
+ return await this.transport.send(CLA, INS.PROVIDE_ESDT_INFO, 0x00, 0x00, data);
162
+ }
163
+ }
164
+ //# sourceMappingURL=MultiversX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultiversX.js","sourceRoot":"","sources":["../src/MultiversX.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@ledgerhq/hw-app-multiversx",
3
+ "version": "6.22.0-next.0",
4
+ "description": "Ledger Hardware Wallet MultiversX Application API",
5
+ "keywords": [
6
+ "Ledger",
7
+ "LedgerWallet",
8
+ "egld",
9
+ "MultiversX",
10
+ "NanoS",
11
+ "Blue",
12
+ "Hardware Wallet"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/LedgerHQ/ledger-live.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/LedgerHQ/ledger-live/issues"
20
+ },
21
+ "homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/ledgerjs/packages/hw-app-multiversx",
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "main": "lib/MultiversX.js",
26
+ "module": "lib-es/MultiversX.js",
27
+ "types": "lib/MultiversX.d.ts",
28
+ "license": "Apache-2.0",
29
+ "dependencies": {
30
+ "@multiversx/sdk-core": "^13.7.0",
31
+ "bignumber.js": "^9.0.1",
32
+ "bip32-path": "^0.4.2",
33
+ "protobufjs": "^7.2.6",
34
+ "axios": "^1.7.4",
35
+ "@ledgerhq/hw-transport": "^6.31.4"
36
+ },
37
+ "devDependencies": {
38
+ "@types/jest": "^29.5.10",
39
+ "@types/node": "^22.10.10",
40
+ "documentation": "14.0.2",
41
+ "jest": "^29.7.0",
42
+ "rimraf": "^4.4.1",
43
+ "source-map-support": "^0.5.21",
44
+ "ts-jest": "^29.1.1",
45
+ "ts-node": "^10.4.0",
46
+ "@ledgerhq/hw-transport-mocker": "^6.29.4"
47
+ },
48
+ "scripts": {
49
+ "clean": "rimraf lib lib-es",
50
+ "build": "tsc && tsc -m esnext --moduleResolution bundler --outDir lib-es",
51
+ "prewatch": "pnpm build",
52
+ "watch": "tsc --watch",
53
+ "watch:es": "tsc --watch -m esnext --moduleResolution bundler --outDir lib-es",
54
+ "doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts",
55
+ "lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx --cache",
56
+ "lint:fix": "pnpm lint --fix",
57
+ "test": "jest",
58
+ "unimported": "unimported"
59
+ }
60
+ }
@@ -0,0 +1,217 @@
1
+ import type Transport from "@ledgerhq/hw-transport";
2
+ import { Address } from "@multiversx/sdk-core";
3
+ import BIPPath from "bip32-path";
4
+
5
+ const CHUNK_SIZE = 150;
6
+ const CURVE_MASK = 0x80;
7
+ const CLA = 0xed;
8
+ const INS = {
9
+ GET_VERSION: 0x02,
10
+ GET_ADDRESS: 0x03,
11
+ SET_ADDRESS: 0x05,
12
+ PROVIDE_ESDT_INFO: 0x08,
13
+ };
14
+ const SIGN_HASH_TX_INS = 0x07;
15
+ const SW_OK = 0x9000;
16
+ const SW_CANCEL = 0x6986;
17
+
18
+ /**
19
+ * MultiversX API
20
+ *
21
+ * @example
22
+ * import MultiversX from "@ledgerhq/hw-app-multiversx";
23
+ * const multiversx = new MultiversX(transport)
24
+ */
25
+ export default class MultiversX {
26
+ transport: Transport;
27
+
28
+ constructor(transport: Transport, scrambleKey = "eGLD") {
29
+ this.transport = transport;
30
+ transport.decorateAppAPIMethods(
31
+ this,
32
+ [
33
+ "getAddress",
34
+ "setAddress",
35
+ "signTransaction",
36
+ "signMessage",
37
+ "getAppConfiguration",
38
+ "provideESDTInfo",
39
+ ],
40
+ scrambleKey,
41
+ );
42
+ }
43
+
44
+ /**
45
+ * Get MultiversX app configuration.
46
+ *
47
+ * @return an object with a contractData, accountIndex, addressIndex, version
48
+ * @example
49
+ * const result = await multiversx.getAppConfiguration();
50
+ * const { contractData, accountIndex, addressIndex, version } = result;
51
+ */
52
+ async getAppConfiguration(): Promise<any> {
53
+ const response = await this.transport.send(CLA, INS.GET_VERSION, 0x00, 0x00);
54
+ return {
55
+ contractData: response[0],
56
+ accountIndex: response[1],
57
+ addressIndex: response[2],
58
+ version: `${response[3]}.${response[4]}.${response[5]}`,
59
+ };
60
+ }
61
+
62
+ serializePath(path: Array<number>) {
63
+ const buf = Buffer.alloc(8);
64
+ buf.writeUInt32BE(path[3], 0);
65
+ buf.writeUInt32BE(path[2], 4);
66
+ return buf;
67
+ }
68
+
69
+ /**
70
+ * Get MultiversX address for a given BIP 32 path.
71
+ *
72
+ * @param path a path in BIP 32 format
73
+ * @param boolDisplay optionally enable or not the display
74
+ * @return an object with a address
75
+ * @example
76
+ * const result = await multiversx.getAddress("44'/508'/0'/0'/0'");
77
+ * const { publicKey, address } = result;
78
+ */
79
+ async getAddress(
80
+ path: string,
81
+ boolDisplay?: boolean,
82
+ ): Promise<{
83
+ publicKey: string;
84
+ address: string;
85
+ }> {
86
+ const bipPath = BIPPath.fromString(path).toPathArray();
87
+ const data = this.serializePath(bipPath);
88
+ const response = await this.transport.send(
89
+ CLA,
90
+ INS.GET_ADDRESS,
91
+ boolDisplay ? 0x01 : 0x00,
92
+ 0x00,
93
+ data,
94
+ [SW_OK, SW_CANCEL],
95
+ );
96
+
97
+ const addressLength = response[0];
98
+ const address = Address.newFromBech32(response.slice(1, 1 + addressLength).toString("ascii"));
99
+
100
+ return {
101
+ publicKey: address.toHex(),
102
+ address: address.toBech32(),
103
+ };
104
+ }
105
+
106
+ /**
107
+ * Set MultiversX address for a given BIP 32 path.
108
+ *
109
+ * @param path a path in BIP 32 format
110
+ * @param display optionally enable or not the display
111
+ * @return an object with a address
112
+ * @example
113
+ * const result = await multiversx.setAddress("44'/508'/0'/0/0");
114
+ * result : Buffer;
115
+ */
116
+ async setAddress(path: string, display?: boolean) {
117
+ const bipPath = BIPPath.fromString(path).toPathArray();
118
+ const data = this.serializePath(bipPath);
119
+ await this.transport.send(CLA, INS.SET_ADDRESS, display ? 0x01 : 0x00, 0x00, data, [
120
+ SW_OK,
121
+ SW_CANCEL,
122
+ ]);
123
+ }
124
+
125
+ async signTransaction(path: string, message: string): Promise<string> {
126
+ const { signature } = await this.sign(path, message);
127
+
128
+ if (signature === null) {
129
+ throw new Error("null signature received");
130
+ }
131
+
132
+ return signature.toString("hex");
133
+ }
134
+
135
+ async sign(path: string, message: string): Promise<{ signature: null | Buffer }> {
136
+ const chunks: Buffer[] = [];
137
+ const buffer: Buffer = Buffer.from(message);
138
+
139
+ for (let i = 0; i < buffer.length; i += CHUNK_SIZE) {
140
+ let end = i + CHUNK_SIZE;
141
+
142
+ if (i > buffer.length) {
143
+ end = buffer.length;
144
+ }
145
+
146
+ chunks.push(buffer.slice(i, end));
147
+ }
148
+
149
+ const apdus: any[] = [];
150
+ chunks.forEach((data, index) => {
151
+ const apdu: any = {
152
+ cla: CLA,
153
+ ins: SIGN_HASH_TX_INS,
154
+ p1: index === 0 ? 0x00 : CURVE_MASK,
155
+ p2: CURVE_MASK,
156
+ data,
157
+ };
158
+ apdus.push(apdu);
159
+ });
160
+
161
+ let response: any = {};
162
+ for (const apdu of apdus) {
163
+ response = await this.transport.send(apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.data);
164
+ }
165
+
166
+ if (response.length !== 67 || response[0] !== 64) {
167
+ throw new Error("invalid signature received from ledger device");
168
+ }
169
+
170
+ const signature = response.slice(1, response.length - 2).toString("hex");
171
+ return { signature };
172
+ }
173
+
174
+ serializeESDTInfo(
175
+ ticker: string,
176
+ id: string,
177
+ decimals: number,
178
+ chainId: string,
179
+ signature: string,
180
+ ): Buffer {
181
+ const tickerLengthBuffer = Buffer.from([ticker.length]);
182
+ const tickerBuffer = Buffer.from(ticker);
183
+ const idLengthBuffer = Buffer.from([id.length]);
184
+ const idBuffer = Buffer.from(id);
185
+ const decimalsBuffer = Buffer.from([decimals]);
186
+ const chainIdLengthBuffer = Buffer.from([chainId.length]);
187
+ const chainIdBuffer = Buffer.from(chainId);
188
+ const signatureBuffer = Buffer.from(signature, "hex");
189
+ const infoBuffer = [
190
+ tickerLengthBuffer,
191
+ tickerBuffer,
192
+ idLengthBuffer,
193
+ idBuffer,
194
+ decimalsBuffer,
195
+ chainIdLengthBuffer,
196
+ chainIdBuffer,
197
+ signatureBuffer,
198
+ ];
199
+ return Buffer.concat(infoBuffer);
200
+ }
201
+
202
+ async provideESDTInfo(
203
+ ticker?: string,
204
+ id?: string,
205
+ decimals?: number,
206
+ chainId?: string,
207
+ signature?: string,
208
+ ): Promise<any> {
209
+ if (!ticker || !id || !decimals || !chainId || !signature) {
210
+ throw new Error("Invalid ESDT token credentials!");
211
+ }
212
+
213
+ const data = this.serializeESDTInfo(ticker, id, decimals, chainId, signature);
214
+
215
+ return await this.transport.send(CLA, INS.PROVIDE_ESDT_INFO, 0x00, 0x00, data);
216
+ }
217
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "lib"
5
+ },
6
+ "include": ["src/**/*"]
7
+ }