@ledgerhq/hw-app-eth 7.0.0-nightly.2 → 7.0.0-nightly.20251120135143
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.
- package/.turbo/turbo-build.log +2 -2
- package/.unimportedrc.json +3 -28
- package/CHANGELOG.md +994 -17
- package/README.md +100 -0
- package/jest.config.ts +18 -0
- package/lib/Eth.d.ts +3 -18
- package/lib/Eth.d.ts.map +1 -1
- package/lib/Eth.js +160 -198
- package/lib/Eth.js.map +1 -1
- package/lib/errors.d.ts +3 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +2 -1
- package/lib/errors.js.map +1 -1
- package/lib/modules/Domains/index.js +6 -15
- package/lib/modules/Domains/index.js.map +1 -1
- package/lib/modules/EIP712/index.d.ts.map +1 -1
- package/lib/modules/EIP712/index.js +112 -125
- package/lib/modules/EIP712/index.js.map +1 -1
- package/lib/modules/EIP712/types.d.ts +1 -0
- package/lib/modules/EIP712/types.d.ts.map +1 -1
- package/lib/modules/EIP712/utils.d.ts +1 -0
- package/lib/modules/EIP712/utils.d.ts.map +1 -1
- package/lib/modules/EIP712/utils.js +14 -24
- package/lib/modules/EIP712/utils.js.map +1 -1
- package/lib/modules/Uniswap/constants.d.ts.map +1 -1
- package/lib/modules/Uniswap/constants.js +1 -0
- package/lib/modules/Uniswap/constants.js.map +1 -1
- package/lib/modules/Uniswap/decoders.d.ts.map +1 -1
- package/lib/modules/Uniswap/decoders.js +8 -3
- package/lib/modules/Uniswap/decoders.js.map +1 -1
- package/lib/modules/Uniswap/index.d.ts +2 -1
- package/lib/modules/Uniswap/index.d.ts.map +1 -1
- package/lib/modules/Uniswap/index.js +11 -20
- package/lib/modules/Uniswap/index.js.map +1 -1
- package/lib/modules/Uniswap/types.d.ts +1 -1
- package/lib/modules/Uniswap/types.d.ts.map +1 -1
- package/lib/services/ledger/contracts.js +4 -13
- package/lib/services/ledger/contracts.js.map +1 -1
- package/lib/services/ledger/erc20.d.ts +2 -1
- package/lib/services/ledger/erc20.d.ts.map +1 -1
- package/lib/services/ledger/erc20.js +16 -32
- package/lib/services/ledger/erc20.js.map +1 -1
- package/lib/services/ledger/index.d.ts.map +1 -1
- package/lib/services/ledger/index.js +34 -32
- package/lib/services/ledger/index.js.map +1 -1
- package/lib/services/ledger/loadConfig.d.ts.map +1 -1
- package/lib/services/ledger/loadConfig.js +7 -1
- package/lib/services/ledger/loadConfig.js.map +1 -1
- package/lib/services/ledger/nfts.js +9 -19
- package/lib/services/ledger/nfts.js.map +1 -1
- package/lib/services/types.d.ts +3 -0
- package/lib/services/types.d.ts.map +1 -1
- package/lib/utils.d.ts +56 -9
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +175 -81
- package/lib/utils.js.map +1 -1
- package/lib-es/Eth.d.ts +3 -18
- package/lib-es/Eth.d.ts.map +1 -1
- package/lib-es/Eth.js +160 -198
- package/lib-es/Eth.js.map +1 -1
- package/lib-es/errors.d.ts +3 -0
- package/lib-es/errors.d.ts.map +1 -1
- package/lib-es/errors.js +1 -0
- package/lib-es/errors.js.map +1 -1
- package/lib-es/modules/Domains/index.js +6 -15
- package/lib-es/modules/Domains/index.js.map +1 -1
- package/lib-es/modules/EIP712/index.d.ts.map +1 -1
- package/lib-es/modules/EIP712/index.js +112 -125
- package/lib-es/modules/EIP712/index.js.map +1 -1
- package/lib-es/modules/EIP712/types.d.ts +1 -0
- package/lib-es/modules/EIP712/types.d.ts.map +1 -1
- package/lib-es/modules/EIP712/utils.d.ts +1 -0
- package/lib-es/modules/EIP712/utils.d.ts.map +1 -1
- package/lib-es/modules/EIP712/utils.js +14 -24
- package/lib-es/modules/EIP712/utils.js.map +1 -1
- package/lib-es/modules/Uniswap/constants.d.ts.map +1 -1
- package/lib-es/modules/Uniswap/constants.js +1 -0
- package/lib-es/modules/Uniswap/constants.js.map +1 -1
- package/lib-es/modules/Uniswap/decoders.d.ts.map +1 -1
- package/lib-es/modules/Uniswap/decoders.js +8 -3
- package/lib-es/modules/Uniswap/decoders.js.map +1 -1
- package/lib-es/modules/Uniswap/index.d.ts +2 -1
- package/lib-es/modules/Uniswap/index.d.ts.map +1 -1
- package/lib-es/modules/Uniswap/index.js +11 -20
- package/lib-es/modules/Uniswap/index.js.map +1 -1
- package/lib-es/modules/Uniswap/types.d.ts +1 -1
- package/lib-es/modules/Uniswap/types.d.ts.map +1 -1
- package/lib-es/services/ledger/contracts.js +4 -13
- package/lib-es/services/ledger/contracts.js.map +1 -1
- package/lib-es/services/ledger/erc20.d.ts +2 -1
- package/lib-es/services/ledger/erc20.d.ts.map +1 -1
- package/lib-es/services/ledger/erc20.js +16 -32
- package/lib-es/services/ledger/erc20.js.map +1 -1
- package/lib-es/services/ledger/index.d.ts.map +1 -1
- package/lib-es/services/ledger/index.js +34 -32
- package/lib-es/services/ledger/index.js.map +1 -1
- package/lib-es/services/ledger/loadConfig.d.ts.map +1 -1
- package/lib-es/services/ledger/loadConfig.js +7 -1
- package/lib-es/services/ledger/loadConfig.js.map +1 -1
- package/lib-es/services/ledger/nfts.js +9 -19
- package/lib-es/services/ledger/nfts.js.map +1 -1
- package/lib-es/services/types.d.ts +3 -0
- package/lib-es/services/types.d.ts.map +1 -1
- package/lib-es/utils.d.ts +56 -9
- package/lib-es/utils.d.ts.map +1 -1
- package/lib-es/utils.js +148 -81
- package/lib-es/utils.js.map +1 -1
- package/package.json +19 -15
- package/src/Eth.ts +51 -82
- package/src/errors.ts +3 -0
- package/src/modules/EIP712/index.ts +17 -4
- package/src/modules/Uniswap/constants.ts +1 -0
- package/src/modules/Uniswap/decoders.ts +10 -3
- package/src/modules/Uniswap/index.ts +9 -8
- package/src/modules/Uniswap/types.ts +2 -1
- package/src/services/ledger/erc20.ts +16 -19
- package/src/services/ledger/index.ts +50 -22
- package/src/services/ledger/loadConfig.ts +4 -1
- package/src/services/ledger/nfts.ts +1 -1
- package/src/services/types.ts +12 -0
- package/src/utils.ts +170 -85
- package/tests/EIP712/filtered-signMessage.unit.test.ts +28 -116
- package/tests/EIP712/noFilter-signMessage.unit.test.ts +0 -2
- package/tests/ERC20/ERC20-CAL-KO.unit.test.ts +14 -25
- package/tests/ERC20/ERC20-CAL-OK.unit.test.ts +15 -10
- package/tests/Eth.unit.test.ts +242 -314
- package/tests/Uniswap/decoders.unit.test.ts +10 -0
- package/tests/Uniswap/index.unit.test.ts +17 -26
- package/tests/fixtures/messages/15-permit.json +3 -3
- package/tests/fixtures/messages/16-permit2.json +3 -3
- package/tests/fixtures/messages/17-uniswapx.json +5 -5
- package/tests/fixtures/utils.ts +17 -18
- package/tests/ledgerService.unit.test.ts +5 -7
- package/tests/utils.unit.test.ts +341 -0
|
@@ -73,6 +73,15 @@ describe("Uniswap", () => {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it("should decode a SWEEP command input", () => {
|
|
77
|
+
// see tx 0xcc3a651b4f962576ed8f2142326271d090dcb701b754429f99e9b77d38cedc30
|
|
78
|
+
const input =
|
|
79
|
+
"0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000001125ffbea29018485cc228e39aade004a359fe990000000000000000000000000000000000000000000000000000000000000000";
|
|
80
|
+
expect(UniswapDecoders["SWEEP"](input, 1)).toEqual([
|
|
81
|
+
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
|
|
76
85
|
it("should return an empty array for other supported commands", () => {
|
|
77
86
|
const input =
|
|
78
87
|
"0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000204fce5e3e2502611000000000000000000000000000000000000000000000000000000001f942ac9a54ae2700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000003ffeea07a27fab7ad1df5297fa75e77a43cb5790000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000ccae1bc46fb018dd396ed4c45565d4cb9d41098";
|
|
@@ -86,6 +95,7 @@ describe("Uniswap", () => {
|
|
|
86
95
|
"V3_SWAP_EXACT_OUT",
|
|
87
96
|
"WRAP_ETH",
|
|
88
97
|
"UNWRAP_ETH",
|
|
98
|
+
"SWEEP",
|
|
89
99
|
].includes(command)
|
|
90
100
|
) {
|
|
91
101
|
return decoder;
|
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
import nock from "nock";
|
|
2
|
-
import {
|
|
2
|
+
import { BigNumber } from "@ethersproject/bignumber";
|
|
3
|
+
import { AddressZero } from "@ethersproject/constants";
|
|
4
|
+
import { type Transaction } from "@ethersproject/transactions";
|
|
5
|
+
import SignatureCALEth from "../fixtures/SignatureCALEth";
|
|
6
|
+
import {
|
|
7
|
+
UNISWAP_EXECUTE_SELECTOR,
|
|
8
|
+
UNISWAP_UNIVERSAL_ROUTER_ADDRESS,
|
|
9
|
+
} from "../../src/modules/Uniswap/constants";
|
|
3
10
|
import {
|
|
4
11
|
getCommandsAndTokensFromUniswapCalldata,
|
|
5
12
|
isSupported,
|
|
6
13
|
loadInfosForUniswap,
|
|
7
14
|
} from "../../src/modules/Uniswap";
|
|
8
|
-
import {
|
|
9
|
-
UNISWAP_EXECUTE_SELECTOR,
|
|
10
|
-
UNISWAP_UNIVERSAL_ROUTER_ADDRESS,
|
|
11
|
-
} from "../../src/modules/Uniswap/constants";
|
|
12
|
-
import SignatureCALEth from "../fixtures/SignatureCALEth";
|
|
13
15
|
|
|
14
16
|
nock.disableNetConnect();
|
|
15
|
-
jest.mock("@ledgerhq/cryptoassets-evm-signatures/data/evm/index", () => ({
|
|
16
|
-
get signatures() {
|
|
17
|
-
return {
|
|
18
|
-
1: SignatureCALEth,
|
|
19
|
-
};
|
|
20
|
-
},
|
|
21
|
-
}));
|
|
22
17
|
|
|
23
18
|
describe("Uniswap", () => {
|
|
24
19
|
describe("index", () => {
|
|
25
20
|
describe("isSupported", () => {
|
|
26
21
|
it("should return false for a non-Uniswap transaction", () => {
|
|
27
|
-
expect(isSupported("0x",
|
|
22
|
+
expect(isSupported("0x", AddressZero, 1, [])).toBe(false);
|
|
28
23
|
});
|
|
29
24
|
|
|
30
25
|
it("should return false for a Uniswap transaction with an invalid selector", () => {
|
|
@@ -142,16 +137,16 @@ describe("Uniswap", () => {
|
|
|
142
137
|
const calldata =
|
|
143
138
|
"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000669bad2800000000000000000000000000000000000000000000000000000000000000040a08060c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000bdaa645097ef80f9d475f341d0d107a45b3a000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000687ce06c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b00000000000000000000000000000000000000000000000000000000687ce06c00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000004142794d71565541a435d1bc910db84510c4d31ad35ff8c046222b2c232fcd99a6256a8f1abe7d42a44f3d92d65f9232db76df2fbef3dfa76eca64b034ed4df5321c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001bffcca36d953d12266cb000000000000000000000000000000000000000000000000027c3dea3f90dafd00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000bdaa645097ef80f9d475f341d0d107a45b3a000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006eb940753b4b52fbec8d33c418133fdb0d4405e6000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000001dc813a4ee4410f144ae2122051c1cfc436f24a00000000000000000000000000000000000000000000000000275e122c92b911e";
|
|
144
139
|
|
|
145
|
-
const transaction:
|
|
140
|
+
const transaction: Transaction = {
|
|
146
141
|
to: UNISWAP_UNIVERSAL_ROUTER_ADDRESS,
|
|
147
142
|
data: calldata,
|
|
148
|
-
gasLimit:
|
|
143
|
+
gasLimit: BigNumber.from(21_000),
|
|
149
144
|
nonce: 0,
|
|
150
|
-
value:
|
|
145
|
+
value: BigNumber.from(0),
|
|
151
146
|
chainId: 1,
|
|
152
147
|
};
|
|
153
148
|
|
|
154
|
-
const res = await loadInfosForUniswap(transaction, 1);
|
|
149
|
+
const res = await loadInfosForUniswap(transaction, 1, { staticERC20Signatures: { 1: SignatureCALEth } });
|
|
155
150
|
expect(res).toEqual({
|
|
156
151
|
pluginData: Buffer.from(
|
|
157
152
|
"07556e69737761703fc91a3afd70395cd496c647d5a6cc9d4b2b7fad3593564c3044022014391e8f355867a57fe88f6a5a4dbcb8bf8f888a9db3ff3449caf72d120396bd02200c13d9c3f79400fe0aa0434ac54d59b79503c9964a4abc3e8cd22763e0242935",
|
|
@@ -162,21 +157,17 @@ describe("Uniswap", () => {
|
|
|
162
157
|
"0457455448c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000012000000013045022100b47ee8551c15a2cf681c649651e987d7e527c481d27c38da1f971a8242792bd3022069c3f688ac5493a23dab5798e3c9b07484765069e1d4be14321aae4d92cb8cbe",
|
|
163
158
|
"hex",
|
|
164
159
|
),
|
|
165
|
-
Buffer.from(
|
|
166
|
-
"0457455448c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000012000000013045022100b47ee8551c15a2cf681c649651e987d7e527c481d27c38da1f971a8242792bd3022069c3f688ac5493a23dab5798e3c9b07484765069e1d4be14321aae4d92cb8cbe",
|
|
167
|
-
"hex",
|
|
168
|
-
),
|
|
169
160
|
],
|
|
170
161
|
});
|
|
171
162
|
});
|
|
172
163
|
|
|
173
164
|
it("should return an empty object for an unsupported Uniswap transaction", async () => {
|
|
174
|
-
const transaction:
|
|
175
|
-
to:
|
|
165
|
+
const transaction: Transaction = {
|
|
166
|
+
to: AddressZero,
|
|
176
167
|
data: "0x",
|
|
177
|
-
gasLimit:
|
|
168
|
+
gasLimit: BigNumber.from(21_000),
|
|
178
169
|
nonce: 0,
|
|
179
|
-
value:
|
|
170
|
+
value: BigNumber.from(0),
|
|
180
171
|
chainId: 1,
|
|
181
172
|
};
|
|
182
173
|
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
"primaryType": "Permit",
|
|
9
9
|
"message": {
|
|
10
10
|
"deadline": 1718992051,
|
|
11
|
-
"nonce": 0,
|
|
12
11
|
"spender": "0x111111125421ca6dc452d289314280a0f8842a65",
|
|
13
|
-
"
|
|
14
|
-
"value": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
|
12
|
+
"nonce": 0,
|
|
13
|
+
"value": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
|
14
|
+
"owner": "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d"
|
|
15
15
|
},
|
|
16
16
|
"types": {
|
|
17
17
|
"EIP712Domain": [
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
"primaryType": "PermitSingle",
|
|
8
8
|
"message": {
|
|
9
9
|
"details": {
|
|
10
|
-
"token": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619",
|
|
11
|
-
"amount": "69420000000000000000",
|
|
12
10
|
"expiration": "1718184249",
|
|
13
|
-
"
|
|
11
|
+
"amount": "69420000000000000000",
|
|
12
|
+
"nonce": "0",
|
|
13
|
+
"token": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619"
|
|
14
14
|
},
|
|
15
15
|
"spender": "0xec7be89e9d109e7e3fec59c222cf297125fefda2",
|
|
16
16
|
"sigDeadline": "1715594049"
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"deadline": "1718467096",
|
|
16
16
|
"witness": {
|
|
17
17
|
"info": {
|
|
18
|
-
"reactor": "0x6000da47483062a0d734ba3dc7576ce6a0b645c4",
|
|
19
|
-
"swapper": "0x224cbc440944c72e951507e97d8bf5ffa2e3d2b9",
|
|
20
18
|
"nonce": "1993354326232431306240697018571020274189859638820531235067341608173853199105",
|
|
21
|
-
"
|
|
19
|
+
"swapper": "0x224cbc440944c72e951507e97d8bf5ffa2e3d2b9",
|
|
22
20
|
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
|
21
|
+
"reactor": "0x6000da47483062a0d734ba3dc7576ce6a0b645c4",
|
|
22
|
+
"deadline": "1718467096",
|
|
23
23
|
"additionalValidationData": "0x"
|
|
24
24
|
},
|
|
25
25
|
"decayStartTime": "1718467024",
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
"inputEndAmount": "100000000000000000",
|
|
32
32
|
"outputs": [
|
|
33
33
|
{
|
|
34
|
-
"token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
35
34
|
"startAmount": "348572327",
|
|
35
|
+
"token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
36
36
|
"endAmount": "332452012",
|
|
37
37
|
"recipient": "0x224cbc440944c72e951507e97d8bf5ffa2e3d2b9"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
|
+
"endAmount": "833213",
|
|
40
41
|
"token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
41
42
|
"startAmount": "873614",
|
|
42
|
-
"endAmount": "833213",
|
|
43
43
|
"recipient": "0x27213e28d7fda5c57fe9e5dd923818dbccf71c47"
|
|
44
44
|
}
|
|
45
45
|
]
|
package/tests/fixtures/utils.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Interface } from "@ethersproject/abi";
|
|
2
|
+
import { serialize as serializeTransaction } from "@ethersproject/transactions";
|
|
2
3
|
import ERC20Abi from "./ABI/ERC20.json";
|
|
3
4
|
import ERC721Abi from "./ABI/ERC721.json";
|
|
4
5
|
import ERC1155Abi from "./ABI/ERC1155.json";
|
|
5
6
|
import PARASWAPAbi from "./ABI/PARASWAP.json";
|
|
6
7
|
|
|
7
|
-
const ERC20Interface = new
|
|
8
|
-
const ERC721Interface = new
|
|
9
|
-
const ERC1155Interface = new
|
|
10
|
-
const PARASWAPInterface = new
|
|
8
|
+
const ERC20Interface = new Interface(ERC20Abi);
|
|
9
|
+
const ERC721Interface = new Interface(ERC721Abi);
|
|
10
|
+
const ERC1155Interface = new Interface(ERC1155Abi);
|
|
11
|
+
const PARASWAPInterface = new Interface(PARASWAPAbi);
|
|
11
12
|
|
|
12
13
|
export const transactionContracts = {
|
|
13
14
|
erc20: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
|
@@ -102,16 +103,14 @@ export const transactionData = {
|
|
|
102
103
|
};
|
|
103
104
|
|
|
104
105
|
export const getSerializedTransaction = (to: string, data: string): string =>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
})
|
|
117
|
-
.substring(2);
|
|
106
|
+
serializeTransaction({
|
|
107
|
+
to,
|
|
108
|
+
nonce: 0,
|
|
109
|
+
gasLimit: 21000,
|
|
110
|
+
data,
|
|
111
|
+
value: 1,
|
|
112
|
+
chainId: 1,
|
|
113
|
+
maxPriorityFeePerGas: 10000,
|
|
114
|
+
maxFeePerGas: 1000000,
|
|
115
|
+
type: 2,
|
|
116
|
+
}).substring(2);
|
|
@@ -11,7 +11,7 @@ import * as uniswapModule from "../src/modules/Uniswap";
|
|
|
11
11
|
import { ResolutionConfig } from "../src/services/types";
|
|
12
12
|
import { ledgerService } from "../src/Eth";
|
|
13
13
|
|
|
14
|
-
const loadConfig = getLoadConfig();
|
|
14
|
+
const loadConfig = getLoadConfig({ staticERC20Signatures: { 1: signatureCALEth } });
|
|
15
15
|
const resolutionConfig: ResolutionConfig = {
|
|
16
16
|
nft: true,
|
|
17
17
|
erc20: true,
|
|
@@ -676,7 +676,6 @@ describe("Ledger Service", () => {
|
|
|
676
676
|
domains: [],
|
|
677
677
|
erc20Tokens: [
|
|
678
678
|
"0457455448c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000012000000013045022100b47ee8551c15a2cf681c649651e987d7e527c481d27c38da1f971a8242792bd3022069c3f688ac5493a23dab5798e3c9b07484765069e1d4be14321aae4d92cb8cbe",
|
|
679
|
-
"0457455448c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000012000000013045022100b47ee8551c15a2cf681c649651e987d7e527c481d27c38da1f971a8242792bd3022069c3f688ac5493a23dab5798e3c9b07484765069e1d4be14321aae4d92cb8cbe",
|
|
680
679
|
],
|
|
681
680
|
nfts: [],
|
|
682
681
|
externalPlugin: [
|
|
@@ -689,8 +688,8 @@ describe("Ledger Service", () => {
|
|
|
689
688
|
plugin: [],
|
|
690
689
|
});
|
|
691
690
|
expect(contractServices.loadInfosForContractMethod).toHaveBeenCalledTimes(0);
|
|
692
|
-
expect(erc20Services.findERC20SignaturesInfo).toHaveBeenCalledTimes(
|
|
693
|
-
expect(erc20Services.byContractAddressAndChainId).toHaveBeenCalledTimes(
|
|
691
|
+
expect(erc20Services.findERC20SignaturesInfo).toHaveBeenCalledTimes(2);
|
|
692
|
+
expect(erc20Services.byContractAddressAndChainId).toHaveBeenCalledTimes(2);
|
|
694
693
|
expect(uniswapModule.loadInfosForUniswap).toHaveBeenCalledTimes(1);
|
|
695
694
|
expect(uniswapModule.getCommandsAndTokensFromUniswapCalldata).toHaveBeenCalledTimes(1);
|
|
696
695
|
expect(nftServices.getNFTInfo).not.toHaveBeenCalled();
|
|
@@ -719,7 +718,6 @@ describe("Ledger Service", () => {
|
|
|
719
718
|
domains: [],
|
|
720
719
|
erc20Tokens: [
|
|
721
720
|
"0457455448c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000012000000013045022100b47ee8551c15a2cf681c649651e987d7e527c481d27c38da1f971a8242792bd3022069c3f688ac5493a23dab5798e3c9b07484765069e1d4be14321aae4d92cb8cbe",
|
|
722
|
-
"0457455448c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000012000000013045022100b47ee8551c15a2cf681c649651e987d7e527c481d27c38da1f971a8242792bd3022069c3f688ac5493a23dab5798e3c9b07484765069e1d4be14321aae4d92cb8cbe",
|
|
723
721
|
],
|
|
724
722
|
nfts: [],
|
|
725
723
|
externalPlugin: [
|
|
@@ -732,8 +730,8 @@ describe("Ledger Service", () => {
|
|
|
732
730
|
plugin: [],
|
|
733
731
|
});
|
|
734
732
|
expect(contractServices.loadInfosForContractMethod).toHaveBeenCalledTimes(0);
|
|
735
|
-
expect(erc20Services.findERC20SignaturesInfo).toHaveBeenCalledTimes(
|
|
736
|
-
expect(erc20Services.byContractAddressAndChainId).toHaveBeenCalledTimes(
|
|
733
|
+
expect(erc20Services.findERC20SignaturesInfo).toHaveBeenCalledTimes(2);
|
|
734
|
+
expect(erc20Services.byContractAddressAndChainId).toHaveBeenCalledTimes(2);
|
|
737
735
|
expect(uniswapModule.loadInfosForUniswap).toHaveBeenCalledTimes(1);
|
|
738
736
|
expect(uniswapModule.getCommandsAndTokensFromUniswapCalldata).toHaveBeenCalledTimes(1);
|
|
739
737
|
expect(nftServices.getNFTInfo).not.toHaveBeenCalled();
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import * as rlp from "@ethersproject/rlp";
|
|
3
|
+
import { AddressZero } from "@ethersproject/constants";
|
|
4
|
+
import { BigNumber as EthersBigNumber } from "@ethersproject/bignumber";
|
|
5
|
+
import { type Transaction, serialize as serializeTransaction } from "@ethersproject/transactions";
|
|
6
|
+
import {
|
|
7
|
+
getChainIdAsUint32,
|
|
8
|
+
getParity,
|
|
9
|
+
getV,
|
|
10
|
+
hexBuffer,
|
|
11
|
+
intAsHexBytes,
|
|
12
|
+
maybeHexBuffer,
|
|
13
|
+
mergeResolutions,
|
|
14
|
+
padHexString,
|
|
15
|
+
safeChunkTransaction,
|
|
16
|
+
splitPath,
|
|
17
|
+
} from "../src/utils";
|
|
18
|
+
|
|
19
|
+
const chainIdsToTest = [
|
|
20
|
+
"1", // Always test Ethereum mainnet
|
|
21
|
+
"56", // Binance Smart Chain
|
|
22
|
+
"134", // Polygon
|
|
23
|
+
"109", // just under the limit for the EIP-155 operation to potentially be more than 1 byte
|
|
24
|
+
"110", // floor limit for the EIP-155 operation to be more than 1 byte if v is 1
|
|
25
|
+
"111", // floor limit for the EIP-155 operation to be more than 1 byte even if v is 0
|
|
26
|
+
"10000", // Random high value
|
|
27
|
+
"2716446429837000", // highest chainId known
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
describe("Eth app biding", () => {
|
|
31
|
+
describe("Utils", () => {
|
|
32
|
+
describe("padHexString", () => {
|
|
33
|
+
it("should prevent hex string from being odd length", () => {
|
|
34
|
+
expect(padHexString("123")).toEqual("0123");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("splitPath", () => {
|
|
39
|
+
it("should split derivation path correctly and respect hardened paths", () => {
|
|
40
|
+
expect(splitPath("44'/60'/123/456/789")).toEqual([
|
|
41
|
+
44 + 0x80000000,
|
|
42
|
+
60 + 0x80000000,
|
|
43
|
+
123,
|
|
44
|
+
456,
|
|
45
|
+
789,
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("hexBuffer", () => {
|
|
51
|
+
it("should convert hex string to buffer", () => {
|
|
52
|
+
const buff = Buffer.from("0123", "hex");
|
|
53
|
+
expect(hexBuffer("0x123")).toEqual(buff);
|
|
54
|
+
expect(hexBuffer("123")).toEqual(buff);
|
|
55
|
+
expect(hexBuffer("0123")).toEqual(buff);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("maybeHexBuffer", () => {
|
|
60
|
+
it("should bufferize hex string and return null for empty input", () => {
|
|
61
|
+
expect(maybeHexBuffer("0x123")).toEqual(Buffer.from("0123", "hex"));
|
|
62
|
+
expect(maybeHexBuffer("")).toEqual(null);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("intAsHexBytes", () => {
|
|
67
|
+
it("should convert integer to hex string with correct number of bytes", () => {
|
|
68
|
+
expect(intAsHexBytes(123, 1)).toEqual("7b");
|
|
69
|
+
expect(intAsHexBytes(123, 2)).toEqual("007b");
|
|
70
|
+
expect(intAsHexBytes(123, 4)).toEqual("0000007b");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("mergeResolutions", () => {
|
|
75
|
+
it("should merge resolutions", () => {
|
|
76
|
+
const resolutions1 = {
|
|
77
|
+
nfts: ["nft1", "nft2"],
|
|
78
|
+
erc20Tokens: ["erc20Token1", "erc20Token2"],
|
|
79
|
+
externalPlugin: [{ payload: "payload1", signature: "signature1" }],
|
|
80
|
+
plugin: ["plugin1", "plugin2"],
|
|
81
|
+
domains: [
|
|
82
|
+
{
|
|
83
|
+
registry: "ens" as const,
|
|
84
|
+
domain: "dev.0xkvn.eth",
|
|
85
|
+
address: "0x6cBCD73CD8e8a42844662f0A0e76D7F79Afd933d",
|
|
86
|
+
type: "forward" as const,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
const resolutions2 = {
|
|
91
|
+
nfts: ["nft3", "nft4"],
|
|
92
|
+
erc20Tokens: ["erc20Token3", "erc20Token4"],
|
|
93
|
+
externalPlugin: [{ payload: "payload2", signature: "signature2" }],
|
|
94
|
+
plugin: ["plugin3", "plugin4"],
|
|
95
|
+
domains: [
|
|
96
|
+
{
|
|
97
|
+
registry: "ens" as const,
|
|
98
|
+
domain: "0xkvn.eth",
|
|
99
|
+
address: "0xB0xB0b5B0106D69fE64545A60A68C014f7570D3F861",
|
|
100
|
+
type: "reverse" as const,
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
expect(mergeResolutions([resolutions1, resolutions2])).toEqual({
|
|
105
|
+
nfts: ["nft1", "nft2", "nft3", "nft4"],
|
|
106
|
+
erc20Tokens: ["erc20Token1", "erc20Token2", "erc20Token3", "erc20Token4"],
|
|
107
|
+
externalPlugin: [
|
|
108
|
+
{ payload: "payload1", signature: "signature1" },
|
|
109
|
+
{ payload: "payload2", signature: "signature2" },
|
|
110
|
+
],
|
|
111
|
+
plugin: ["plugin1", "plugin2", "plugin3", "plugin4"],
|
|
112
|
+
domains: [
|
|
113
|
+
{
|
|
114
|
+
registry: "ens",
|
|
115
|
+
domain: "dev.0xkvn.eth",
|
|
116
|
+
address: "0x6cBCD73CD8e8a42844662f0A0e76D7F79Afd933d",
|
|
117
|
+
type: "forward",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
registry: "ens",
|
|
121
|
+
domain: "0xkvn.eth",
|
|
122
|
+
address: "0xB0xB0b5B0106D69fE64545A60A68C014f7570D3F861",
|
|
123
|
+
type: "reverse",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("getParity", () => {
|
|
131
|
+
it("should return the v from the device for typed transactions (EIP-2718)", () => {
|
|
132
|
+
expect(getParity(0, new BigNumber(1), 1)).toEqual(0);
|
|
133
|
+
expect(getParity(1, new BigNumber(1), 1)).toEqual(1);
|
|
134
|
+
expect(getParity(0, new BigNumber(1), 2)).toEqual(0);
|
|
135
|
+
expect(getParity(1, new BigNumber(1), 2)).toEqual(1);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it.each(chainIdsToTest)(
|
|
139
|
+
"should return the v from the device for legacy transactions (EIP-155) with chainId: %s",
|
|
140
|
+
(chainId: string) => {
|
|
141
|
+
const chainIdBN = new BigNumber(chainId);
|
|
142
|
+
const chainIdUint4 = parseInt(
|
|
143
|
+
Buffer.from(padHexString(chainIdBN.toString(16)), "hex")
|
|
144
|
+
.subarray(0, 4)
|
|
145
|
+
.toString("hex"),
|
|
146
|
+
16,
|
|
147
|
+
);
|
|
148
|
+
const chainIdWithEIP155 = chainIdUint4 * 2 + 35;
|
|
149
|
+
|
|
150
|
+
expect([
|
|
151
|
+
getParity(chainIdWithEIP155 % 256, chainIdBN, null),
|
|
152
|
+
getParity((chainIdWithEIP155 + 1) % 256, chainIdBN, null),
|
|
153
|
+
]).toEqual([0, 1]);
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("getChainIdAsUint32", () => {
|
|
159
|
+
it("should return the chainId as a 4 bytes integer", () => {
|
|
160
|
+
expect(getChainIdAsUint32(1)).toEqual(1);
|
|
161
|
+
expect(getChainIdAsUint32(134)).toEqual(134);
|
|
162
|
+
expect(getChainIdAsUint32(new BigNumber(134))).toEqual(134);
|
|
163
|
+
expect(getChainIdAsUint32(new BigNumber(10_000_000_000))).toEqual(39062500);
|
|
164
|
+
expect(getChainIdAsUint32(10_000_000_000)).toEqual(39062500);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("getV", () => {
|
|
169
|
+
it("should return the v value from the device for legacy transactions non providing a chainId", () => {
|
|
170
|
+
expect(getV(27, new BigNumber(0), null)).toEqual((27).toString(16));
|
|
171
|
+
expect(getV(28, new BigNumber(0), null)).toEqual((28).toString(16));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it.each(chainIdsToTest)(
|
|
175
|
+
"should return the v with EIP-155 applied for legacy transactions providing chainId: %s",
|
|
176
|
+
(chainId: string) => {
|
|
177
|
+
const chainIdBN = new BigNumber(chainId);
|
|
178
|
+
const chainIdUint4 = parseInt(
|
|
179
|
+
Buffer.from(padHexString(chainIdBN.toString(16)), "hex")
|
|
180
|
+
.subarray(0, 4)
|
|
181
|
+
.toString("hex"),
|
|
182
|
+
16,
|
|
183
|
+
);
|
|
184
|
+
const chainIdWithEIP155 = chainIdUint4 * 2 + 35;
|
|
185
|
+
const vEven = chainIdWithEIP155 % 256;
|
|
186
|
+
const vOdd = (chainIdWithEIP155 + 1) % 256;
|
|
187
|
+
|
|
188
|
+
expect(getV(vEven, chainIdBN, null)).toEqual(
|
|
189
|
+
padHexString(chainIdBN.multipliedBy(2).plus(35).toString(16)),
|
|
190
|
+
);
|
|
191
|
+
expect(getV(vOdd, chainIdBN, null)).toEqual(
|
|
192
|
+
padHexString(chainIdBN.multipliedBy(2).plus(35).plus(1).toString(16)),
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
it.each(chainIdsToTest)(
|
|
198
|
+
"should return the parity for transactions using EIP-2718 and no matter the chainId: %s",
|
|
199
|
+
(chainId: string) => {
|
|
200
|
+
const chainIdBN = new BigNumber(chainId);
|
|
201
|
+
expect(getV(0, chainIdBN, 1)).toEqual("00");
|
|
202
|
+
expect(getV(1, chainIdBN, 1)).toEqual("01");
|
|
203
|
+
expect(getV(0, chainIdBN, 2)).toEqual("00");
|
|
204
|
+
expect(getV(1, chainIdBN, 2)).toEqual("01");
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
it("should throw an error if the v value is invalid", () => {
|
|
209
|
+
expect(() => getV(26, new BigNumber(10_000), null)).toThrow("Invalid v value");
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("safeChunkTransaction", () => {
|
|
214
|
+
// Derivation of 44'/60'/0'/0'/0
|
|
215
|
+
// 21B
|
|
216
|
+
const derivationPathBuff = Buffer.from("058000002c8000003c800000008000000000000000", "hex");
|
|
217
|
+
|
|
218
|
+
it("should return a single chunk if the transaction is small enough", () => {
|
|
219
|
+
const rawTx: Transaction = {
|
|
220
|
+
to: AddressZero,
|
|
221
|
+
nonce: 0,
|
|
222
|
+
value: EthersBigNumber.from(0),
|
|
223
|
+
gasPrice: EthersBigNumber.from(1),
|
|
224
|
+
gasLimit: EthersBigNumber.from(2),
|
|
225
|
+
data: "0x",
|
|
226
|
+
chainId: 1,
|
|
227
|
+
};
|
|
228
|
+
const serialized = serializeTransaction(rawTx);
|
|
229
|
+
const rlpBuff = Buffer.from(serialized.slice(2), "hex");
|
|
230
|
+
|
|
231
|
+
if (rlpBuff.length + derivationPathBuff.length > 255)
|
|
232
|
+
throw new Error("Transaction too big");
|
|
233
|
+
|
|
234
|
+
const payload = Buffer.concat([derivationPathBuff, rlpBuff]);
|
|
235
|
+
expect(safeChunkTransaction(rlpBuff, derivationPathBuff, rawTx.type)).toEqual([payload]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("should return multiple 255B chunks for typed transactions (EIP-2718)", () => {
|
|
239
|
+
const rawTx: Transaction = {
|
|
240
|
+
to: AddressZero,
|
|
241
|
+
nonce: 0,
|
|
242
|
+
value: EthersBigNumber.from(0),
|
|
243
|
+
gasPrice: EthersBigNumber.from(1),
|
|
244
|
+
gasLimit: EthersBigNumber.from(2),
|
|
245
|
+
data: "0x" + new Array(256).fill("00").join(""),
|
|
246
|
+
chainId: 1,
|
|
247
|
+
type: 1,
|
|
248
|
+
};
|
|
249
|
+
const serialized = serializeTransaction(rawTx);
|
|
250
|
+
const rlpBuff = Buffer.from(serialized.slice(2), "hex");
|
|
251
|
+
|
|
252
|
+
if (rlpBuff.length + derivationPathBuff.length < 255)
|
|
253
|
+
throw new Error("Transaction too small");
|
|
254
|
+
|
|
255
|
+
// Chunk size should be 255B
|
|
256
|
+
const payload = Buffer.concat([derivationPathBuff, rlpBuff]);
|
|
257
|
+
const chunks = safeChunkTransaction(rlpBuff, derivationPathBuff, rawTx.type);
|
|
258
|
+
expect(chunks.length).toEqual(2);
|
|
259
|
+
expect(chunks).toEqual([payload.subarray(0, 255), payload.subarray(255)]);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it("should return multiple variable chunks for legacy transactions to prevent chunking just before the [r,s,v] for a 1 byte chainId", () => {
|
|
263
|
+
const rawTx: Transaction = {
|
|
264
|
+
to: AddressZero,
|
|
265
|
+
nonce: 0,
|
|
266
|
+
value: EthersBigNumber.from(0),
|
|
267
|
+
gasPrice: EthersBigNumber.from(1),
|
|
268
|
+
gasLimit: EthersBigNumber.from(2),
|
|
269
|
+
data: "0x" + new Array(458).fill("00").join(""),
|
|
270
|
+
chainId: 127, // RLP of VRS should be only 3B as this value is <= 0x7f
|
|
271
|
+
type: 0,
|
|
272
|
+
};
|
|
273
|
+
const serialized = serializeTransaction(rawTx);
|
|
274
|
+
const rlpBuff = Buffer.from(serialized.slice(2), "hex");
|
|
275
|
+
|
|
276
|
+
if (rlpBuff.length + derivationPathBuff.length !== 513)
|
|
277
|
+
throw new Error("Transaction not chunking before the [r,s,v]");
|
|
278
|
+
|
|
279
|
+
// Chunk size should be 254B to avoid chunking just before the [r,s,v]
|
|
280
|
+
const payload = Buffer.concat([derivationPathBuff, rlpBuff]);
|
|
281
|
+
const chunks = safeChunkTransaction(rlpBuff, derivationPathBuff, rawTx.type);
|
|
282
|
+
expect(chunks.length).toEqual(3);
|
|
283
|
+
expect(chunks).toEqual([
|
|
284
|
+
payload.subarray(0, 254),
|
|
285
|
+
payload.subarray(254, 508),
|
|
286
|
+
payload.subarray(508),
|
|
287
|
+
]);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Above 6 bytes values, ethers will simply fail parsing/serializing the transaction
|
|
291
|
+
it.each([1, 2, 3, 4, 5, 6])(
|
|
292
|
+
"should return multiple variable chunks for legacy transactions to prevent chunking just before the [r,s,v] for a %s byte(s) chainId",
|
|
293
|
+
(chainIdSizeInBytes: number) => {
|
|
294
|
+
const chainId = new BigNumber("0x" + new Array(chainIdSizeInBytes).fill("81").join(""));
|
|
295
|
+
const encodedVrs = hexBuffer(
|
|
296
|
+
rlp.encode(["0x" + chainId.toString(16), "0x", "0x"]),
|
|
297
|
+
).subarray(1);
|
|
298
|
+
|
|
299
|
+
for (let i = 1; i <= encodedVrs.length; i++) {
|
|
300
|
+
const rawTx: Transaction = {
|
|
301
|
+
to: AddressZero,
|
|
302
|
+
nonce: 0,
|
|
303
|
+
value: EthersBigNumber.from(0),
|
|
304
|
+
gasPrice: EthersBigNumber.from(1),
|
|
305
|
+
gasLimit: EthersBigNumber.from(2),
|
|
306
|
+
data: "0x" + new Array(458 - chainIdSizeInBytes).fill("00").join(""), // This should make a 492B long rlp
|
|
307
|
+
chainId: chainId.toNumber(),
|
|
308
|
+
type: 0,
|
|
309
|
+
};
|
|
310
|
+
const serialized = serializeTransaction(rawTx);
|
|
311
|
+
const rlpBuff = Buffer.from(serialized.slice(2), "hex");
|
|
312
|
+
|
|
313
|
+
if (rlpBuff.length + derivationPathBuff.length !== 513)
|
|
314
|
+
throw new Error("Transaction not chunking before the [r,s,v]");
|
|
315
|
+
|
|
316
|
+
// Just made from observation, don't treat this as a general rule
|
|
317
|
+
const chunkSize =
|
|
318
|
+
chainIdSizeInBytes < 3
|
|
319
|
+
? 255 - chainIdSizeInBytes
|
|
320
|
+
: chainIdSizeInBytes < 5
|
|
321
|
+
? 256 - chainIdSizeInBytes
|
|
322
|
+
: 257 - chainIdSizeInBytes;
|
|
323
|
+
const chunks = safeChunkTransaction(rlpBuff, derivationPathBuff, rawTx.type);
|
|
324
|
+
expect(chunks.length).toEqual(3);
|
|
325
|
+
expect(
|
|
326
|
+
[`0000` + encodedVrs.toString("hex"), `00` + encodedVrs.toString("hex")].includes(
|
|
327
|
+
chunks[2].toString("hex"),
|
|
328
|
+
),
|
|
329
|
+
).toBe(true);
|
|
330
|
+
const payload = Buffer.concat([derivationPathBuff, rlpBuff]);
|
|
331
|
+
expect(safeChunkTransaction(rlpBuff, derivationPathBuff, rawTx.type)).toEqual([
|
|
332
|
+
payload.subarray(0, chunkSize),
|
|
333
|
+
payload.subarray(chunkSize, chunkSize * 2),
|
|
334
|
+
payload.subarray(chunkSize * 2),
|
|
335
|
+
]);
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
});
|