Skip to content

Commit

Permalink
feat: Add EIP-712 management in prepareMessageToSign (#892)
Browse files Browse the repository at this point in the history
* feat: Add EIP-712 management in prepareMessageToSign

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: remove unused import

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: resolve import issue

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: change expected result of prepareMessage in case of thrown error

Signed-off-by: Stéphane Prohaszka <[email protected]>

* feat: rollback on TypedMessageData properties

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: test with EIP712Message

Signed-off-by: Stéphane Prohaszka <[email protected]>

* feat: add tests

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: move fixtures folder

Signed-off-by: Stéphane Prohaszka <[email protected]>

* feat: update changelog

Signed-off-by: Stéphane Prohaszka <[email protected]>

* chore: change test object name

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: Update preparedMessageType in mobile

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: revert unintended modification

Signed-off-by: Stéphane Prohaszka <[email protected]>

* chore: rename createCryptoCurrency into createFixtureCryptoCurrency to avoid confusion

Signed-off-by: Stéphane Prohaszka <[email protected]>

* chore: extract some code to test it

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: eslint issue

Signed-off-by: Stéphane Prohaszka <[email protected]>

* feat: review feedback

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: review feedback

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: rebase issue with mobile platform player

Signed-off-by: Stéphane Prohaszka <[email protected]>

* chore: revert mobile package modification

Signed-off-by: Stéphane Prohaszka <[email protected]>

* fix: unit test

Signed-off-by: Stéphane Prohaszka <[email protected]>

* feat: simplify a little bit eth signMessage

* fix: PR feedback

Signed-off-by: Stéphane Prohaszka <[email protected]>

Signed-off-by: Stéphane Prohaszka <[email protected]>
  • Loading branch information
sprohaszka-ledger committed Sep 7, 2022
1 parent d9800ac commit d70bb70
Show file tree
Hide file tree
Showing 19 changed files with 505 additions and 141 deletions.
6 changes: 6 additions & 0 deletions .changeset/real-owls-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ledgerhq/live-common": minor
"@ledgerhq/hw-app-eth": patch
---

Add EIP-712 capability when preparing message to sign
30 changes: 13 additions & 17 deletions apps/ledger-live-mobile/src/components/WebPlatformPlayer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import type {
RawPlatformAccount,
} from "@ledgerhq/live-common/platform/rawTypes";
import { getEnv } from "@ledgerhq/live-common/env";
import { getAccountBridge } from "@ledgerhq/live-common/bridge/index";
import {
isTokenAccount,
flattenAccounts,
Expand All @@ -39,8 +38,9 @@ import {
findCryptoCurrencyById,
listAndFilterCurrencies,
} from "@ledgerhq/live-common/currencies/index";
import type { AppManifest } from "@ledgerhq/live-common/platform/types";
import type { Transaction } from "@ledgerhq/live-common/generated/types";
import type { MessageData } from "@ledgerhq/live-common/hw/signMessage/types";
import type { AppManifest } from "@ledgerhq/live-common/platform/types";
import {
broadcastTransactionLogic,
receiveOnAccountLogic,
Expand All @@ -49,7 +49,6 @@ import {
CompleteExchangeUiRequest,
signMessageLogic,
} from "@ledgerhq/live-common/platform/logic";

import { useJSONRPCServer } from "@ledgerhq/live-common/platform/JSONRPCServer";
import { accountToPlatformAccount } from "@ledgerhq/live-common/platform/converters";
import {
Expand All @@ -70,6 +69,7 @@ import UpdateIcon from "../../icons/Update";
import InfoIcon from "../../icons/Info";
import InfoPanel from "./InfoPanel";
import { track } from "../../analytics/segment";
import prepareSignTransaction from "./liveSDKLogic";

const tracking = trackingWrapper(track);

Expand Down Expand Up @@ -297,20 +297,16 @@ const WebPlatformPlayer = ({ manifest, inputs }: Props) => {
{ manifest, accounts, tracking },
accountId,
transaction,
(account: AccountLike, parentAccount: Account | null, { liveTx }) => {
const { recipient, ...txData } = liveTx;

const bridge = getAccountBridge(account, parentAccount);
const t = bridge.createTransaction(account);
const t2 = bridge.updateTransaction(t, {
recipient,
subAccountId: isTokenAccount(account) ? account.id : undefined,
});

const tx = bridge.updateTransaction(t2, {
userGasLimit: txData.gasLimit,
...txData,
});
(
account: AccountLike,
parentAccount: Account | null,
{
liveTx,
}: {
liveTx: Partial<Transaction>;
},
) => {
const tx = prepareSignTransaction(account, parentAccount, liveTx);

return new Promise((resolve, reject) => {
navigation.navigate(NavigatorName.SignTransaction, {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import BigNumber from "bignumber.js";
import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets";
import { Account, TokenAccount } from "@ledgerhq/types-live";
import { PlatformTransaction } from "@ledgerhq/live-common/platform/types";
import { Transaction } from "@ledgerhq/live-common/generated/types";
import prepareSignTransaction from "./liveSDKLogic";

// Fake the support of the test currency
jest.mock("@ledgerhq/live-common/currencies/support", () => ({
isCurrencySupported: () => true,
}));

describe("prepareSignTransaction", () => {
it("returns a Transaction", () => {
// Given
const parentAccount = createAccount("12");
const childAccount = createTokenAccount(
"22",
"ethereumjs:2:ethereum:0x012:",
);
const expectedResult = {
amount: new BigNumber("1000"),
data: Buffer.from([]),
estimatedGasLimit: null,
family: "ethereum",
feeCustomUnit: { code: "Gwei", magnitude: 9, name: "Gwei" },
feesStrategy: "medium",
gasPrice: new BigNumber("700000"),
gasLimit: new BigNumber("1200000"),
userGasLimit: new BigNumber("1200000"),
mode: "send",
networkInfo: null,
nonce: 8,
recipient: "0x0123456",
subAccountId: "ethereumjs:2:ethereum:0x022:",
useAllAmount: false,
};

// When
const result = prepareSignTransaction(
childAccount,
parentAccount,
createEtherumTransaction() as Partial<Transaction>,
);

// Then
expect(result).toEqual(expectedResult);
});
});

// *** UTIL FUNCTIONS ***
function createEtherumTransaction(): PlatformTransaction {
return {
family: "ethereum" as any,
amount: new BigNumber("1000"),
recipient: "0x0123456",
nonce: 8,
data: Buffer.from("Some data...", "hex"),
gasPrice: new BigNumber("700000"),
gasLimit: new BigNumber("1200000"),
};
}

const createCryptoCurrency = (family: string): CryptoCurrency => ({
type: "CryptoCurrency",
id: "testCoinId",
coinType: 8008,
name: "MyCoin",
managerAppName: "MyCoin",
ticker: "MYC",
countervalueTicker: "MYC",
scheme: "mycoin",
color: "#ff0000",
family,
units: [
{
name: "MYC",
code: "MYC",
magnitude: 8,
},
{
name: "SmallestUnit",
code: "SMALLESTUNIT",
magnitude: 0,
},
],
explorerViews: [
{
address: "https://mycoinexplorer.com/account/$address",
tx: "https://mycoinexplorer.com/transaction/$hash",
token: "https://mycoinexplorer.com/token/$contractAddress/?a=$address",
},
],
});

const defaultEthCryptoFamily = createCryptoCurrency("ethereum");
const createAccount = (
id: string,
crypto: CryptoCurrency = defaultEthCryptoFamily,
): Account => ({
type: "Account",
id: `ethereumjs:2:ethereum:0x0${id}:`,
seedIdentifier: "0x01",
derivationMode: "ethM",
index: 0,
freshAddress: "0x01",
freshAddressPath: "44'/60'/0'/0/0",
freshAddresses: [],
name: "Ethereum 1",
starred: false,
used: false,
balance: new BigNumber("51281813126095913"),
spendableBalance: new BigNumber("51281813126095913"),
creationDate: new Date(),
blockHeight: 8168983,
currency: crypto,
unit: {
name: "satoshi",
code: "BTC",
magnitude: 5,
},
operationsCount: 0,
operations: [],
pendingOperations: [],
lastSyncDate: new Date(),
balanceHistoryCache: {
HOUR: {
balances: [],
latestDate: undefined,
},
DAY: {
balances: [],
latestDate: undefined,
},
WEEK: {
balances: [],
latestDate: undefined,
},
},
swapHistory: [],
});

function createTokenAccount(id = "32", parentId = "whatever"): TokenAccount {
return {
type: "TokenAccount",
id: `ethereumjs:2:ethereum:0x0${id}:`,
parentId,
token: createTokenCurrency(),
balance: new BigNumber(0),
spendableBalance: new BigNumber(0),
creationDate: new Date(),
operationsCount: 0,
operations: [],
pendingOperations: [],
starred: false,
balanceHistoryCache: {
WEEK: { latestDate: null, balances: [] },
HOUR: { latestDate: null, balances: [] },
DAY: { latestDate: null, balances: [] },
},
swapHistory: [],
};
}

function createTokenCurrency(): TokenCurrency {
return {
type: "TokenCurrency",
id: "3",
contractAddress: "",
parentCurrency: defaultEthCryptoFamily,
tokenType: "",
// -- CurrencyCommon
name: "",
ticker: "",
units: [],
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { isTokenAccount } from "@ledgerhq/live-common/account/index";
import { getAccountBridge } from "@ledgerhq/live-common/bridge/index";
import { Transaction } from "@ledgerhq/live-common/lib/generated/types";
import { Account, AccountLike, TransactionCommon } from "@ledgerhq/types-live";

export default function prepareSignTransaction(
account: AccountLike,
parentAccount: Account | null,
liveTx: Partial<Transaction>,
): TransactionCommon {
const bridge = getAccountBridge(account, parentAccount);
const t = bridge.createTransaction(account);
const { recipient, ...txData } = liveTx;
const t2 = bridge.updateTransaction(t, {
recipient,
subAccountId: isTokenAccount(account) ? account.id : undefined,
});

return bridge.updateTransaction(t2, {
userGasLimit: txData.gasLimit,
...txData,
});
}
2 changes: 1 addition & 1 deletion libs/ledger-live-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
"@ledgerhq/hw-transport-mocker": "workspace:^",
"@ledgerhq/hw-transport-node-speculos": "workspace:^",
"@ledgerhq/json-bignumber": "^1.1.0",
"@ledgerhq/live-app-sdk": "^0.7.0",
"@ledgerhq/live-app-sdk": "^0.8.1",
"@ledgerhq/logs": "workspace:^",
"@polkadot/types": "8.12.2",
"@polkadot/types-known": "8.12.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Btc from "@ledgerhq/hw-app-btc";
import type { Resolver } from "../../hw/signMessage/types";
import type { SignMessage } from "../../hw/signMessage/types";

const resolver: Resolver = async (transport, { path, message }) => {
const signMessage: SignMessage = async (transport, { path, message }) => {
const btc = new Btc(transport);
const hexMessage = Buffer.from(message).toString("hex");
const result = await btc.signMessageNew(path, hexMessage);
Expand All @@ -16,4 +16,4 @@ const resolver: Resolver = async (transport, { path, message }) => {
};
};

export default resolver;
export default { signMessage };
Loading

0 comments on commit d70bb70

Please sign in to comment.