Skip to content

Commit 70ace1a

Browse files
author
Fabrice Bascoulergue
authored
Improve ledger test implementation and documentation (#24)
* Improve ledger test implem and documentation * Use node 14 LTS as base for CICD
1 parent ecd4307 commit 70ace1a

File tree

8 files changed

+558
-55
lines changed

8 files changed

+558
-55
lines changed

.github/workflows/merge.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313

1414
strategy:
1515
matrix:
16-
node-version: [12.x]
16+
node-version: [14.x]
1717

1818
steps:
1919
- name: Checkout code

.github/workflows/pull_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
strategy:
1616
matrix:
17-
node-version: [10.x, 12.x, 14.x, 15.x]
17+
node-version: [14.x]
1818

1919
env:
2020
CLOUDSDK_CORE_PROJECT: dev

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ Directly importing the CosmJS SDK or other cryptographic library should be consi
7272

7373
Do not hesitate to contribute to this repository. This SDK is intended to be a one-stop-shop for all Lum Network javascript implementations and should definitely be improved over time by all its users.
7474

75+
### Unittests
76+
77+
#### All unittests except the ones involving a Ledger device (skipped by default) can be run using the following command
78+
79+
```bash
80+
yarn test
81+
```
82+
83+
#### Ledger unittests
84+
85+
In order to run the unittest involving Ledger devices you need to do the following:
86+
87+
1. Chose which application you want to use for the tests (Cosmos or Lum)
88+
2. Remove the `.skip` from all the tests your want to run in `./tests/ledger.test.ts`
89+
3. Connect a Ledger device and open either the Cosmos application or the Lum application
90+
4. Run `yarn test tests/ledger.test.ts`
91+
5. Follow the instructions on your Ledger device to pass each test that require a user input
92+
7593
## Protocol Buffer Codecs
7694

7795
### Introduction

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"@babel/plugin-transform-runtime": "^7.12.10",
6666
"@babel/preset-env": "^7.8.3",
6767
"@babel/preset-typescript": "^7.8.3",
68+
"@ledgerhq/hw-transport-node-hid": "^6.6.0",
6869
"@types/jest": "^26.0.20",
6970
"@types/ledgerhq__hw-transport-node-hid": "^4.22.2",
7071
"axios": "^0.21.1",

src/client/LumClient.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Uint64 } from '@cosmjs/math';
21
import { Tendermint34Client, StatusResponse } from '@cosmjs/tendermint-rpc';
32
import {
43
QueryClient as StargateQueryClient,
@@ -15,8 +14,7 @@ import {
1514
accountFromAny,
1615
} from '@cosmjs/stargate';
1716

18-
import { BaseAccount } from '../codec/cosmos/auth/v1beta1/auth';
19-
import { LumWallet, LumUtils, LumTypes, LumRegistry } from '..';
17+
import { LumWallet, LumUtils, LumTypes } from '..';
2018
import { BeamExtension, setupBeamExtension as BeamSetupBeamExtension, MintExtension, setupMintExtension as MintSetupExtension } from '../extensions';
2119

2220
export class LumClient {

src/wallet/LumLedgerWallet.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export class LumLedgerWallet extends LumWallet {
1010
cosmosApp: Cosmos;
1111
private hdPath?: string;
1212

13-
constructor(transport: Transport) {
13+
constructor(transport: Transport, scrambleKey = 'CSM') {
1414
super();
15-
this.cosmosApp = new Cosmos(transport, 'CSM'); // TODO: CSM identifier should either be LUM or dynamic depending on our ledger implementation
15+
this.cosmosApp = new Cosmos(transport, scrambleKey);
1616
}
1717

1818
signingMode = (): SignMode => {

tests/ledger.test.ts

Lines changed: 135 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,33 @@
1-
// import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
2-
// import { LumWalletFactory, LumMessages, LumUtils, LumConstants } from '../src';
1+
import axios from 'axios';
2+
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
3+
import { LumWalletFactory, LumMessages, LumUtils, LumConstants, LumWallet } from '../src';
34

45
import { LumClient } from '../src';
56

7+
const requestCoinsIfNeeded = async (clt: LumClient, w: LumWallet, microLumMinAmount?: number) => {
8+
const balance = await clt.getBalance(w.getAddress(), LumConstants.MicroLumDenom);
9+
if (balance && parseInt(balance.amount) > microLumMinAmount) {
10+
return;
11+
}
12+
const res = await axios.get(`https://bridge.testnet.lum.network/faucet/${w.getAddress()}`);
13+
expect(res.status).toEqual(200);
14+
const faucetResult = new Promise((resolve, reject) => {
15+
let it = 0;
16+
const rec = setInterval(async () => {
17+
const balance = await clt.getBalance(w.getAddress(), LumConstants.MicroLumDenom);
18+
if (balance && parseInt(balance.amount) > microLumMinAmount) {
19+
clearInterval(rec);
20+
resolve(true);
21+
} else if (it >= 60) {
22+
clearInterval(rec);
23+
reject();
24+
}
25+
it++;
26+
}, 1000);
27+
});
28+
await expect(faucetResult).resolves.toBeTruthy();
29+
};
30+
631
describe('Ledger', () => {
732
let clt: LumClient;
833

@@ -14,47 +39,117 @@ describe('Ledger', () => {
1439
await expect(clt.disconnect()).resolves.toBeTruthy();
1540
});
1641

17-
it('Manual signature must work', async () => {
42+
// Remove the .skip part of the function to run the ledger tests manually
43+
it.skip('Cosmos App Manual signature must work', async () => {
44+
// Manual testing using ledger device
45+
// Ledger device must be unlocked and Cosmos app opened prior to running those tests
46+
const transport = await TransportNodeHid.create();
47+
const w = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
48+
expect(w).toBeTruthy();
49+
50+
await requestCoinsIfNeeded(clt, w, 1000);
51+
52+
const acc = await clt.getAccount(w.getAddress());
53+
expect(acc).toBeTruthy();
54+
55+
const balance = await clt.getBalance(acc.address, LumConstants.MicroLumDenom);
56+
expect(parseInt(balance.amount)).toBeGreaterThan(0);
57+
58+
const chainId = await clt.getChainId();
59+
const doc = {
60+
accountNumber: acc.accountNumber,
61+
chainId,
62+
fee: {
63+
amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }],
64+
gas: '100000',
65+
},
66+
memo: 'Send LUM using Ledger App',
67+
messages: [LumMessages.BuildMsgSend(w.getAddress(), 'lum1lsagfzrm4gz28he4wunt63sts5xzmczwjttsr9', [{ denom: LumConstants.MicroLumDenom, amount: '1' }])],
68+
signers: [
69+
{
70+
accountNumber: acc.accountNumber,
71+
sequence: acc.sequence,
72+
publicKey: w.getPublicKey(),
73+
},
74+
],
75+
};
76+
const res = await clt.signAndBroadcastTx(w, doc);
77+
expect(LumUtils.broadcastTxCommitSuccess(res)).toBeTruthy();
78+
});
79+
80+
// Remove the .skip part of the function to run the ledger tests manually
81+
it.skip('Cosmos App Signature verification should work', async () => {
1882
// Manual testing using ledger device
1983
// Ledger device must be unlocked and Cosmos app opened prior to running those tests
20-
// const transport = await TransportNodeHid.create();
21-
// const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
22-
// expect(w1).toBeTruthy();
23-
// const acc = await clt.getAccount(w1.getAddress());
24-
// expect(acc).toBeTruthy();
25-
// const balance = await clt.getBalance(acc.address, 'lum');
26-
// expect(parseInt(balance.amount)).toBeGreaterThan(0);
27-
// const chainId = await clt.getChainId();
28-
// const sendMsg = LumMessages.BuildMsgSend(w1.getAddress(), 'lum1lsagfzrm4gz28he4wunt63sts5xzmczwjttsr9', [{ denom: 'lum', amount: '3' }]);
29-
// const fee = {
30-
// amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }],
31-
// gas: '100000',
32-
// };
33-
// const doc = {
34-
// accountNumber: acc.accountNumber,
35-
// chainId,
36-
// fee: fee,
37-
// memo: 'Just a ledger transaction',
38-
// messages: [sendMsg],
39-
// sequence: acc.sequence,
40-
// };
41-
// const res = await clt.signAndBroadcastTx(w1, doc);
42-
// expect(LumUtils.broadcastTxCommitSuccess(res)).toBeTruthy();
84+
const message = 'Lum network is an awesome decentralized protocol';
85+
const transport = await TransportNodeHid.create();
86+
const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
87+
const w2 = await LumWalletFactory.fromMnemonic(LumUtils.generateMnemonic());
88+
const signed = await w1.signMessage(message);
89+
const v1 = await LumUtils.verifySignMsg(signed);
90+
expect(v1).toBeTruthy();
91+
const v2 = await LumUtils.verifySignMsg(Object.assign({}, signed, { msg: 'Wrong message input' }));
92+
expect(v2).toBeFalsy();
93+
const v3 = await LumUtils.verifySignMsg(Object.assign({}, signed, { publicKey: w2.getPublicKey() }));
94+
expect(v3).toBeFalsy();
95+
const v4 = await LumUtils.verifySignMsg(Object.assign({}, signed, { address: w2.getAddress() }));
96+
expect(v4).toBeFalsy();
4397
});
4498

45-
it('Signature verification should work', async () => {
46-
// const message = 'Lum network is an awesome decentralized protocol';
47-
// const transport = await TransportNodeHid.create();
48-
// const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
49-
// const w2 = await LumWalletFactory.fromMnemonic(LumUtils.generateMnemonic());
50-
// const signed = await w1.signMessage(message);
51-
// const v1 = await LumUtils.verifySignMsg(signed);
52-
// expect(v1).toBeTruthy();
53-
// const v2 = await LumUtils.verifySignMsg(Object.assign({}, signed, { msg: 'Wrong message input' }));
54-
// expect(v2).toBeFalsy();
55-
// const v3 = await LumUtils.verifySignMsg(Object.assign({}, signed, { publicKey: w2.getPublicKey() }));
56-
// expect(v3).toBeFalsy();
57-
// const v4 = await LumUtils.verifySignMsg(Object.assign({}, signed, { address: w2.getAddress() }));
58-
// expect(v4).toBeFalsy();
99+
// Remove the .skip part of the function to run the ledger tests manually
100+
it.skip('Lum App Manual signature must work', async () => {
101+
// Manual testing using ledger device
102+
// Ledger device must be unlocked and Lum app opened prior to running those tests
103+
const transport = await TransportNodeHid.create();
104+
const w = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/837'/0'/0/0`, 'lum');
105+
expect(w).toBeTruthy();
106+
107+
await requestCoinsIfNeeded(clt, w, 1000);
108+
109+
const acc = await clt.getAccount(w.getAddress());
110+
expect(acc).toBeTruthy();
111+
112+
const balance = await clt.getBalance(acc.address, LumConstants.MicroLumDenom);
113+
expect(parseInt(balance.amount)).toBeGreaterThan(0);
114+
115+
const chainId = await clt.getChainId();
116+
const doc = {
117+
accountNumber: acc.accountNumber,
118+
chainId,
119+
fee: {
120+
amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }],
121+
gas: '100000',
122+
},
123+
memo: 'Send LUM using Ledger App',
124+
messages: [LumMessages.BuildMsgSend(w.getAddress(), 'lum1lsagfzrm4gz28he4wunt63sts5xzmczwjttsr9', [{ denom: LumConstants.MicroLumDenom, amount: '1' }])],
125+
signers: [
126+
{
127+
accountNumber: acc.accountNumber,
128+
sequence: acc.sequence,
129+
publicKey: w.getPublicKey(),
130+
},
131+
],
132+
};
133+
const res = await clt.signAndBroadcastTx(w, doc);
134+
expect(LumUtils.broadcastTxCommitSuccess(res)).toBeTruthy();
135+
});
136+
137+
// Remove the .skip part of the function to run the ledger tests manually
138+
it.skip('Lum App Signature verification should work', async () => {
139+
// Manual testing using ledger device
140+
// Ledger device must be unlocked and Lum app opened prior to running those tests
141+
const message = 'Lum network is an awesome decentralized protocol';
142+
const transport = await TransportNodeHid.create();
143+
const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/837'/0'/0/0`, 'lum');
144+
const w2 = await LumWalletFactory.fromMnemonic(LumUtils.generateMnemonic());
145+
const signed = await w1.signMessage(message);
146+
const v1 = await LumUtils.verifySignMsg(signed);
147+
expect(v1).toBeTruthy();
148+
const v2 = await LumUtils.verifySignMsg(Object.assign({}, signed, { msg: 'Wrong message input' }));
149+
expect(v2).toBeFalsy();
150+
const v3 = await LumUtils.verifySignMsg(Object.assign({}, signed, { publicKey: w2.getPublicKey() }));
151+
expect(v3).toBeFalsy();
152+
const v4 = await LumUtils.verifySignMsg(Object.assign({}, signed, { address: w2.getAddress() }));
153+
expect(v4).toBeFalsy();
59154
});
60155
});

0 commit comments

Comments
 (0)