Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/5.26.0 #1687

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Draft
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
8 changes: 5 additions & 3 deletions .github/workflows/runTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ name: Run Tests
env:
INDEXER_URL: ${{ secrets.INDEXER_URL }}
on: [pull_request]
concurrency:
group: ${{ github.workflow }}
jobs:
test-ci:
name: test
timeout-minutes: 20
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.45.3-jammy
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 21
- run: npm install -g yarn && yarn
- run: npx playwright install --with-deps chromium
- run: yarn setup
- run: yarn build:freighter-api
- run: yarn build:extension
- run: yarn test:ci
- run: yarn test:e2e
3 changes: 0 additions & 3 deletions .husky/e2eTests.sh

This file was deleted.

3 changes: 1 addition & 2 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

bash ./.husky/addTranslations.sh
bash ./.husky/e2eTests.sh
bash ./.husky/addTranslations.sh
29 changes: 28 additions & 1 deletion @shared/api/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const fundAccount = async (publicKey: string): Promise<void> => {
};

export const addAccount = async (
password: string,
password: string = "",
): Promise<{
publicKey: string;
allAccounts: Array<Account>;
Expand Down Expand Up @@ -1496,6 +1496,33 @@ export const simulateTokenTransfer = async (args: {
};
};

export const simulateTransaction = async (args: {
xdr: string;
networkDetails: NetworkDetails;
}) => {
const { xdr, networkDetails } = args;
const options = {
method: "POST",
headers: {
// eslint-disable-next-line @typescript-eslint/naming-convention
"Content-Type": "application/json",
},
body: JSON.stringify({
xdr,
// eslint-disable-next-line @typescript-eslint/naming-convention
network_url: networkDetails.sorobanRpcUrl,
// eslint-disable-next-line @typescript-eslint/naming-convention
network_passphrase: networkDetails.networkPassphrase,
}),
};
const res = await fetch(`${INDEXER_URL}/simulate-tx`, options);
const response = await res.json();
return {
ok: res.ok,
response,
};
};

export const saveIsBlockaidAnnounced = async ({
isBlockaidAnnounced,
}: {
Expand Down
22 changes: 21 additions & 1 deletion extension/e2e-tests/addAsset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test("Adding unverified Soroban token", async ({ page, extensionId }) => {
await expect(page.getByTestId("asset-notification")).toHaveText(
"Not on your listsFreighter uses asset lists to check assets you interact with. You can define your own assets lists in Settings.",
);
await expect(page.getByTestId("ManageAssetCode")).toHaveText("E2E");
await expect(page.getByTestId("ManageAssetCode")).toHaveText("E2E Token");
await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add");
await page.getByTestId("ManageAssetRowButton").click({ force: true });

Expand Down Expand Up @@ -81,3 +81,23 @@ test("Adding Soroban verified token", async ({ page, extensionId }) => {
timeout: 30000,
});
});
test.afterAll(async ({ page, extensionId }) => {
if (
test.info().status !== test.info().expectedStatus &&
test.info().title === "Adding Soroban verified token"
) {
// remove trustline in cleanup if Adding Soroban verified token test failed
test.slow();
await loginToTestAccount({ page, extensionId });

await page.getByText("Manage Assets").click({ force: true });
await page.getByPlaceholder("Enter password").fill(PASSWORD);
await page.getByText("Log In").click({ force: true });

await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click();
await page.getByText("Remove asset").click();
await expect(page.getByTestId("account-view")).toBeVisible({
timeout: 30000,
});
}
});
2 changes: 1 addition & 1 deletion extension/e2e-tests/helpers/test-token.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const TEST_TOKEN_ADDRESS =
"CA5F3Q3KQWGG5J4U6OBCJEFVG4B5JVMHFRGQGMLNZXTEMO7YEO6UYMMD";
"CCP33I36MH3QCJZWLWQYSVSHISOGYDUDW5VFW3F3JW3SWWIAPMP6OWF5";
14 changes: 13 additions & 1 deletion extension/e2e-tests/loadAccount.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures";
import { loginToTestAccount } from "./helpers/login";
import { loginToTestAccount, loginAndFund } from "./helpers/login";

test("Load accounts on standalone network", async ({ page, extensionId }) => {
test.slow();
Expand Down Expand Up @@ -27,3 +27,15 @@ test("Load accounts on standalone network", async ({ page, extensionId }) => {
});
await expect(page.getByTestId("account-assets")).toContainText("XLM");
});
test("Switches account with password prompt", async ({ page, extensionId }) => {
test.slow();
await loginToTestAccount({ page, extensionId });
await expect(page.getByTestId("account-assets")).toContainText("XLM");
await page.getByTestId("AccountHeader__icon-btn").click();
await page.getByText("Account 2").click();

await page.getByTestId("account-options-dropdown").click();
await page.getByText("Manage Assets").click({ force: true });

await expect(page.getByText("Your assets")).toBeVisible();
});
20 changes: 20 additions & 0 deletions extension/e2e-tests/sendPayment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,23 @@ test("Send token payment to C address", async ({ page, extensionId }) => {
await expect(page.getByText("Sent E2E")).toBeVisible();
await expect(page.getByTestId("asset-amount")).toContainText(".001 E2E");
});
test.afterAll(async ({ page, extensionId }) => {
if (
test.info().status !== test.info().expectedStatus &&
test.info().title === "Send SAC to C address"
) {
// remove trustline in cleanup if Send SAC to C address test failed
test.slow();
await loginToTestAccount({ page, extensionId });

await page.getByText("Manage Assets").click({ force: true });
await page.getByPlaceholder("Enter password").fill(PASSWORD);
await page.getByText("Log In").click({ force: true });

await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click();
await page.getByText("Remove asset").click();
await expect(page.getByTestId("account-view")).toBeVisible({
timeout: 30000,
});
}
});
11 changes: 8 additions & 3 deletions extension/src/background/ducks/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ interface UiData {

interface AppData {
privateKey?: string;
password?: string;
password: string;
}

export const sessionSlice = createSlice({
Expand All @@ -72,11 +72,12 @@ export const sessionSlice = createSlice({
reset: () => initialState,
logOut: () => initialState,
setActivePrivateKey: (state, action: { payload: AppData }) => {
const { privateKey = "" } = action.payload;
const { privateKey = "", password = "" } = action.payload;

return {
...state,
privateKey,
password,
};
},
setMigratedMnemonicPhrase: (
Expand All @@ -90,7 +91,11 @@ export const sessionSlice = createSlice({
migratedMnemonicPhrase,
};
},
timeoutAccountAccess: (state) => ({ ...state, privateKey: "" }),
timeoutAccountAccess: (state) => ({
...state,
privateKey: "",
password: "",
}),
updateAllAccountsAccountName: (
state,
action: { payload: { updatedAccountName: string } },
Expand Down
37 changes: 28 additions & 9 deletions extension/src/background/messageListener/popupMessageListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
bipPath: string;
}) => {
const mnemonicPhrase = mnemonicPhraseSelector(sessionStore.getState());
const password = passwordSelector(sessionStore.getState()) || "";
let allAccounts = allAccountsSelector(sessionStore.getState());

const keyId = `${HW_PREFIX}${publicKey}`;
Expand Down Expand Up @@ -245,7 +246,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
);

// an active hw account should not have an active private key
sessionStore.dispatch(setActivePrivateKey({ privateKey: "" }));
sessionStore.dispatch(setActivePrivateKey({ privateKey: "", password }));
};

const _storeAccount = async ({
Expand Down Expand Up @@ -442,7 +443,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {

sessionTimer.startSession();
sessionStore.dispatch(
setActivePrivateKey({ privateKey: keyPair.privateKey }),
setActivePrivateKey({ privateKey: keyPair.privateKey, password }),
);

const currentState = sessionStore.getState();
Expand All @@ -455,7 +456,13 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
};

const addAccount = async () => {
const { password } = request;
let password = request.password;
// in case a password is not provided, let's try using the value saved
// in current session store
if (!password) {
password = passwordSelector(sessionStore.getState()) || "";
}

const mnemonicPhrase = mnemonicPhraseSelector(sessionStore.getState());

if (!mnemonicPhrase) {
Expand Down Expand Up @@ -494,7 +501,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {

sessionTimer.startSession();
sessionStore.dispatch(
setActivePrivateKey({ privateKey: keyPair.privateKey }),
setActivePrivateKey({ privateKey: keyPair.privateKey, password }),
);

const currentState = sessionStore.getState();
Expand Down Expand Up @@ -540,7 +547,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
});

sessionTimer.startSession();
sessionStore.dispatch(setActivePrivateKey({ privateKey }));
sessionStore.dispatch(setActivePrivateKey({ privateKey, password }));

const currentState = sessionStore.getState();

Expand Down Expand Up @@ -572,7 +579,19 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
const { publicKey } = request;
await _activatePublicKey({ publicKey });

sessionStore.dispatch(timeoutAccountAccess());
const password = passwordSelector(sessionStore.getState()) || "";
const keyID = (await localStore.getItem(KEY_ID)) || "";

try {
const wallet = await _unlockKeystore({ keyID, password });
const privateKey = wallet.privateKey;

if (!(await getIsHardwareWalletActive())) {
sessionStore.dispatch(setActivePrivateKey({ privateKey, password }));
}
} catch (e) {
console.error(e);
}

const currentState = sessionStore.getState();

Expand Down Expand Up @@ -850,7 +869,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
// start the timer now that we have active private key
sessionTimer.startSession();
sessionStore.dispatch(
setActivePrivateKey({ privateKey: wallet.getSecret(0) }),
setActivePrivateKey({ privateKey: wallet.getSecret(0), password }),
);
}

Expand Down Expand Up @@ -999,7 +1018,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
sessionTimer.startSession();
if (!(await getIsHardwareWalletActive())) {
sessionStore.dispatch(
setActivePrivateKey({ privateKey: activePrivateKey }),
setActivePrivateKey({ privateKey: activePrivateKey, password }),
);
}

Expand Down Expand Up @@ -1680,7 +1699,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {

sessionTimer.startSession();
sessionStore.dispatch(
setActivePrivateKey({ privateKey: newWallet.getSecret(0) }),
setActivePrivateKey({ privateKey: newWallet.getSecret(0), password }),
);
}

Expand Down
3 changes: 3 additions & 0 deletions extension/src/popup/assets/icon-x-remove.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions extension/src/popup/basics/buttons/RemoveButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Button } from "@stellar/design-system";
import React from "react";

import IconXRemove from "popup/assets/icon-x-remove.svg";

interface RemoveButtonProps {
onClick: () => void;
}

export const RemoveButton = ({ onClick }: RemoveButtonProps) => (
<Button size="md" variant="tertiary" onClick={onClick}>
<img src={IconXRemove} alt="icon x remove" />
</Button>
);
2 changes: 1 addition & 1 deletion extension/src/popup/components/PunycodedDomain/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const PunycodedDomain = ({
className={`PunycodedDomain ${isRow ? "PunycodedDomain--row" : ""}`}
{...props}
>
<div>
<div className="PunycodedDomain__favicon-container">
<img
className="PunycodedDomain__favicon"
src={favicon}
Expand Down
6 changes: 6 additions & 0 deletions extension/src/popup/components/PunycodedDomain/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
margin-bottom: 0;
}

&__favicon-container {
width: 32px;
height: 32px;
overflow: hidden;
}

&__favicon {
width: 2rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const AccountHeader = ({
leftContent={
<div
className="AccountHeader__icon-btn"
data-testid="AccountHeader__icon-btn"
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
>
<AccountListIdenticon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export const AccountListIdenticon = ({
const shortPublicKey = truncatedPublicKey(publicKey);

const handleMakeAccountActive = () => {
if (setLoading) {
// If this account is already active (selected) we don't need to load any
// more stuff, so let's just collapse the dropdown in this case
if (!active && setLoading) {
setLoading(true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
align-items: center;
justify-content: space-between;

&:last-child {
padding-bottom: 4rem;
}

&__info {
color: var(--sds-clr-gray-12);
flex-grow: 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
saveAssetSelectSource,
saveAssetSelectType,
AssetSelectType,
saveAmount,
} from "popup/ducks/transactionSubmission";
import { isContractId } from "popup/helpers/soroban";
import { useIsSwap } from "popup/helpers/useIsSwap";
Expand Down Expand Up @@ -121,6 +122,9 @@ export const PathPayAssetSelect = ({
),
);
dispatch(saveAssetSelectSource(source));
if (source) {
dispatch(saveAmount("0"));
}
navigateTo(ROUTES.manageAssets, isSwap ? "?swap=true" : "");
};

Expand Down
Loading