Skip to content

Commit

Permalink
feat: injective integration (#4583)
Browse files Browse the repository at this point in the history
feat: injective integration
  • Loading branch information
hedi-edelbloute committed Sep 26, 2023
1 parent ef7de22 commit 1de4597
Show file tree
Hide file tree
Showing 41 changed files with 2,367 additions and 717 deletions.
11 changes: 11 additions & 0 deletions .changeset/lemon-taxis-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@ledgerhq/types-cryptoassets": minor
"@ledgerhq/cryptoassets": minor
"@ledgerhq/types-live": minor
"ledger-live-desktop": minor
"live-mobile": minor
"@ledgerhq/live-common": minor
"@ledgerhq/live-cli": minor
---

Integrate injective + gas rework
1 change: 1 addition & 0 deletions apps/cli/src/live-common-setup-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ setSupportedCurrencies([
"stacks",
"telos_evm",
"coreum",
"injective",
]);

for (const k in process.env) setEnvUnsafe(k as EnvName, process.env[k]);
Expand Down
3 changes: 2 additions & 1 deletion apps/ledger-live-desktop/cryptoassets.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- this file is generated by generate-cryptoassets-md.test.ts -->
# Supported crypto assets
## Crypto currencies (135)
## Crypto currencies (136)
| name | ticker | supported on Ledger Live? | ledger id |
|--|--|--|--|
| Algorand | ALGO | YES | algorand |
Expand Down Expand Up @@ -35,6 +35,7 @@
| Flare | FLR | YES | flare |
| Hedera | HBAR | YES | hedera |
| Horizen | ZEN | YES | zencash |
| Injective | INJ | YES | injective |
| Internet Computer | ICP | YES | internet_computer |
| Kava EVM | KAVA | YES | kava_evm |
| Klaytn | KLAY | YES | klaytn |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,5 @@ setSupportedCurrencies([
"stacks",
"telos_evm",
"coreum",
"injective",
]);
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const StepChooseCurrency = ({ currency, setCurrency }: StepProps) => {
const baseGoerli = useFeature("currencyBaseGoerli");
const klaytn = useFeature("currencyKlaytn");
const mock = useEnv("MOCK");
const injective = useFeature("currencyInjective");

const featureFlaggedCurrencies = useMemo(
(): Partial<Record<CryptoCurrencyId, Feature<unknown> | null>> => ({
Expand Down Expand Up @@ -103,6 +104,7 @@ const StepChooseCurrency = ({ currency, setCurrency }: StepProps) => {
base,
base_goerli: baseGoerli,
klaytn,
injective,
}),
[
axelar,
Expand Down Expand Up @@ -138,6 +140,7 @@ const StepChooseCurrency = ({ currency, setCurrency }: StepProps) => {
base,
baseGoerli,
klaytn,
injective,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, memo } from "react";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { accountsSelector } from "~/renderer/reducers/accounts";
import styled, { CSSProperties } from "styled-components";
import styled from "styled-components";
import { Flex, Text, Icon } from "@ledgerhq/react-ui";
import FormattedVal from "~/renderer/components/FormattedVal";
import { setTrackingSource } from "~/renderer/analytics/TrackPage";
Expand Down Expand Up @@ -42,7 +42,7 @@ const EllipsisText = styled(Text)`
type Props = {
currency?: CurrencyData | null;
counterCurrency?: string;
style: CSSProperties;
style: React.CSSProperties;
loading: boolean;
locale: string;
isStarred: boolean;
Expand Down
4 changes: 4 additions & 0 deletions apps/ledger-live-desktop/static/i18n/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -5333,6 +5333,10 @@
"title": "Action rejected",
"description": "User rejected the operation on the device"
},
"ExpertModeRequired": {
"title": "Expert mode required",
"description": "Expert mode needs to be enabled."
},
"TransactionRefusedOnDevice": {
"title": "Operation denied on device",
"description": "Please retry or contact Ledger Support if in doubt"
Expand Down
1 change: 1 addition & 0 deletions apps/ledger-live-mobile/src/live-common-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ setSupportedCurrencies([
"stacks",
"telos_evm",
"coreum",
"injective",
]);

if (Config.VERBOSE) {
Expand Down
4 changes: 4 additions & 0 deletions apps/ledger-live-mobile/src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,10 @@
"title": "Operation canceled on device",
"description": "You rejected the operation on the device."
},
"ExpertModeRequired": {
"title": "Expert mode required",
"description": "Expert mode needs to be enabled."
},
"WebsocketConnectionError": {
"title": "Sorry, connection failed",
"description": "Please try again with a better network connection (websocket error)."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export default function AddAccountsSelectCrypto({ navigation, route }: Props) {
const baseGoerli = useFeature("currencyBaseGoerli");
const klaytn = useFeature("currencyKlaytn");
const mock = useEnv("MOCK");
const injective = useFeature("currencyInjective");
const featureFlaggedCurrencies = useMemo(
(): Partial<Record<CryptoCurrencyId, Feature<unknown> | null>> => ({
axelar,
Expand Down Expand Up @@ -123,6 +124,7 @@ export default function AddAccountsSelectCrypto({ navigation, route }: Props) {
base,
base_goerli: baseGoerli,
klaytn,
injective,
}),
[
axelar,
Expand Down Expand Up @@ -158,6 +160,7 @@ export default function AddAccountsSelectCrypto({ navigation, route }: Props) {
base,
baseGoerli,
klaytn,
injective,
],
);

Expand Down
2 changes: 2 additions & 0 deletions libs/coin-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
"rxjs": "^6.6.7"
},
"devDependencies": {
"@ledgerhq/hw-transport-node-speculos": "workspace:^",
"@ledgerhq/hw-transport-node-speculos-http": "workspace:^",
"@types/invariant": "^2.2.2",
"@types/jest": "^29.2.4",
"@types/lodash": "^4.14.191",
Expand Down
10 changes: 10 additions & 0 deletions libs/coin-framework/src/bot/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
} from "@ledgerhq/types-live";
import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";

import type SpeculosTransportHttp from "@ledgerhq/hw-transport-node-speculos-http";
import type SpeculosTransportWebsocket from "@ledgerhq/hw-transport-node-speculos";
export type SpeculosTransport = SpeculosTransportHttp | SpeculosTransportWebsocket;

// Type coming from live-common/src/load/speculos.ts
export type AppCandidate = {
path: string;
Expand Down Expand Up @@ -146,6 +150,12 @@ export type AppSpec<T extends TransactionCommon> = {
allowEmptyAccounts?: boolean;
// do not keep operations in accounts (Cosmos family case)
skipOperationHistory?: boolean;
// executed when speculos device is created, used for example to enable expert mode on cosmos nano app
onSpeculosDeviceCreated?: (device: {
transport: SpeculosTransport;
id: string;
appPath: string;
}) => Promise<void>;
};
export type SpecReport<T extends TransactionCommon> = {
spec: AppSpec<T>;
Expand Down
2 changes: 1 addition & 1 deletion libs/env/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const envDefinitions = {
desc: "Node endpoint for celo",
},
COSMOS_GAS_AMPLIFIER: {
def: 1.2,
def: 1.5,
parser: intParser,
desc: "Cosmos gas estimate multiplier",
},
Expand Down
8 changes: 3 additions & 5 deletions libs/ledger-live-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,9 @@
"@celo/utils": "^3.0.1",
"@celo/wallet-base": "^3.0.1",
"@celo/wallet-ledger": "^3.0.1",
"@cosmjs/amino": "^0.28.4",
"@cosmjs/crypto": "^0.26.5",
"@cosmjs/launchpad": "^0.26.5",
"@cosmjs/ledger-amino": "^0.26.5",
"@cosmjs/proto-signing": "^0.26.5",
"@cosmjs/crypto": "^0.31.0",
"@cosmjs/stargate": "^0.26.5",
"@cosmjs/amino": "^0.31.1",
"@crypto-org-chain/chain-jslib": "1.1.2",
"@elrondnetwork/erdjs": "11.0.0",
"@elrondnetwork/erdjs-network-providers": "^1.1.2",
Expand Down Expand Up @@ -193,6 +190,7 @@
"@xstate/react": "^1.6.3",
"@zondax/cbor": "v8.1.0-zondax-no-bigint",
"@zondax/izari-filecoin": "^1.2.0",
"@zondax/ledger-cosmos-js": "^3.0.3",
"@zondax/ledger-filecoin": "^0.11.2",
"@zondax/ledger-icp": "^0.7.0",
"@zondax/ledger-stacks": "^1.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ setSupportedCurrencies([
"stacks",
"telos_evm",
"coreum",
"injective",
]);

for (const k in process.env) setEnvUnsafe(k as EnvName, process.env[k]);
Expand Down
6 changes: 6 additions & 0 deletions libs/ledger-live-common/src/bot/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ export async function runWithAppSpec<T extends Transaction>(
try {
device = await createSpeculosDevice(deviceParams);
appReport.appPath = device.appPath;
if (spec.onSpeculosDeviceCreated) {
await spec.onSpeculosDeviceCreated(device);
}
const bridge = getCurrencyBridge(currency);
const syncConfig = {
paginationConfig: {},
Expand Down Expand Up @@ -300,6 +303,9 @@ export async function runWithAppSpec<T extends Transaction>(
);
await releaseSpeculosDevice(device.id);
device = await createSpeculosDevice(deviceParams);
if (spec.onSpeculosDeviceCreated) {
await spec.onSpeculosDeviceCreated(device);
}
}
}
mutationsCount = {};
Expand Down
4 changes: 4 additions & 0 deletions libs/ledger-live-common/src/config/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const defaultConfig = {
lcd: "https://full-node.mainnet-1.coreum.dev:1317",
minGasPrice: 0.1,
},
injective: {
lcd: "https://injective-api.polkachu.com",
minGasPrice: 900000000,
},
} as { [currency: string]: CosmosCurrencyConfig },
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,7 @@ Array [
"stride",
"umee",
"internet_computer",
"injective",
"arbitrum",
"cronos",
"flare",
Expand Down
16 changes: 16 additions & 0 deletions libs/ledger-live-common/src/data/icons/svg/INJ.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 64 additions & 8 deletions libs/ledger-live-common/src/families/cosmos/api/Cosmos.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import network from "@ledgerhq/live-network/network";
import { AxiosResponse } from "axios";
import BigNumber from "bignumber.js";
import cryptoFactory from "../chain/chain";
import { CosmosAPI } from "./Cosmos";
jest.mock("@ledgerhq/live-network/network");
const mockedNetwork = jest.mocked(network);

describe("CosmosApi", () => {
let cosmosApi: CosmosAPI;
Expand All @@ -14,36 +17,89 @@ describe("CosmosApi", () => {
jest.resetAllMocks();
});

describe("getAccount", () => {
it("should return base_account if available", async () => {
mockedNetwork.mockResolvedValue({
data: {
account: {
account_number: 1,
sequence: 0,
pub_key: { key: "k", "@type": "type" },
base_account: {
account_number: 2,
sequence: 42,
pub_key: { key: "k2", "@type": "type2" },
},
},
},
} as AxiosResponse);

const account = await cosmosApi.getAccount("addr");
expect(account.accountNumber).toEqual(2);
expect(account.sequence).toEqual(42);
expect(account.pubKey).toEqual("k2");
expect(account.pubKeyType).toEqual("type2");
});

it("should return account if base_account isn't available", async () => {
mockedNetwork.mockResolvedValue({
data: {
account: { account_number: 1, sequence: 0, pub_key: { key: "k", "@type": "type" } },
},
} as AxiosResponse);

const account = await cosmosApi.getAccount("addr");
expect(account.accountNumber).toEqual(1);
expect(account.sequence).toEqual(0);
expect(account.pubKey).toEqual("k");
expect(account.pubKeyType).toEqual("type");
});

it("should return default sequence value if network fails", async () => {
mockedNetwork.mockImplementation(() => {
throw new Error();
});
const account = await cosmosApi.getAccount("addr");
expect(account.sequence).toEqual(0);
});

it("should return default pubkeytype value if network fails", async () => {
mockedNetwork.mockImplementation(() => {
throw new Error();
});
const account = await cosmosApi.getAccount("addr");
expect(account.pubKeyType).toEqual(cryptoFactory("cosmos").defaultPubKeyType);
});
});

describe("simulate", () => {
it("should return gas used when the network call returns gas used", async () => {
// @ts-expect-error method is mocked
network.mockResolvedValue({
mockedNetwork.mockResolvedValue({
data: {
gas_info: {
gas_used: 42000,
},
},
});
} as AxiosResponse);
const gas = await cosmosApi.simulate([]);
expect(gas).toEqual(new BigNumber(42000));
});

it("should throw an error when the network call does not return gas used", async () => {
// @ts-expect-error method is mocked
network.mockResolvedValue({
mockedNetwork.mockResolvedValue({
data: { gas_info: {} },
});
} as AxiosResponse);
await expect(cosmosApi.simulate([])).rejects.toThrowError();
});

it("should throw an error when the network call fails", async () => {
// @ts-expect-error method is mocked
network.mockImplementation(() => {
mockedNetwork.mockImplementation(() => {
throw new Error();
});
await expect(cosmosApi.simulate([])).rejects.toThrowError();
});
});

describe("getTransactions", () => {
it("should return an empty array when network call fails", async () => {
// @ts-expect-error method is mocked
Expand Down
Loading

0 comments on commit 1de4597

Please sign in to comment.