@ledgerhq/hw-app-eth 6.28.2 → 6.29.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 +5 -2
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +58 -16
  4. package/jest.config.ts +6 -0
  5. package/lib/Eth.d.ts +37 -0
  6. package/lib/Eth.d.ts.map +1 -1
  7. package/lib/Eth.js +66 -72
  8. package/lib/Eth.js.map +1 -1
  9. package/lib/modules/EIP712/EIP712.types.d.ts +44 -0
  10. package/lib/modules/EIP712/EIP712.types.d.ts.map +1 -0
  11. package/lib/modules/EIP712/EIP712.types.js +3 -0
  12. package/lib/modules/EIP712/EIP712.types.js.map +1 -0
  13. package/lib/modules/EIP712/EIP712.utils.d.ts +65 -0
  14. package/lib/modules/EIP712/EIP712.utils.d.ts.map +1 -0
  15. package/lib/modules/EIP712/EIP712.utils.js +217 -0
  16. package/lib/modules/EIP712/EIP712.utils.js.map +1 -0
  17. package/lib/modules/EIP712/index.d.ts +60 -0
  18. package/lib/modules/EIP712/index.d.ts.map +1 -0
  19. package/lib/modules/EIP712/index.js +554 -0
  20. package/lib/modules/EIP712/index.js.map +1 -0
  21. package/lib/utils.d.ts +15 -1
  22. package/lib/utils.d.ts.map +1 -1
  23. package/lib/utils.js +43 -3
  24. package/lib/utils.js.map +1 -1
  25. package/lib-es/Eth.d.ts +37 -0
  26. package/lib-es/Eth.d.ts.map +1 -1
  27. package/lib-es/Eth.js +42 -48
  28. package/lib-es/Eth.js.map +1 -1
  29. package/lib-es/modules/EIP712/EIP712.types.d.ts +44 -0
  30. package/lib-es/modules/EIP712/EIP712.types.d.ts.map +1 -0
  31. package/lib-es/modules/EIP712/EIP712.types.js +2 -0
  32. package/lib-es/modules/EIP712/EIP712.types.js.map +1 -0
  33. package/lib-es/modules/EIP712/EIP712.utils.d.ts +65 -0
  34. package/lib-es/modules/EIP712/EIP712.utils.d.ts.map +1 -0
  35. package/lib-es/modules/EIP712/EIP712.utils.js +211 -0
  36. package/lib-es/modules/EIP712/EIP712.utils.js.map +1 -0
  37. package/lib-es/modules/EIP712/index.d.ts +60 -0
  38. package/lib-es/modules/EIP712/index.d.ts.map +1 -0
  39. package/lib-es/modules/EIP712/index.js +549 -0
  40. package/lib-es/modules/EIP712/index.js.map +1 -0
  41. package/lib-es/services/ledger/contracts.d.ts +0 -0
  42. package/lib-es/services/ledger/contracts.d.ts.map +0 -0
  43. package/lib-es/services/ledger/contracts.js +0 -0
  44. package/lib-es/services/ledger/contracts.js.map +0 -0
  45. package/lib-es/services/ledger/erc20.d.ts +0 -0
  46. package/lib-es/services/ledger/erc20.d.ts.map +0 -0
  47. package/lib-es/services/ledger/erc20.js +0 -0
  48. package/lib-es/services/ledger/erc20.js.map +0 -0
  49. package/lib-es/services/ledger/index.d.ts +0 -0
  50. package/lib-es/services/ledger/index.d.ts.map +0 -0
  51. package/lib-es/services/ledger/index.js +0 -0
  52. package/lib-es/services/ledger/index.js.map +0 -0
  53. package/lib-es/services/ledger/loadConfig.d.ts +0 -0
  54. package/lib-es/services/ledger/loadConfig.d.ts.map +0 -0
  55. package/lib-es/services/ledger/loadConfig.js +0 -0
  56. package/lib-es/services/ledger/loadConfig.js.map +0 -0
  57. package/lib-es/services/ledger/nfts.d.ts +0 -0
  58. package/lib-es/services/ledger/nfts.d.ts.map +0 -0
  59. package/lib-es/services/ledger/nfts.js +0 -0
  60. package/lib-es/services/ledger/nfts.js.map +0 -0
  61. package/lib-es/services/types.d.ts +0 -0
  62. package/lib-es/services/types.d.ts.map +0 -0
  63. package/lib-es/services/types.js +0 -0
  64. package/lib-es/services/types.js.map +0 -0
  65. package/lib-es/utils.d.ts +15 -1
  66. package/lib-es/utils.d.ts.map +1 -1
  67. package/lib-es/utils.js +38 -2
  68. package/lib-es/utils.js.map +1 -1
  69. package/package.json +13 -8
  70. package/src/Eth.ts +59 -56
  71. package/src/modules/EIP712/EIP712.types.ts +54 -0
  72. package/src/modules/EIP712/EIP712.utils.ts +251 -0
  73. package/src/modules/EIP712/index.ts +409 -0
  74. package/src/utils.ts +42 -2
  75. package/tests/EIP712.unit.test.ts +760 -0
  76. package/tests/sample-messages/0.apdus +58 -0
  77. package/tests/sample-messages/0.json +44 -0
  78. package/tests/sample-messages/1.apdus +66 -0
  79. package/tests/sample-messages/1.json +50 -0
  80. package/tests/sample-messages/10.apdus +30 -0
  81. package/tests/sample-messages/10.json +23 -0
  82. package/tests/sample-messages/2.apdus +126 -0
  83. package/tests/sample-messages/2.json +153 -0
  84. package/tests/sample-messages/3.apdus +42 -0
  85. package/tests/sample-messages/3.json +31 -0
  86. package/tests/sample-messages/4.apdus +84 -0
  87. package/tests/sample-messages/4.json +110 -0
  88. package/tests/sample-messages/5.apdus +112 -0
  89. package/tests/sample-messages/5.json +92 -0
  90. package/tests/sample-messages/6.apdus +94 -0
  91. package/tests/sample-messages/6.json +78 -0
  92. package/tests/sample-messages/7.apdus +70 -0
  93. package/tests/sample-messages/7.json +55 -0
  94. package/tests/sample-messages/8.apdus +68 -0
  95. package/tests/sample-messages/8.json +50 -0
  96. package/tests/sample-messages/9.apdus +68 -0
  97. package/tests/sample-messages/9.json +50 -0
  98. package/LICENSE +0 -202
  99. package/lib-es/contracts.d.ts +0 -17
  100. package/lib-es/contracts.d.ts.map +0 -1
  101. package/lib-es/contracts.js +0 -103
  102. package/lib-es/contracts.js.map +0 -1
  103. package/lib-es/erc20.d.ts +0 -22
  104. package/lib-es/erc20.d.ts.map +0 -1
  105. package/lib-es/erc20.js +0 -64
  106. package/lib-es/erc20.js.map +0 -1
package/lib-es/utils.js CHANGED
@@ -1,6 +1,29 @@
1
1
  import { encode, decode } from "@ethersproject/rlp";
2
2
  import { BigNumber } from "bignumber.js";
3
- export function decodeTxInfo(rawTx) {
3
+ export function splitPath(path) {
4
+ var result = [];
5
+ var components = path.split("/");
6
+ components.forEach(function (element) {
7
+ var number = parseInt(element, 10);
8
+ if (isNaN(number)) {
9
+ return; // FIXME shouldn't it throws instead?
10
+ }
11
+ if (element.length > 1 && element[element.length - 1] === "'") {
12
+ number += 0x80000000;
13
+ }
14
+ result.push(number);
15
+ });
16
+ return result;
17
+ }
18
+ export function hexBuffer(str) {
19
+ return Buffer.from(str.startsWith("0x") ? str.slice(2) : str, "hex");
20
+ }
21
+ export function maybeHexBuffer(str) {
22
+ if (!str)
23
+ return null;
24
+ return hexBuffer(str);
25
+ }
26
+ export var decodeTxInfo = function (rawTx) {
4
27
  var VALID_TYPES = [1, 2];
5
28
  var txType = VALID_TYPES.includes(rawTx[0]) ? rawTx[0] : null;
6
29
  var rlpData = txType === null ? rawTx : rawTx.slice(1);
@@ -68,5 +91,18 @@ export function decodeTxInfo(rawTx) {
68
91
  chainIdTruncated: chainIdTruncated,
69
92
  vrsOffset: vrsOffset
70
93
  };
71
- }
94
+ };
95
+ /**
96
+ * @ignore for the README
97
+ *
98
+ * Helper to convert an integer as a hexadecimal string with the right amount of digits
99
+ * to respect the number of bytes given as parameter
100
+ *
101
+ * @param int Integer
102
+ * @param bytes Number of bytes it should be represented as (1 byte = 2 caraters)
103
+ * @returns The given integer as an hexa string padded with the right number of 0
104
+ */
105
+ export var intAsHexBytes = function (int, bytes) {
106
+ return int.toString(16).padStart(2 * bytes, "0");
107
+ };
72
108
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/hw-app-eth",
3
- "version": "6.28.2",
3
+ "version": "6.29.0",
4
4
  "description": "Ledger Hardware Wallet Ethereum Application API",
5
5
  "keywords": [
6
6
  "Ledger",
@@ -32,15 +32,20 @@
32
32
  "@ledgerhq/cryptoassets": "^6.28.2",
33
33
  "@ledgerhq/errors": "^6.10.0",
34
34
  "@ledgerhq/hw-transport": "^6.27.1",
35
+ "@ledgerhq/hw-transport-mocker": "^6.27.1",
35
36
  "@ledgerhq/logs": "^6.10.0",
36
37
  "axios": "^0.26.1",
37
38
  "bignumber.js": "^9.0.2"
38
39
  },
40
+ "gitHead": "dd0dea64b58e5a9125c8a422dcffd29e5ef6abec",
39
41
  "scripts": {
40
- "clean": "bash ../../script/clean.sh",
41
- "build": "bash ../../script/build.sh",
42
- "watch": "bash ../../script/watch.sh",
43
- "doc": "bash ../../script/doc.sh"
44
- },
45
- "gitHead": "e86a1210a6b9d4271116b21c195bcadbf11b950f"
46
- }
42
+ "clean": "rimraf lib lib-es",
43
+ "build": "tsc && tsc -m ES6 --outDir lib-es",
44
+ "prewatch": "pnpm build",
45
+ "watch": "tsc --watch",
46
+ "doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts",
47
+ "lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx",
48
+ "lint:fix": "pnpm lint --fix",
49
+ "test": "jest"
50
+ }
51
+ }
package/src/Eth.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  // FIXME drop:
18
18
  import type Transport from "@ledgerhq/hw-transport";
19
19
  import { BigNumber } from "bignumber.js";
20
- import { decodeTxInfo } from "./utils";
20
+ import { decodeTxInfo, hexBuffer, maybeHexBuffer, splitPath } from "./utils";
21
21
  // NB: these are temporary import for the deprecated fallback mechanism
22
22
  import { LedgerEthTransactionResolution, LoadConfig } from "./services/types";
23
23
  import ledgerService from "./services/ledger";
@@ -25,6 +25,11 @@ import {
25
25
  EthAppNftNotSupported,
26
26
  EthAppPleaseEnableContractData,
27
27
  } from "./errors";
28
+ import {
29
+ signEIP712HashedMessage,
30
+ signEIP712Message,
31
+ EIP712Message,
32
+ } from "./modules/EIP712";
28
33
 
29
34
  export type StarkQuantizationType =
30
35
  | "eth"
@@ -40,33 +45,6 @@ const starkQuantizationTypeMap = {
40
45
  erc721mintable: 5,
41
46
  };
42
47
 
43
- function splitPath(path: string): number[] {
44
- const result: number[] = [];
45
- const components = path.split("/");
46
- components.forEach((element) => {
47
- let number = parseInt(element, 10);
48
- if (isNaN(number)) {
49
- return; // FIXME shouldn't it throws instead?
50
- }
51
- if (element.length > 1 && element[element.length - 1] === "'") {
52
- number += 0x80000000;
53
- }
54
- result.push(number);
55
- });
56
- return result;
57
- }
58
-
59
- function hexBuffer(str: string): Buffer {
60
- return Buffer.from(str.startsWith("0x") ? str.slice(2) : str, "hex");
61
- }
62
-
63
- function maybeHexBuffer(
64
- str: string | null | undefined
65
- ): Buffer | null | undefined {
66
- if (!str) return null;
67
- return hexBuffer(str);
68
- }
69
-
70
48
  const remapTransactionRelatedErrors = (e) => {
71
49
  if (e && e.statusCode === 0x6a80) {
72
50
  return new EthAppPleaseEnableContractData(
@@ -76,6 +54,7 @@ const remapTransactionRelatedErrors = (e) => {
76
54
 
77
55
  return e;
78
56
  };
57
+
79
58
  /**
80
59
  * Ethereum API
81
60
  *
@@ -107,6 +86,7 @@ export default class Eth {
107
86
  "signTransaction",
108
87
  "signPersonalMessage",
109
88
  "getAppConfiguration",
89
+ "signEIP712Message",
110
90
  "signEIP712HashedMessage",
111
91
  "starkGetPublicKey",
112
92
  "starkSignOrder",
@@ -251,9 +231,8 @@ export default class Eth {
251
231
  }
252
232
 
253
233
  const rawTx = Buffer.from(rawTxHex, "hex");
254
- const { vrsOffset, txType, chainId, chainIdTruncated } = decodeTxInfo(
255
- rawTx
256
- );
234
+ const { vrsOffset, txType, chainId, chainIdTruncated } =
235
+ decodeTxInfo(rawTx);
257
236
 
258
237
  const paths = splitPath(path);
259
238
  let response;
@@ -432,31 +411,55 @@ export default class Eth {
432
411
  s: string;
433
412
  r: string;
434
413
  }> {
435
- const domainSeparator = hexBuffer(domainSeparatorHex);
436
- const hashStruct = hexBuffer(hashStructMessageHex);
437
- const paths = splitPath(path);
438
- const buffer = Buffer.alloc(1 + paths.length * 4 + 32 + 32, 0);
439
- let offset = 0;
440
- buffer[0] = paths.length;
441
- paths.forEach((element, index) => {
442
- buffer.writeUInt32BE(element, 1 + 4 * index);
443
- });
444
- offset = 1 + 4 * paths.length;
445
- domainSeparator.copy(buffer, offset);
446
- offset += 32;
447
- hashStruct.copy(buffer, offset);
448
- return this.transport
449
- .send(0xe0, 0x0c, 0x00, 0x00, buffer)
450
- .then((response) => {
451
- const v = response[0];
452
- const r = response.slice(1, 1 + 32).toString("hex");
453
- const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
454
- return {
455
- v,
456
- r,
457
- s,
458
- };
459
- });
414
+ return signEIP712HashedMessage(
415
+ this.transport,
416
+ path,
417
+ domainSeparatorHex,
418
+ hashStructMessageHex
419
+ );
420
+ }
421
+
422
+ /**
423
+ * Sign an EIP-721 formatted message following the specification here:
424
+ * https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.asc#sign-eth-eip-712
425
+ @example
426
+ eth.signEIP721Message("44'/60'/0'/0/0", {
427
+ domain: {
428
+ chainId: 69,
429
+ name: "Da Domain",
430
+ verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
431
+ version: "1"
432
+ },
433
+ types: {
434
+ "EIP712Domain": [
435
+ { name: "name", type: "string" },
436
+ { name: "version", type: "string" },
437
+ { name: "chainId", type: "uint256" },
438
+ { name: "verifyingContract", type: "address" }
439
+ ],
440
+ "Test": [
441
+ { name: "contents", type: "string" }
442
+ ]
443
+ },
444
+ primaryType: "Test",
445
+ message: {contents: "Hello, Bob!"},
446
+ })
447
+ *
448
+ * @param {String} path derivationPath
449
+ * @param {Object} jsonMessage message to sign
450
+ * @param {Boolean} fullImplem use the legacy implementation
451
+ * @returns {Promise}
452
+ */
453
+ async signEIP712Message(
454
+ path: string,
455
+ jsonMessage: EIP712Message,
456
+ fullImplem = false
457
+ ): Promise<{
458
+ v: number;
459
+ s: string;
460
+ r: string;
461
+ }> {
462
+ return signEIP712Message(this.transport, path, jsonMessage, fullImplem);
460
463
  }
461
464
 
462
465
  /**
@@ -0,0 +1,54 @@
1
+ export type EIP712Message = {
2
+ domain: EIP712MessageDomain;
3
+ types: EIP712MessageTypes;
4
+ primaryType: string;
5
+ message: Record<string, unknown>;
6
+ };
7
+
8
+ export type EIP712MessageDomain = Partial<{
9
+ name: string;
10
+ chainId: number;
11
+ version: string;
12
+ verifyingContract: string;
13
+ salt: string;
14
+ }>;
15
+
16
+ export type EIP712MessageTypesEntry = {
17
+ name: string;
18
+ type: string;
19
+ };
20
+
21
+ export type EIP712MessageTypes = {
22
+ EIP712Domain: EIP712MessageTypesEntry[];
23
+ [key: string]: EIP712MessageTypesEntry[];
24
+ };
25
+
26
+ export type StructDefData = Required<
27
+ | {
28
+ structType: "name";
29
+ value: string;
30
+ }
31
+ | {
32
+ structType: "field";
33
+ value: Buffer;
34
+ }
35
+ >;
36
+
37
+ export type StructImplemData = Required<
38
+ | {
39
+ structType: "root";
40
+ value: string;
41
+ }
42
+ | {
43
+ structType: "array";
44
+ value: number;
45
+ }
46
+ | {
47
+ structType: "field";
48
+ value: Required<{
49
+ data: unknown;
50
+ type: string;
51
+ sizeInBits: number | undefined;
52
+ }>;
53
+ }
54
+ >;
@@ -0,0 +1,251 @@
1
+ import { hexBuffer, intAsHexBytes } from "../../utils";
2
+ import { EIP712MessageTypesEntry } from "./EIP712.types";
3
+
4
+ /**
5
+ * @ignore for the README
6
+ *
7
+ * A Map of helpers to get the wanted binary value for
8
+ * each type of array possible in a type definition
9
+ */
10
+ enum EIP712_ARRAY_TYPE_VALUE {
11
+ DYNAMIC = 0,
12
+ FIXED = 1,
13
+ }
14
+
15
+ /**
16
+ * @ignore for the README
17
+ *
18
+ * A Map of helpers to get the id and size to return for each
19
+ * type that can be used in EIP712
20
+ */
21
+ export const EIP712_TYPE_PROPERTIES: Record<
22
+ string,
23
+ {
24
+ key: (size?: number) => number;
25
+ sizeInBits: (size?: number) => number | null;
26
+ }
27
+ > = {
28
+ CUSTOM: {
29
+ key: () => 0,
30
+ sizeInBits: () => null,
31
+ },
32
+ INT: {
33
+ key: () => 1,
34
+ sizeInBits: (size) => Number(size) / 8,
35
+ },
36
+ UINT: {
37
+ key: () => 2,
38
+ sizeInBits: (size) => Number(size) / 8,
39
+ },
40
+ ADDRESS: {
41
+ key: () => 3,
42
+ sizeInBits: () => null,
43
+ },
44
+ BOOL: {
45
+ key: () => 4,
46
+ sizeInBits: () => null,
47
+ },
48
+ STRING: {
49
+ key: () => 5,
50
+ sizeInBits: () => null,
51
+ },
52
+ BYTES: {
53
+ key: (size) => (typeof size !== "undefined" ? 6 : 7),
54
+ sizeInBits: (size) => (typeof size !== "undefined" ? Number(size) : null),
55
+ },
56
+ };
57
+
58
+ /**
59
+ * @ignore for the README
60
+ *
61
+ * A Map of encoders to transform a value to formatted buffer
62
+ */
63
+ export const EIP712_TYPE_ENCODERS = {
64
+ INT(value: number | string | null): Buffer {
65
+ const failSafeValue = value ?? 0;
66
+
67
+ if (typeof failSafeValue === "string" && failSafeValue?.startsWith("0x")) {
68
+ return hexBuffer(failSafeValue);
69
+ }
70
+
71
+ const valueAsInt =
72
+ typeof failSafeValue === "string"
73
+ ? parseInt(failSafeValue, 10)
74
+ : failSafeValue;
75
+
76
+ const valueAsHexString = valueAsInt.toString(16);
77
+ const paddedHexString =
78
+ valueAsHexString.length % 2 ? "0" + valueAsHexString : valueAsHexString;
79
+
80
+ return Buffer.from(paddedHexString, "hex");
81
+ },
82
+
83
+ UINT(value: number | string): Buffer {
84
+ return this.INT(value);
85
+ },
86
+
87
+ BOOL(value: number | string | boolean | null): Buffer {
88
+ return this.INT(typeof value === "boolean" ? Number(value) : value);
89
+ },
90
+
91
+ ADDRESS(value: string | null): Buffer {
92
+ // Only sending the first 10 bytes (why ?)
93
+ return hexBuffer(value ?? "").slice(0, 20);
94
+ },
95
+
96
+ STRING(value: string | null): Buffer {
97
+ return Buffer.from(value ?? "", "utf-8");
98
+ },
99
+
100
+ BYTES(value: string | null, sizeInBits?: number): Buffer {
101
+ const failSafeValue = value ?? "";
102
+ // Why slice again ?
103
+ return hexBuffer(failSafeValue).slice(
104
+ 0,
105
+ sizeInBits ?? (failSafeValue?.length - 2) / 2
106
+ );
107
+ },
108
+ };
109
+
110
+ /**
111
+ * @ignore for the README
112
+ *
113
+ * Helper parsing an EIP712 Type name to return its type and size(s)
114
+ * if it's an array or nested arrays
115
+ *
116
+ * @see EIP712MessageTypes
117
+ *
118
+ * @example "uint8[2][][4]" => [{name: "uint", bits: 8}, [2, null, 4]]
119
+ * @example "bool" => [{name: "bool", bits: null}, []]
120
+ *
121
+ * @param {String} typeName
122
+ * @returns {[{ name: string; bits: Number | null }, Array<Number | null | undefined>]}
123
+ */
124
+ export const destructTypeFromString = (
125
+ typeName?: string
126
+ ): [
127
+ { name: string; bits: number | undefined } | null,
128
+ Array<number | null>
129
+ ] => {
130
+ // Will split "any[][1][10]" in "any", "[][1][10]"
131
+ const splitNameAndArraysRegex = new RegExp(/^([^[\]]*)(\[.*\])*/g);
132
+ // Will match all numbers (or null) inside each array. [0][10][] => [0,10,null]
133
+ const splitArraysRegex = new RegExp(/\[(\d*)\]/g);
134
+ // Will separate the the name from the potential bits allocation. uint8 => [uint,8]
135
+ const splitNameAndNumberRegex = new RegExp(/(\D*)(\d*)/);
136
+
137
+ const [, type, maybeArrays] =
138
+ splitNameAndArraysRegex.exec(typeName || "") || [];
139
+ const [, name, bits] = splitNameAndNumberRegex.exec(type || "") || [];
140
+ const typeDescription = name
141
+ ? { name, bits: bits ? Number(bits) : undefined }
142
+ : null;
143
+
144
+ const arrays = maybeArrays ? [...maybeArrays.matchAll(splitArraysRegex)] : [];
145
+ // Parse each size to either a Number or null
146
+ const arraySizes = arrays.map(([, size]) => (size ? Number(size) : null));
147
+
148
+ return [typeDescription, arraySizes];
149
+ };
150
+
151
+ /**
152
+ * @ignore for the README
153
+ *
154
+ * Helper to construct the hexadecimal ByteString for the description
155
+ * of a field in an EIP712 Message
156
+ *
157
+ * @param isArray
158
+ * @param typeSize
159
+ * @param typeValue
160
+ * @returns {String} HexByteString
161
+ */
162
+ export const constructTypeDescByteString = (
163
+ isArray: boolean,
164
+ typeSize: number | null | undefined,
165
+ typeValue: number
166
+ ): string => {
167
+ if (typeValue >= 16) {
168
+ throw new Error(
169
+ "Eth utils - constructTypeDescByteString - Cannot accept a typeValue >= 16 because the typeValue can only be 4 bits in binary" +
170
+ { isArray, typeSize, typeValue }
171
+ );
172
+ }
173
+ // 1 is array, 0 is not array
174
+ const isArrayBit = isArray ? "1" : "0";
175
+ // 1 has type size, 0 has no type size
176
+ const hasTypeSize = typeof typeSize === "number" ? "1" : "0";
177
+ // 2 unused bits
178
+ const unusedBits = "00";
179
+ // type key as 4 bits
180
+ const typeValueBits = typeValue.toString(2).padStart(4, "0");
181
+
182
+ return intAsHexBytes(
183
+ parseInt(isArrayBit + hasTypeSize + unusedBits + typeValueBits, 2),
184
+ 1
185
+ );
186
+ };
187
+
188
+ /**
189
+ * @ignore for the README
190
+ *
191
+ * Helper to create the buffer to describe an EIP712 types' entry structure
192
+ *
193
+ * @param {EIP712MessageTypesEntry} entry
194
+ * @returns {Buffer}
195
+ */
196
+ export const makeTypeEntryStructBuffer = ({
197
+ name,
198
+ type,
199
+ }: EIP712MessageTypesEntry): Buffer => {
200
+ const [typeDescription, arrSizes] = destructTypeFromString(type as string);
201
+ const isTypeAnArray = Boolean(arrSizes.length);
202
+ const typeProperties =
203
+ EIP712_TYPE_PROPERTIES[typeDescription?.name?.toUpperCase() || ""] ||
204
+ EIP712_TYPE_PROPERTIES.CUSTOM;
205
+
206
+ const typeKey = typeProperties.key(typeDescription?.bits);
207
+ const typeSizeInBits = typeProperties.sizeInBits(typeDescription?.bits);
208
+
209
+ const typeDescData = constructTypeDescByteString(
210
+ isTypeAnArray,
211
+ typeSizeInBits,
212
+ typeKey
213
+ );
214
+
215
+ const bufferArray: Buffer[] = [Buffer.from(typeDescData, "hex")];
216
+
217
+ if (typeProperties === EIP712_TYPE_PROPERTIES.CUSTOM) {
218
+ bufferArray.push(
219
+ Buffer.from(intAsHexBytes(typeDescription?.name?.length ?? 0, 1), "hex")
220
+ );
221
+ bufferArray.push(Buffer.from(typeDescription?.name ?? "", "utf-8"));
222
+ }
223
+
224
+ if (typeof typeSizeInBits === "number") {
225
+ bufferArray.push(Buffer.from(intAsHexBytes(typeSizeInBits, 1), "hex"));
226
+ }
227
+
228
+ if (isTypeAnArray) {
229
+ bufferArray.push(Buffer.from(intAsHexBytes(arrSizes.length, 1), "hex"));
230
+
231
+ arrSizes.forEach((size) => {
232
+ if (typeof size === "number") {
233
+ bufferArray.push(
234
+ Buffer.from(intAsHexBytes(EIP712_ARRAY_TYPE_VALUE.FIXED, 1), "hex"),
235
+ Buffer.from(intAsHexBytes(size, 1), "hex")
236
+ );
237
+ } else {
238
+ bufferArray.push(
239
+ Buffer.from(intAsHexBytes(EIP712_ARRAY_TYPE_VALUE.DYNAMIC, 1), "hex")
240
+ );
241
+ }
242
+ });
243
+ }
244
+
245
+ bufferArray.push(
246
+ Buffer.from(intAsHexBytes(name.length, 1), "hex"),
247
+ Buffer.from(name, "utf-8")
248
+ );
249
+
250
+ return Buffer.concat(bufferArray);
251
+ };