Skip to content

Commit

Permalink
feat/253 Implement ledger service in Extension (#295)
Browse files Browse the repository at this point in the history
* Implement Ledger service with transfer functionality

Re-enable test

Fix failing test

feat/335 - Approve Bond Tx, Sign bond with Ledger (#336)

* Hook up bond approval and Ledger signing

* Clean up, fix naming

* Add query for public_key

* Hooking up Reveal PK tx to extension

* Put public_key into explicit schema type

* Fix schema order

* Refactor submit calls to include signing

* Fix error on submit public key reveal, clean up logs

* Begin hooking up staking update events

* Fix issue with Reveal PK tx

* Fix Cargo.lock

* Addressing PR feedback
  • Loading branch information
jurevans authored Jul 20, 2023
1 parent a06a331 commit 6d82708
Show file tree
Hide file tree
Showing 97 changed files with 5,285 additions and 681 deletions.
2 changes: 1 addition & 1 deletion apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
"@namada/storage": "0.1.0",
"@namada/types": "0.1.0",
"@namada/utils": "0.1.0",
"@namada/ledger-namada": "0.0.1",
"@cosmjs/encoding": "^0.29.0",
"@ledgerhq/hw-transport": "^6.28.3",
"@ledgerhq/hw-transport-webhid": "^6.27.14",
"@ledgerhq/hw-transport-webusb": "^6.27.14",
"@zondax/ledger-namada": "^0.0.2",
"bignumber.js": "^9.1.1",
"@dao-xyz/borsh": "^5.1.5",
"buffer": "^6.0.3",
Expand Down
22 changes: 20 additions & 2 deletions apps/extension/src/App/Accounts/AccountListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,39 @@ const textToClipboard = (content: string): void => {
navigator.clipboard.writeText(content);
};

const isChild = (type: AccountType, path: Bip44Path): boolean => {
// All PrivateKey accounts are child accounts
if (type === AccountType.PrivateKey) {
return true;
}

if (type === AccountType.Ledger) {
// If this is a Ledger account, a child account is any account
// with a path that isn't the default path (/0'/0/0). This is for display
// purposes only. If the sum of the path components is greater than
// zero, it is a child.
const { account, change, index = 0 } = path;
return account + change + index > 0;
}

return false;
};

const formatDerivationPath = (
isChildAccount: boolean,
{ account, change, index = 0 }: Bip44Path,
type: AccountType
): string =>
isChildAccount
? `/${account}'/${
type === AccountType.PrivateKey ? `${change}/` : ""
type !== AccountType.Mnemonic ? `${change}/` : ""
}${index}`
: "";

const AccountListing = ({ account, parentAlias }: Props): JSX.Element => {
const { address, alias, path, type } = account;
const navigate = useNavigate();
const isChildAccount = type !== AccountType.Mnemonic;
const isChildAccount = isChild(type, path);

return (
<AccountListingContainer>
Expand Down
8 changes: 5 additions & 3 deletions apps/extension/src/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@ export const App: React.FC = () => {
setStatus(Status.Pending);

try {
const parentId = await requester.sendMessage(
const parent = await requester.sendMessage(
Ports.Background,
new GetActiveAccountMsg()
);
const parentAccount = accounts.find((account) => account.id === parentId);
const parentAccount = accounts.find(
(account) => account.id === parent?.id
);
setParentAccount(parentAccount);
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -115,7 +117,7 @@ export const App: React.FC = () => {
},
onFail: () => {
setError("An error occurred connecting to extension");
setStatus(Status.Failed);
setStatus(Status.Completed);
},
},
{ tries: 10, ms: 100 },
Expand Down
49 changes: 18 additions & 31 deletions apps/extension/src/App/Settings/ExtraSettings/ExtraSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import { ExtensionRequester } from "extension";
import { Mode, ExtraSetting } from "./types";
import { ResetPassword } from "./ResetPassword";
import { DeleteAccount } from "./DeleteAccount";
import {
ExtraSettingsContainer,
CloseLink
} from "./ExtraSettings.components";
import { ExtraSettingsContainer, CloseLink } from "./ExtraSettings.components";

/**
* Container for additional settings forms such as the reset password form.
Expand All @@ -17,37 +14,27 @@ const ExtraSettings: React.FC<{
requester: ExtensionRequester;
onClose: () => void;
onDeleteAccount: (id: string) => void;
}> = ({
extraSetting,
requester,
onClose,
onDeleteAccount,
}) => {
}> = ({ extraSetting, requester, onClose, onDeleteAccount }) => {
return (
<ExtraSettingsContainer>
{extraSetting &&
<CloseLink onClick={onClose}>
Close
</CloseLink>}

{
extraSetting === null ? "" :

extraSetting.mode === Mode.ResetPassword ?
<ResetPassword
accountId={extraSetting.accountId}
requester={requester}
/> :

extraSetting.mode === Mode.DeleteAccount ?
<DeleteAccount
accountId={extraSetting.accountId}
requester={requester}
onDeleteAccount={onDeleteAccount}
/> :
{extraSetting && <CloseLink onClick={onClose}>Close</CloseLink>}

{extraSetting === null ? (
""
) : extraSetting.mode === Mode.ResetPassword ? (
<ResetPassword
accountId={extraSetting.accountId}
requester={requester}
/>
) : extraSetting.mode === Mode.DeleteAccount ? (
<DeleteAccount
accountId={extraSetting.accountId}
requester={requester}
onDeleteAccount={onDeleteAccount}
/>
) : (
assertNever(extraSetting.mode)
}
)}
</ExtraSettingsContainer>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ enum Status {
Unsubmitted,
Pending,
Complete,
Failed
};
Failed,
}

export type Props = {
accountId: string,
requester: ExtensionRequester
accountId: string;
requester: ExtensionRequester;
};

const ResetPassword: React.FC<Props> = ({ accountId, requester }) => {
Expand All @@ -42,8 +42,8 @@ const ResetPassword: React.FC<Props> = ({ accountId, requester }) => {

const match = newPassword === confirmNewPassword;
const { feedback } = zxcvbn(newPassword);
const hasFeedback = feedback.warning !== "" ||
feedback.suggestions.length > 0;
const hasFeedback =
feedback.warning !== "" || feedback.suggestions.length > 0;

const shouldDisableSubmit =
status === Status.Pending ||
Expand All @@ -52,7 +52,7 @@ const ResetPassword: React.FC<Props> = ({ accountId, requester }) => {
!match ||
(process.env.NODE_ENV !== "development" && hasFeedback);

const handleSubmit = async () => {
const handleSubmit = async (): Promise<void> => {
setStatus(Status.Pending);

const result = await requester.sendMessage<ResetPasswordMsg>(
Expand Down Expand Up @@ -87,7 +87,7 @@ const ResetPassword: React.FC<Props> = ({ accountId, requester }) => {
<Input
type="password"
value={currentPassword}
onChange={e => setCurrentPassword(e.target.value)}
onChange={(e) => setCurrentPassword(e.target.value)}
/>
</InputContainer>

Expand All @@ -96,52 +96,44 @@ const ResetPassword: React.FC<Props> = ({ accountId, requester }) => {
<Input
type="password"
value={newPassword}
onChange={e => setNewPassword(e.target.value)}
onChange={(e) => setNewPassword(e.target.value)}
/>

<InputFeedback className="warning">
{feedback.warning}
</InputFeedback>

{feedback.suggestions.map((suggestion, i) =>
{feedback.suggestions.map((suggestion, i) => (
<InputFeedback key={i}>{suggestion}</InputFeedback>
)}
))}
</InputContainer>

<InputContainer className="medium">
<Header5>Confirm new password</Header5>
<Input
type="password"
value={confirmNewPassword}
onChange={e => setConfirmNewPassword(e.target.value)}
onChange={(e) => setConfirmNewPassword(e.target.value)}
/>

{!match && (
<InputFeedback>Passwords do not match</InputFeedback>
)}
{!match && <InputFeedback>Passwords do not match</InputFeedback>}
</InputContainer>

{errorMessage && (
<ErrorFeedback>{errorMessage}</ErrorFeedback>
)}
{errorMessage && <ErrorFeedback>{errorMessage}</ErrorFeedback>}

<Button
variant={ButtonVariant.Contained}
onClick={handleSubmit}
disabled={shouldDisableSubmit}
>
{status === Status.Pending ?
"Pending..." :
"Reset password"}
{status === Status.Pending ? "Pending..." : "Reset password"}
</Button>
</>
)}

{status === Status.Complete && (
<p>Complete!</p>
)}
{status === Status.Complete && <p>Complete!</p>}
</>
);
}
};

export default ResetPassword;
4 changes: 2 additions & 2 deletions apps/extension/src/App/Settings/ExtraSettings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
export enum Mode {
ResetPassword = "Reset password",
DeleteAccount = "Delete account",
};
}

export type ExtraSetting = {
mode: Mode;
accountId: string;
}
};
Loading

0 comments on commit 6d82708

Please sign in to comment.