Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
node-version: [12.x]
node-version: [14.x]

steps:
- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 15.x]
node-version: [14.x]

env:
CLOUDSDK_CORE_PROJECT: dev
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ Directly importing the CosmJS SDK or other cryptographic library should be consi

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.

### Unittests

#### All unittests except the ones involving a Ledger device (skipped by default) can be run using the following command

```bash
yarn test
```

#### Ledger unittests

In order to run the unittest involving Ledger devices you need to do the following:

1. Chose which application you want to use for the tests (Cosmos or Lum)
2. Remove the `.skip` from all the tests your want to run in `./tests/ledger.test.ts`
3. Connect a Ledger device and open either the Cosmos application or the Lum application
4. Run `yarn test tests/ledger.test.ts`
5. Follow the instructions on your Ledger device to pass each test that require a user input

## Protocol Buffer Codecs

### Introduction
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@ledgerhq/hw-transport-node-hid": "^6.6.0",
"@types/jest": "^26.0.20",
"@types/ledgerhq__hw-transport-node-hid": "^4.22.2",
"axios": "^0.21.1",
Expand Down
4 changes: 1 addition & 3 deletions src/client/LumClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Uint64 } from '@cosmjs/math';
import { Tendermint34Client, StatusResponse } from '@cosmjs/tendermint-rpc';
import {
QueryClient as StargateQueryClient,
Expand All @@ -15,8 +14,7 @@ import {
accountFromAny,
} from '@cosmjs/stargate';

import { BaseAccount } from '../codec/cosmos/auth/v1beta1/auth';
import { LumWallet, LumUtils, LumTypes, LumRegistry } from '..';
import { LumWallet, LumUtils, LumTypes } from '..';
import { BeamExtension, setupBeamExtension as BeamSetupBeamExtension, MintExtension, setupMintExtension as MintSetupExtension } from '../extensions';

export class LumClient {
Expand Down
4 changes: 2 additions & 2 deletions src/wallet/LumLedgerWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export class LumLedgerWallet extends LumWallet {
cosmosApp: Cosmos;
private hdPath?: string;

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

signingMode = (): SignMode => {
Expand Down
175 changes: 135 additions & 40 deletions tests/ledger.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
// import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
// import { LumWalletFactory, LumMessages, LumUtils, LumConstants } from '../src';
import axios from 'axios';
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
import { LumWalletFactory, LumMessages, LumUtils, LumConstants, LumWallet } from '../src';

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

const requestCoinsIfNeeded = async (clt: LumClient, w: LumWallet, microLumMinAmount?: number) => {
const balance = await clt.getBalance(w.getAddress(), LumConstants.MicroLumDenom);
if (balance && parseInt(balance.amount) > microLumMinAmount) {
return;
}
const res = await axios.get(`https://bridge.testnet.lum.network/faucet/${w.getAddress()}`);
expect(res.status).toEqual(200);
const faucetResult = new Promise((resolve, reject) => {
let it = 0;
const rec = setInterval(async () => {
const balance = await clt.getBalance(w.getAddress(), LumConstants.MicroLumDenom);
if (balance && parseInt(balance.amount) > microLumMinAmount) {
clearInterval(rec);
resolve(true);
} else if (it >= 60) {
clearInterval(rec);
reject();
}
it++;
}, 1000);
});
await expect(faucetResult).resolves.toBeTruthy();
};

describe('Ledger', () => {
let clt: LumClient;

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

it('Manual signature must work', async () => {
// Remove the .skip part of the function to run the ledger tests manually
it.skip('Cosmos App Manual signature must work', async () => {
// Manual testing using ledger device
// Ledger device must be unlocked and Cosmos app opened prior to running those tests
const transport = await TransportNodeHid.create();
const w = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
expect(w).toBeTruthy();

await requestCoinsIfNeeded(clt, w, 1000);

const acc = await clt.getAccount(w.getAddress());
expect(acc).toBeTruthy();

const balance = await clt.getBalance(acc.address, LumConstants.MicroLumDenom);
expect(parseInt(balance.amount)).toBeGreaterThan(0);

const chainId = await clt.getChainId();
const doc = {
accountNumber: acc.accountNumber,
chainId,
fee: {
amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }],
gas: '100000',
},
memo: 'Send LUM using Ledger App',
messages: [LumMessages.BuildMsgSend(w.getAddress(), 'lum1lsagfzrm4gz28he4wunt63sts5xzmczwjttsr9', [{ denom: LumConstants.MicroLumDenom, amount: '1' }])],
signers: [
{
accountNumber: acc.accountNumber,
sequence: acc.sequence,
publicKey: w.getPublicKey(),
},
],
};
const res = await clt.signAndBroadcastTx(w, doc);
expect(LumUtils.broadcastTxCommitSuccess(res)).toBeTruthy();
});

// Remove the .skip part of the function to run the ledger tests manually
it.skip('Cosmos App Signature verification should work', async () => {
// Manual testing using ledger device
// Ledger device must be unlocked and Cosmos app opened prior to running those tests
// const transport = await TransportNodeHid.create();
// const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
// expect(w1).toBeTruthy();
// const acc = await clt.getAccount(w1.getAddress());
// expect(acc).toBeTruthy();
// const balance = await clt.getBalance(acc.address, 'lum');
// expect(parseInt(balance.amount)).toBeGreaterThan(0);
// const chainId = await clt.getChainId();
// const sendMsg = LumMessages.BuildMsgSend(w1.getAddress(), 'lum1lsagfzrm4gz28he4wunt63sts5xzmczwjttsr9', [{ denom: 'lum', amount: '3' }]);
// const fee = {
// amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }],
// gas: '100000',
// };
// const doc = {
// accountNumber: acc.accountNumber,
// chainId,
// fee: fee,
// memo: 'Just a ledger transaction',
// messages: [sendMsg],
// sequence: acc.sequence,
// };
// const res = await clt.signAndBroadcastTx(w1, doc);
// expect(LumUtils.broadcastTxCommitSuccess(res)).toBeTruthy();
const message = 'Lum network is an awesome decentralized protocol';
const transport = await TransportNodeHid.create();
const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
const w2 = await LumWalletFactory.fromMnemonic(LumUtils.generateMnemonic());
const signed = await w1.signMessage(message);
const v1 = await LumUtils.verifySignMsg(signed);
expect(v1).toBeTruthy();
const v2 = await LumUtils.verifySignMsg(Object.assign({}, signed, { msg: 'Wrong message input' }));
expect(v2).toBeFalsy();
const v3 = await LumUtils.verifySignMsg(Object.assign({}, signed, { publicKey: w2.getPublicKey() }));
expect(v3).toBeFalsy();
const v4 = await LumUtils.verifySignMsg(Object.assign({}, signed, { address: w2.getAddress() }));
expect(v4).toBeFalsy();
});

it('Signature verification should work', async () => {
// const message = 'Lum network is an awesome decentralized protocol';
// const transport = await TransportNodeHid.create();
// const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/118'/0'/0/0`, 'lum');
// const w2 = await LumWalletFactory.fromMnemonic(LumUtils.generateMnemonic());
// const signed = await w1.signMessage(message);
// const v1 = await LumUtils.verifySignMsg(signed);
// expect(v1).toBeTruthy();
// const v2 = await LumUtils.verifySignMsg(Object.assign({}, signed, { msg: 'Wrong message input' }));
// expect(v2).toBeFalsy();
// const v3 = await LumUtils.verifySignMsg(Object.assign({}, signed, { publicKey: w2.getPublicKey() }));
// expect(v3).toBeFalsy();
// const v4 = await LumUtils.verifySignMsg(Object.assign({}, signed, { address: w2.getAddress() }));
// expect(v4).toBeFalsy();
// Remove the .skip part of the function to run the ledger tests manually
it.skip('Lum App Manual signature must work', async () => {
// Manual testing using ledger device
// Ledger device must be unlocked and Lum app opened prior to running those tests
const transport = await TransportNodeHid.create();
const w = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/837'/0'/0/0`, 'lum');
expect(w).toBeTruthy();

await requestCoinsIfNeeded(clt, w, 1000);

const acc = await clt.getAccount(w.getAddress());
expect(acc).toBeTruthy();

const balance = await clt.getBalance(acc.address, LumConstants.MicroLumDenom);
expect(parseInt(balance.amount)).toBeGreaterThan(0);

const chainId = await clt.getChainId();
const doc = {
accountNumber: acc.accountNumber,
chainId,
fee: {
amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }],
gas: '100000',
},
memo: 'Send LUM using Ledger App',
messages: [LumMessages.BuildMsgSend(w.getAddress(), 'lum1lsagfzrm4gz28he4wunt63sts5xzmczwjttsr9', [{ denom: LumConstants.MicroLumDenom, amount: '1' }])],
signers: [
{
accountNumber: acc.accountNumber,
sequence: acc.sequence,
publicKey: w.getPublicKey(),
},
],
};
const res = await clt.signAndBroadcastTx(w, doc);
expect(LumUtils.broadcastTxCommitSuccess(res)).toBeTruthy();
});

// Remove the .skip part of the function to run the ledger tests manually
it.skip('Lum App Signature verification should work', async () => {
// Manual testing using ledger device
// Ledger device must be unlocked and Lum app opened prior to running those tests
const message = 'Lum network is an awesome decentralized protocol';
const transport = await TransportNodeHid.create();
const w1 = await LumWalletFactory.fromLedgerTransport(transport, `m/44'/837'/0'/0/0`, 'lum');
const w2 = await LumWalletFactory.fromMnemonic(LumUtils.generateMnemonic());
const signed = await w1.signMessage(message);
const v1 = await LumUtils.verifySignMsg(signed);
expect(v1).toBeTruthy();
const v2 = await LumUtils.verifySignMsg(Object.assign({}, signed, { msg: 'Wrong message input' }));
expect(v2).toBeFalsy();
const v3 = await LumUtils.verifySignMsg(Object.assign({}, signed, { publicKey: w2.getPublicKey() }));
expect(v3).toBeFalsy();
const v4 = await LumUtils.verifySignMsg(Object.assign({}, signed, { address: w2.getAddress() }));
expect(v4).toBeFalsy();
});
});
Loading