Skip to content

Commit

Permalink
Fix: support CAL test pub key (#8349)
Browse files Browse the repository at this point in the history
* fix: fix support CALL moonpay sell

* refactor: remove providerDataCache in sell

* test: fix test

* fix: support CAL test in sell

* fix: fix set MOCK_EXCHANGE_TEST_CONFIG

* refactor: remove extra id

* refactor: remove extra change

* fix: remove extra id

* refactor: remove extra change

* chore: remove debugger

* chore: remove extra comment

* fix: add MOCK_EXCHANGE_TEST_PARTNER env variable

* chore: improve CODEOWNER

* fix: fix test

* chore: remove console.log

* chore: remove redundant git owner

* refactor: move env variables and improve tests

* chore: remove console.log

* fix: fix logic

* chore: remove extra export

* Update apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/ExchangeTestPartnerMode.tsx

Co-authored-by: Kevin Le Seigle <[email protected]>

* Update apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/ExchangeTestPartnerMode.tsx

Co-authored-by: Kevin Le Seigle <[email protected]>

* chore: fix lint

---------

Co-authored-by: Kevin Le Seigle <[email protected]>
  • Loading branch information
sarneijim and KVNLS authored Nov 15, 2024
1 parent 8165e1b commit f0a2488
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 78 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ libs/ledger-live-common/src/exchange/ @ledgerhq/p
libs/exchange-module/ @ledgerhq/ptx
libs/wallet-api-acre-module/ @ledgerhq/ptx
libs/ledgerjs/packages/hw-app-exchange/ @ledgerhq/ptx
libs/ledger-live-common/src/cal/partners*.ts @ledgerhq/ptx


# Wallet API team
**/PlatformAppProviderWrapper.tsx @ledgerhq/wallet-api
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useState } from "react";
import { setEnv, getEnv } from "@ledgerhq/live-env";
import Switch from "~/renderer/components/Switch";
import Box from "~/renderer/components/Box";
import { useTranslation } from "react-i18next";
import { SettingsSectionRow } from "../../SettingsSection";

const ExchangeTestPartnerMode = () => {
const { t } = useTranslation();
const [enableExchangeTestPartnerMode, setEnableExchangeDevMode] = useState<boolean>(
getEnv("MOCK_EXCHANGE_TEST_PARTNER"),
);

const handleChangeSwitch = () => {
setEnableExchangeDevMode(!enableExchangeTestPartnerMode);
setEnv("MOCK_EXCHANGE_TEST_PARTNER", !enableExchangeTestPartnerMode);
};

return (
<SettingsSectionRow
title={t("settings.developer.exchangeTestPartnerMode.title")}
desc={t("settings.developer.exchangeTestPartnerMode.desc")}
>
<Box grow horizontal flow={2} alignItems="center">
<Switch isChecked={enableExchangeTestPartnerMode} onChange={handleChangeSwitch} />
</Box>
</SettingsSectionRow>
);
};

export default ExchangeTestPartnerMode;
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import EnableLearnPageStagingUrlToggle from "./EnableLearnPageStagingUrlToggle";
import OnboardingAppInstallDebugButton from "./OnboardingAppInstallDebug";
import EnableStagingNftMetadataServiceToggle from "./EnableStagingNftMetadataServiceToggle";
import ExchangeDeveloperMode from "./ExchangeDeveloperMode";
import ExchangeTestPartnerMode from "./ExchangeTestPartnerMode";
import LottieTester from "../Experimental/LottieTester";
import StorylyTester from "../Experimental/StorylyTester";
import PostOnboardingHubTester from "../Experimental/PostOnboardingHubTester";
Expand Down Expand Up @@ -104,7 +105,7 @@ const Default = () => {
<StorylyTester />
</FeatureToggle>
<ExchangeDeveloperMode />

<ExchangeTestPartnerMode />
<FeatureToggle featureId="lldWalletSync">
<WalletSyncTester />
</FeatureToggle>
Expand Down
5 changes: 4 additions & 1 deletion apps/ledger-live-desktop/static/i18n/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -4138,6 +4138,10 @@
"desc": "Add exchange provider's info",
"placeholder": "Exchange provider's info in CAL format"
},
"exchangeTestPartnerMode": {
"title": "Exchange in Test Partner Mode",
"desc": "Enable use of the partner stage public key"
},
"analyticsConsole": {
"title": "Allow Analytics Console",
"desc": "Display and allow opening analytics console."
Expand Down Expand Up @@ -6616,7 +6620,6 @@
"alreadySync": "I already turned it on",
"learnMore": "How does Ledger Sync work?"
},

"manage": {
"cta": "Manage",
"synchronize": {
Expand Down
5 changes: 5 additions & 0 deletions libs/env/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,11 @@ const envDefinitions = {
parser: boolParser,
desc: "mock the cryptoassets config and test partner (in the context of app-exchange)",
},
MOCK_EXCHANGE_TEST_PARTNER: {
def: false,
parser: boolParser,
desc: "change CAL partner context to test",
},
MOCK_REMOTE_LIVE_MANIFEST: {
def: "",
parser: stringParser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe("getProvidersData", () => {
// Given

// When
const partners = await getProvidersData("swap");
const partners = await getProvidersData({ type: "swap" });

// Then
expect(partners["changelly"]).toEqual({
Expand Down
78 changes: 65 additions & 13 deletions libs/ledger-live-common/src/cal/partners.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ import network from "@ledgerhq/live-network";

jest.mock("@ledgerhq/live-network");

const test = "test" as "prod" | "test";
const prod = "prod" as "prod" | "test";

beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();
});

describe("transformData", () => {
it.each([
[
"prod",
prod,
{
providera: {
name: "ProviderA",
Expand All @@ -34,7 +42,7 @@ describe("transformData", () => {
},
],
[
"test",
test,
{
providera: {
name: "ProviderA",
Expand All @@ -57,11 +65,12 @@ describe("transformData", () => {
},
],
])(
"should transform providers data correctly with %p env",
(env: string, expected: Record<string, ExchangeProvider>) => {
"should transform providers data correctly with %p Ledger signature env",
(ledgerSignatureEnv: "prod" | "test", expected: Record<string, ExchangeProvider>) => {
const providersData = [
{
name: "ProviderA",
partner_id: "providera",
public_key: "1234567890abcdef",
public_key_curve: "secp256k1",
service_app_version: 2,
Expand All @@ -75,6 +84,7 @@ describe("transformData", () => {
},
{
name: "ProviderB",
partner_id: "providerb",
public_key: "abcdef1234567890",
public_key_curve: "secp256r1",
service_app_version: 2,
Expand All @@ -88,7 +98,7 @@ describe("transformData", () => {
},
];

const result = transformData(providersData, env as "prod" | "test");
const result = transformData(providersData, ledgerSignatureEnv);
expect(result).toEqual(expected);
},
);
Expand All @@ -98,15 +108,31 @@ describe("transformData", () => {

const expected: Record<string, ExchangeProvider> = {};

const result = transformData(providersData, "prod");
const result = transformData(providersData);
expect(result).toEqual(expected);
});
});

describe("getProvidersData", () => {
it.each([
[
"prod",
prod,
prod,
{
providera: {
name: "ProviderA",
publicKey: {
curve: "secp256k1",
data: Buffer.from("1234567890abcdef", "hex"),
},
signature: Buffer.from("a1b2c3", "hex"),
version: 2,
} satisfies ExchangeProvider,
},
],
[
prod,
test,
{
providera: {
name: "ProviderA",
Expand All @@ -120,7 +146,23 @@ describe("getProvidersData", () => {
},
],
[
"test",
test,
test,
{
providera: {
name: "ProviderA",
publicKey: {
curve: "secp256k1",
data: Buffer.from("1234567890abcdef", "hex"),
},
signature: Buffer.from("d1e2f3", "hex"),
version: 2,
} satisfies ExchangeProvider,
},
],
[
test,
prod,
{
providera: {
name: "ProviderA",
Expand All @@ -134,11 +176,16 @@ describe("getProvidersData", () => {
},
],
])(
"should fetch and transform providers data with %p signature",
async (env: string, expected: Record<string, ExchangeProvider>) => {
"should fetch and transform providers data with %p Ledger signature env and %p partner signature",
async (
ledgerSignatureEnv: "prod" | "test",
partnerSignatureEnv: "prod" | "test",
expected: Record<string, ExchangeProvider>,
) => {
const mockProvidersData: ProvidersDataResponse = [
{
name: "ProviderA",
partner_id: "providera",
public_key: "1234567890abcdef",
public_key_curve: "secp256k1",
service_app_version: 2,
Expand All @@ -154,13 +201,18 @@ describe("getProvidersData", () => {

(network as jest.Mock).mockResolvedValue({ data: mockProvidersData });

const result = await getProvidersData("swap", env as "prod" | "test");
const result = await getProvidersData({
type: "swap",
ledgerSignatureEnv,
partnerSignatureEnv,
});

expect(network).toHaveBeenCalledWith({
method: "GET",
url: "https://crypto-assets-service.api.ledger.com/v1/partners",
params: {
output: "name,public_key,public_key_curve,service_app_version,descriptor",
env: partnerSignatureEnv,
output: "name,public_key,public_key_curve,service_app_version,descriptor,partner_id,env",
service_name: "swap",
},
});
Expand All @@ -172,6 +224,6 @@ describe("getProvidersData", () => {
it("should handle errors when fetching data", async () => {
(network as jest.Mock).mockRejectedValue(new Error("Network error"));

await expect(getProvidersData("swap")).rejects.toThrow("Network error");
await expect(getProvidersData({ type: "swap" })).rejects.toThrow("Network error");
});
});
25 changes: 16 additions & 9 deletions libs/ledger-live-common/src/cal/partners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type ProvidersDataResponse = {
public_key: string;
public_key_curve: string;
service_app_version: number;
partner_id: string;
descriptor: {
data: string;
signatures: {
Expand All @@ -49,36 +50,42 @@ export type ProvidersDataResponse = {
// Exported for test purpose only
export function transformData(
providersData: ProvidersDataResponse,
env: "prod" | "test",
ledgerSignatureEnv: "prod" | "test" = "prod",
): Record<string, ExchangeProvider> {
const transformed = {};
providersData.forEach(provider => {
const key = provider.name.toLowerCase();
const key = provider.partner_id;
transformed[key] = {
name: provider.name,
publicKey: {
curve: provider.public_key_curve,
data: Buffer.from(provider.public_key, "hex"),
},
version: provider.service_app_version,
signature: Buffer.from(provider.descriptor.signatures[env], "hex"),
signature: Buffer.from(provider.descriptor.signatures[ledgerSignatureEnv], "hex"),
};
});
return transformed;
}

export async function getProvidersData(
type: "swap" | "fund" | "sell",
env: "prod" | "test" = "prod",
): Promise<Record<string, ExchangeProvider>> {
export async function getProvidersData({
type,
partnerSignatureEnv = "prod",
ledgerSignatureEnv = "prod",
}: {
type: "swap" | "fund" | "sell";
partnerSignatureEnv?: "test" | "prod";
ledgerSignatureEnv?: "test" | "prod";
}): Promise<Record<string, ExchangeProvider>> {
const { data: providersData } = await network<ProvidersDataResponse>({
method: "GET",
url: `${CAL_BASE_URL}/v1/partners`,
params: {
output: "name,public_key,public_key_curve,service_app_version,descriptor",
output: "name,public_key,public_key_curve,service_app_version,descriptor,partner_id,env",
service_name: type,
env: partnerSignatureEnv,
},
});

return transformData(providersData, env);
return transformData(providersData, ledgerSignatureEnv);
}
14 changes: 10 additions & 4 deletions libs/ledger-live-common/src/exchange/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,29 @@ export function convertToAppExchangePartnerKey(

export const getProviderConfig = async (
exchangeType: ExchangeTypes,
providerName: string,
provider: string,
): Promise<ExchangeProviderNameAndSignature> => {
if (getEnv("MOCK_EXCHANGE_TEST_CONFIG") && testProvider) {
return testProvider;
}
const ledgerSignatureEnv = getEnv("MOCK_EXCHANGE_TEST_CONFIG") ? "test" : "prod";
const partnerSignatureEnv = getEnv("MOCK_EXCHANGE_TEST_PARTNER") ? "test" : "prod";

switch (exchangeType) {
case ExchangeTypes.Fund:
case ExchangeTypes.FundNg:
return getFundProvider(providerName.toLowerCase());
return getFundProvider(provider.toLowerCase());

case ExchangeTypes.Sell:
case ExchangeTypes.SellNg:
return await getSellProvider(providerName.toLowerCase());
return await getSellProvider({
providerId: provider.toLowerCase(),
ledgerSignatureEnv,
partnerSignatureEnv,
});

default:
throw new Error(`Unknown partner ${providerName} type`);
throw new Error(`Unknown partner ${provider} type`);
}
};

Expand Down
Loading

0 comments on commit f0a2488

Please sign in to comment.