@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
374 lines • 14 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const satstack_1 = require("./satstack");
const bitcoin_1 = __importDefault(require("@ledgerhq/coin-bitcoin/datasets/bitcoin"));
const descriptor_1 = require("@ledgerhq/coin-bitcoin/descriptor");
const live_env_1 = require("@ledgerhq/live-env");
const account_1 = require("../../account");
const currencies_1 = require("../../currencies");
const index_1 = require("@ledgerhq/coin-framework/crypto-assets/index");
(0, currencies_1.setSupportedCurrencies)(["bitcoin"]);
jest.setTimeout(10000);
describe("validateRPCNodeConfig", () => {
test("valid cases", () => {
expect((0, satstack_1.validateRPCNodeConfig)({
host: "192.168.0.1:9999",
username: "user",
password: "pass",
})).toEqual([]);
expect((0, satstack_1.validateRPCNodeConfig)({
host: "192.168.0.1:9999",
username: "user",
password: "pass",
tls: false,
})).toEqual([]);
expect((0, satstack_1.validateRPCNodeConfig)({
host: "192.168.0.1:9999",
username: "user",
password: "pass",
tls: true,
})).toEqual([]);
expect((0, satstack_1.validateRPCNodeConfig)({
host: "ledger.com",
username: "user",
password: "pass",
})).toEqual([]);
});
test("invalid cases", () => {
const errors = (0, satstack_1.validateRPCNodeConfig)({
host: "",
username: "",
password: "",
});
expect(errors.length).toEqual(3);
expect(errors.map(e => e.field).sort()).toEqual(["host", "password", "username"]);
expect(errors.every(e => e.error instanceof Error)).toBe(true);
});
});
describe("isValidHost", () => {
test("invalid", () => {
expect((0, satstack_1.isValidHost)("")).toBe(false);
expect((0, satstack_1.isValidHost)("a b")).toBe(false);
expect((0, satstack_1.isValidHost)("ledger .com")).toBe(false);
});
test("valid", () => {
expect((0, satstack_1.isValidHost)("52.207.220.222/node/btc/")).toBe(true);
expect((0, satstack_1.isValidHost)("ledger.com/foo")).toBe(true);
expect((0, satstack_1.isValidHost)("ledger.com")).toBe(true);
expect((0, satstack_1.isValidHost)("localhost")).toBe(true);
expect((0, satstack_1.isValidHost)("0.0.0.0")).toBe(true);
expect((0, satstack_1.isValidHost)("127.0.0.1")).toBe(true);
expect((0, satstack_1.isValidHost)("192.168.0.1")).toBe(true);
expect((0, satstack_1.isValidHost)("192.168.0.1:8888")).toBe(true);
expect((0, satstack_1.isValidHost)("locahost:8888")).toBe(true);
expect((0, satstack_1.isValidHost)("ledger:8888")).toBe(true);
expect((0, satstack_1.isValidHost)("ledger1:8888")).toBe(true);
expect((0, satstack_1.isValidHost)("ledger-1:8888")).toBe(true);
});
});
const mockConfig = {
host: "localhost",
username: "user",
password: "pass",
};
describe("checkRPCNodeConfig", () => {
beforeAll(() => {
(0, live_env_1.setEnv)("MOCK", "1");
});
afterAll(() => {
(0, live_env_1.setEnv)("MOCK", "");
});
test("default is good", async () => {
await (0, satstack_1.checkRPCNodeConfig)(mockConfig);
});
test("disconnected case", async () => {
(0, satstack_1.setMockStatus)({
type: "node-disconnected",
});
try {
await expect(async () => {
await (0, satstack_1.checkRPCNodeConfig)(mockConfig);
}).rejects.toThrow();
}
finally {
(0, satstack_1.setMockStatus)({
type: "ready",
});
}
});
});
describe("parseSatStackConfig", () => {
test("parse a config with descriptors", () => {
expect((0, satstack_1.parseSatStackConfig)(`{
"accounts": [
{
"external": "pkh([224b6226/44'/0'/0']xpub6BuPWhjLqutPV8SF4RMrrn8c3t7uBZbz4CBbThpbg9GYjqRMncra9mjgSfWSK7uMDz37hhzJ8wvkbDDQQJt6VgwLoszvmPiSBtLA1bPLLSn/0/*)",
"internal": "pkh([224b6226/44'/0'/0']xpub6BuPWhjLqutPV8SF4RMrrn8c3t7uBZbz4CBbThpbg9GYjqRMncra9mjgSfWSK7uMDz37hhzJ8wvkbDDQQJt6VgwLoszvmPiSBtLA1bPLLSn/1/*)"
},
{
"external": "wpkh([d6a9e45e/84'/0'/1']xpub6DEHKg8fgKcb9at2u9Xhjtx4tXGyWqUPQAx2zNCzr41gQRyCqpCn7onSoJU4VS96GXyCtAhhFxErnG2pGVvVexaqF7DEfqGGnGk7Havn7C2/0/*)",
"internal": "wpkh([d6a9e45e/84'/0'/1']xpub6DEHKg8fgKcb9at2u9Xhjtx4tXGyWqUPQAx2zNCzr41gQRyCqpCn7onSoJU4VS96GXyCtAhhFxErnG2pGVvVexaqF7DEfqGGnGk7Havn7C2/1/*)",
"_whatever": 42
}
],
"rpcurl": "localhost",
"rpcuser": "user",
"rpcpass": "pass",
"notls": true,
"_whatever": {"a":"b"}
}`)).toEqual({
accounts: [
{
descriptor: {
external: "pkh([224b6226/44'/0'/0']xpub6BuPWhjLqutPV8SF4RMrrn8c3t7uBZbz4CBbThpbg9GYjqRMncra9mjgSfWSK7uMDz37hhzJ8wvkbDDQQJt6VgwLoszvmPiSBtLA1bPLLSn/0/*)",
internal: "pkh([224b6226/44'/0'/0']xpub6BuPWhjLqutPV8SF4RMrrn8c3t7uBZbz4CBbThpbg9GYjqRMncra9mjgSfWSK7uMDz37hhzJ8wvkbDDQQJt6VgwLoszvmPiSBtLA1bPLLSn/1/*)",
},
extra: {},
},
{
descriptor: {
external: "wpkh([d6a9e45e/84'/0'/1']xpub6DEHKg8fgKcb9at2u9Xhjtx4tXGyWqUPQAx2zNCzr41gQRyCqpCn7onSoJU4VS96GXyCtAhhFxErnG2pGVvVexaqF7DEfqGGnGk7Havn7C2/0/*)",
internal: "wpkh([d6a9e45e/84'/0'/1']xpub6DEHKg8fgKcb9at2u9Xhjtx4tXGyWqUPQAx2zNCzr41gQRyCqpCn7onSoJU4VS96GXyCtAhhFxErnG2pGVvVexaqF7DEfqGGnGk7Havn7C2/1/*)",
},
extra: {
_whatever: 42,
},
},
],
extra: {
_whatever: {
a: "b",
},
},
node: {
host: "localhost",
password: "pass",
tls: false,
username: "user",
},
});
});
test("invalid values", () => {
expect(() => (0, satstack_1.parseSatStackConfig)("")).toThrow();
expect((0, satstack_1.parseSatStackConfig)("{}")).toBeUndefined();
expect((0, satstack_1.parseSatStackConfig)('{"accounts":[]}')).toBeUndefined();
expect((0, satstack_1.parseSatStackConfig)('{"accounts":[],"rpcurl":"localhost","rpcuser":"user"}')).toBeUndefined();
expect((0, satstack_1.parseSatStackConfig)('{"accounts":[],"rpcurl":"localhost","rpcpass":"pass"}')).toBeUndefined();
expect((0, satstack_1.parseSatStackConfig)('{"accounts":[],"rpcuser":"user","rpcpass": "pass"}')).toBeUndefined();
});
});
describe("stringifySatStackConfig", () => {
test("stringify config with accounts", () => {
expect((0, satstack_1.stringifySatStackConfig)({
node: mockConfig,
extra: {
foo: "bar",
},
accounts: (bitcoin_1.default.accounts || [])
.map(a => (0, descriptor_1.inferDescriptorFromAccount)((0, account_1.fromAccountRaw)(a.raw)))
.filter(Boolean).map((descriptor, i) => ({
descriptor,
extra: {
i,
},
})),
})).toEqual(`{
"accounts": [
{
"external": "pkh([224b6226/44'/0'/0']xpub6BuPWhjLqutPV8SF4RMrrn8c3t7uBZbz4CBbThpbg9GYjqRMncra9mjgSfWSK7uMDz37hhzJ8wvkbDDQQJt6VgwLoszvmPiSBtLA1bPLLSn/0/*)",
"internal": "pkh([224b6226/44'/0'/0']xpub6BuPWhjLqutPV8SF4RMrrn8c3t7uBZbz4CBbThpbg9GYjqRMncra9mjgSfWSK7uMDz37hhzJ8wvkbDDQQJt6VgwLoszvmPiSBtLA1bPLLSn/1/*)",
"i": 0
},
{
"external": "wpkh([d6a9e45e/84'/0'/1']xpub6DEHKg8fgKcb9at2u9Xhjtx4tXGyWqUPQAx2zNCzr41gQRyCqpCn7onSoJU4VS96GXyCtAhhFxErnG2pGVvVexaqF7DEfqGGnGk7Havn7C2/0/*)",
"internal": "wpkh([d6a9e45e/84'/0'/1']xpub6DEHKg8fgKcb9at2u9Xhjtx4tXGyWqUPQAx2zNCzr41gQRyCqpCn7onSoJU4VS96GXyCtAhhFxErnG2pGVvVexaqF7DEfqGGnGk7Havn7C2/1/*)",
"i": 1
}
],
"rpcurl": "localhost",
"rpcuser": "user",
"rpcpass": "pass",
"notls": true,
"foo": "bar"
}`);
});
});
describe("editSatStackConfig", () => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
(0, index_1.setCryptoAssetsStore)({
findTokenById: (_) => undefined,
findTokenByAddressInCurrency: (_, __) => undefined,
});
const config = {
node: { ...mockConfig, tls: false },
extra: {
foo: "bar",
},
accounts: (bitcoin_1.default.accounts || [])
.map(a => (0, descriptor_1.inferDescriptorFromAccount)((0, account_1.fromAccountRaw)(a.raw)))
.filter(Boolean)
.map((descriptor, i) => ({
descriptor,
extra: {
i,
},
})),
};
test("restore identity", () => {
expect((0, satstack_1.parseSatStackConfig)((0, satstack_1.stringifySatStackConfig)(config))).toEqual(config);
});
test("update node config", () => {
expect((0, satstack_1.editSatStackConfig)({
...config,
node: {
...config.node,
host: "ledger.com",
password: "update",
},
}, {
node: config.node,
})).toEqual(config);
});
test("append accounts", () => {
expect((0, satstack_1.editSatStackConfig)({ ...config, accounts: config.accounts.slice(0, 1) }, {
accounts: config.accounts.slice(1),
})).toEqual(config);
});
test("dedup accounts", () => {
expect((0, satstack_1.editSatStackConfig)({ ...config, accounts: config.accounts.slice(0, 1) }, {
accounts: config.accounts,
})).toEqual(config);
});
});
describe("isSatStackEnabled", () => {
afterEach(() => {
(0, live_env_1.setEnv)("SATSTACK", false);
});
test("enabled", () => {
(0, live_env_1.setEnv)("SATSTACK", true);
expect((0, satstack_1.isSatStackEnabled)()).toBe(true);
});
test("disabled", () => {
expect((0, satstack_1.isSatStackEnabled)()).toBe(false);
});
});
describe("fetchSatStackStatus", () => {
beforeEach(() => {
(0, live_env_1.setEnv)("MOCK", "1");
(0, satstack_1.setMockStatus)({
type: "ready",
});
});
afterEach(() => {
(0, live_env_1.setEnv)("SATSTACK", false);
(0, live_env_1.setEnv)("MOCK", "");
(0, satstack_1.setMockStatus)({
type: "ready",
});
});
test("disconnected", async () => {
await expect((0, satstack_1.fetchSatStackStatus)()).resolves.toEqual({
type: "satstack-disconnected",
});
});
test("scanning", async () => {
(0, live_env_1.setEnv)("SATSTACK", true);
(0, satstack_1.setMockStatus)({
type: "scanning",
progress: 0.42,
});
await expect((0, satstack_1.fetchSatStackStatus)()).resolves.toEqual({
type: "scanning",
progress: 0.42,
});
});
test("ready", async () => {
(0, live_env_1.setEnv)("SATSTACK", true);
await expect((0, satstack_1.fetchSatStackStatus)()).resolves.toEqual({
type: "ready",
});
});
});
describe("statusObservable", () => {
beforeEach(() => {
(0, live_env_1.setEnv)("MOCK", "1");
(0, satstack_1.setMockStatus)({
type: "ready",
});
});
afterEach(() => {
(0, live_env_1.setEnv)("SATSTACK", false);
(0, live_env_1.setEnv)("MOCK", "");
(0, satstack_1.setMockStatus)({
type: "ready",
});
});
test("events", async () => {
(0, live_env_1.setEnv)("SATSTACK", true);
const stack = [
{
type: "ready",
},
{
type: "node-disconnected",
},
{
type: "node-disconnected",
},
{
type: "satstack-disconnected",
},
{
type: "ready",
},
];
let success;
const p = new Promise(s => {
success = s;
});
let last = {
type: "ready",
};
const u = satstack_1.statusObservable.subscribe(e => {
if (stack.length === 0) {
u.unsubscribe();
success();
}
else {
expect(e).toEqual(last);
(0, satstack_1.setMockStatus)((last = stack.splice(0, 1)[0]));
}
});
await p;
});
});
describe("requiresSatStackReady", () => {
beforeEach(() => {
(0, live_env_1.setEnv)("MOCK", "1");
});
afterEach(() => {
(0, satstack_1.setMockStatus)({
type: "ready",
});
(0, live_env_1.setEnv)("SATSTACK", false);
(0, live_env_1.setEnv)("MOCK", "");
});
test("without satstack", async () => {
await expect((0, satstack_1.requiresSatStackReady)()).resolves.toBe(undefined);
});
test("with satstack", async () => {
(0, live_env_1.setEnv)("SATSTACK", true);
await expect((0, satstack_1.requiresSatStackReady)()).resolves.toBe(undefined);
});
test("with satstack not ready", async () => {
(0, live_env_1.setEnv)("SATSTACK", true);
(0, satstack_1.setMockStatus)({
type: "node-disconnected",
});
await expect((0, satstack_1.requiresSatStackReady)()).rejects.toThrow();
});
});
//# sourceMappingURL=satstack.test.js.map