Skip to content

Commit

Permalink
Support for Wallet Test Framework (#3737)
Browse files Browse the repository at this point in the history
Hey!

I'm one of the developers on the [Wallet Test
Framework](https://wtf.allwallet.dev/about/) project. As part of our
grant from the Ethereum Foundation, we've built some integrations with
wallets—Taho included.

This pull request contains the changes we needed to make to automate
your wallet: adding a few `id` attributes, and introducing an attribute
to differentiate between signing and sending a transaction. Neither
myself nor @gaudren are experienced TypeScript developers, so please
forgive any obvious mistakes here.

If you're curious what Taho+WTF looks like:


https://github.com/tahowallet/extension/assets/57262657/303d1df2-6458-440d-8d9e-3abbc302f720

And the glue code that makes this work:
https://github.com/wallet-test-framework/glue-taho

Assuming you folks are on board, we'd like to eventually discuss
integrating WTF with your testing strategy!

Latest build:
[extension-builds-3737](https://github.com/tahowallet/extension/suites/21568125918/artifacts/1339626984)
(as of Tue, 19 Mar 2024 16:33:25 GMT).
  • Loading branch information
Shadowfiend authored Mar 19, 2024
2 parents 4c55ec7 + 2a29b36 commit 4a93eba
Show file tree
Hide file tree
Showing 27 changed files with 115 additions and 17 deletions.
2 changes: 2 additions & 0 deletions background/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export type LegacyEVMTransactionRequest = Pick<
estimatedRollupFee: bigint
estimatedRollupGwei: bigint
nonce?: number
broadcastOnSign: boolean
}

/**
Expand Down Expand Up @@ -219,6 +220,7 @@ export type EIP1559TransactionRequest = Pick<
gasLimit: bigint
chainID: EIP1559Transaction["network"]["chainID"]
nonce?: number
broadcastOnSign: boolean
}

export type TransactionRequest =
Expand Down
16 changes: 14 additions & 2 deletions background/services/chain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,17 @@ export default class ChainService extends BaseService<Events> {
transactionRequest: EnrichedLegacyTransactionRequest
gasEstimationError: string | undefined
}> {
const { from, to, value, gasLimit, input, gasPrice, nonce, annotation } =
partialRequest
const {
from,
to,
value,
gasLimit,
input,
gasPrice,
nonce,
annotation,
broadcastOnSign,
} = partialRequest
// Basic transaction construction based on the provided options, with extra data from the chain service
const transactionRequest: EnrichedLegacyTransactionRequest = {
from,
Expand All @@ -553,6 +562,7 @@ export default class ChainService extends BaseService<Events> {
? await this.estimateL1RollupGasPrice(network)
: 0n,
estimatedRollupFee: 0n,
broadcastOnSign,
}

if (network.chainID === OPTIMISM.chainID) {
Expand Down Expand Up @@ -628,6 +638,7 @@ export default class ChainService extends BaseService<Events> {
maxPriorityFeePerGas,
nonce,
annotation,
broadcastOnSign,
} = partialRequest

// Basic transaction construction based on the provided options, with extra data from the chain service
Expand All @@ -644,6 +655,7 @@ export default class ChainService extends BaseService<Events> {
chainID: network.chainID,
nonce,
annotation,
broadcastOnSign,
}

// Always estimate gas to decide whether the transaction will likely fail.
Expand Down
2 changes: 2 additions & 0 deletions background/services/chain/tests/index.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe("Chain Service", () => {
nonce: 1,
maxPriorityFeePerGas: 1n,
maxFeePerGas: 2n,
broadcastOnSign: true,
}

const stub = sandbox.stub(
Expand Down Expand Up @@ -98,6 +99,7 @@ describe("Chain Service", () => {
network: OPTIMISM,
nonce: 1,
gasPrice: 1_000n,
broadcastOnSign: true,
}

const stub = sandbox.stub(
Expand Down
14 changes: 12 additions & 2 deletions background/services/enrichment/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,15 @@ export type EnrichedEIP1559TransactionSignatureRequest =
from: string
annotation?: TransactionAnnotation
network: EVMNetwork
broadcastOnSign: boolean
}

export type EnrichedLegacyTransactionSignatureRequest =
Partial<LegacyEVMTransactionRequest> & {
from: string
annotation?: TransactionAnnotation
network: EVMNetwork
broadcastOnSign: boolean
}

export type EnrichedEIP1559TransactionRequest = EIP1559TransactionRequest & {
Expand All @@ -121,10 +123,18 @@ export type EnrichedEVMTransactionRequest =
| EnrichedLegacyTransactionRequest

type PartialEIP1559TransactionRequestWithFrom =
Partial<EIP1559TransactionRequest> & { from: string; network: EVMNetwork }
Partial<EIP1559TransactionRequest> & {
from: string
network: EVMNetwork
broadcastOnSign: boolean
}

type PartialLegacyEVMTransactionRequestWithFrom =
Partial<LegacyEVMTransactionRequest> & { from: string; network: EVMNetwork }
Partial<LegacyEVMTransactionRequest> & {
from: string
network: EVMNetwork
broadcastOnSign: boolean
}

export type PartialTransactionRequestWithFrom =
| PartialEIP1559TransactionRequestWithFrom
Expand Down
5 changes: 5 additions & 0 deletions background/services/internal-ethereum-provider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ type Events = ServiceLifecycleEvents & {
Partial<EnrichedEVMTransactionRequest> & {
from: string
network: EVMNetwork
broadcastOnSign: boolean
},
SignedTransaction
>
Expand Down Expand Up @@ -245,6 +246,7 @@ export default class InternalEthereumProviderService extends BaseService<Events>
...(params[0] as JsonRpcTransactionRequest),
},
origin,
true,
).then(async (signed) => {
await this.chainService.broadcastSignedTransaction(signed)
return signed.hash
Expand All @@ -253,6 +255,7 @@ export default class InternalEthereumProviderService extends BaseService<Events>
return this.signTransaction(
params[0] as JsonRpcTransactionRequest,
origin,
false,
).then((signedTransaction) =>
serializeEthersTransaction(
ethersTransactionFromSignedTransaction(signedTransaction),
Expand Down Expand Up @@ -394,6 +397,7 @@ export default class InternalEthereumProviderService extends BaseService<Events>
private async signTransaction(
transactionRequest: JsonRpcTransactionRequest,
origin: string,
broadcastOnSign: boolean,
): Promise<SignedTransaction> {
const annotation =
origin === TAHO_INTERNAL_ORIGIN &&
Expand Down Expand Up @@ -457,6 +461,7 @@ export default class InternalEthereumProviderService extends BaseService<Events>
from,
network: currentNetwork,
annotation,
broadcastOnSign,
},
resolver: resolve,
rejecter: reject,
Expand Down
2 changes: 2 additions & 0 deletions background/tests/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ export const createTransactionRequest = (
gasLimit: 0n,
chainID: "0",
network: ETHEREUM,
broadcastOnSign: true,
...overrides,
})

Expand All @@ -264,6 +265,7 @@ export const createLegacyTransactionRequest = (
to: "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
type: 0,
value: 10000000000000000n,
broadcastOnSign: true,
...overrides,
})

Expand Down
1 change: 1 addition & 0 deletions ui/components/DAppConnection/DAppConnectionInfoBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function DefaultConnectionPopover({ close }: PopoverProps): ReactElement {
>
<section>
<SharedIcon
id="close"
icon="close.svg"
width={12}
aria-label={tShared("close")}
Expand Down
3 changes: 3 additions & 0 deletions ui/components/Shared/SharedAddress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import SharedTooltip from "./SharedTooltip"
import { trimWithEllipsis } from "../../utils/textUtils"

type SharedAddressProps = {
id?: string
address: string
name?: string | undefined
elide: boolean
Expand All @@ -31,6 +32,7 @@ type SharedAddressProps = {
* `nameResolverSystem` prop is ignored.
*/
export default function SharedAddress({
id,
name,
address,
elide,
Expand All @@ -48,6 +50,7 @@ export default function SharedAddress({

return (
<button
id={id}
type="button"
onClick={copyAddress}
title={`Copy to clipboard:\n${address}`}
Expand Down
4 changes: 3 additions & 1 deletion ui/components/Shared/SharedCurrentAccountInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useAreInternalSignersUnlocked } from "../../hooks/signing-hooks"
import SharedAvatar from "./SharedAvatar"

type Props = {
address: string
shortenedAddress: string
name: string | undefined
avatarURL: string | undefined
Expand All @@ -13,6 +14,7 @@ type Props = {
}

export default function SharedCurrentAccountInformation({
address,
shortenedAddress,
name,
avatarURL,
Expand All @@ -23,7 +25,7 @@ export default function SharedCurrentAccountInformation({
const icon = areInternalSignersUnlocked ? "unlock" : "lock"
return (
<div className={classNames("account_info_wrap", { hover: showHoverStyle })}>
<span className="account_info_label ellipsis">
<span title={address} className="account_info_label ellipsis">
{name ?? shortenedAddress}
</span>
<SharedAvatar
Expand Down
13 changes: 11 additions & 2 deletions ui/components/Shared/SharedIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { CSSProperties, ReactElement } from "react"

type Props = {
id?: string
icon: string
width: number
height?: number
Expand All @@ -14,7 +15,14 @@ type Props = {
}

export default function SharedIcon(props: Props): ReactElement {
const { icon, width, height = width, color = "transparent", style } = props
const {
id,
icon,
width,
height = width,
color = "transparent",
style,
} = props

if ("onClick" in props) {
const {
Expand All @@ -27,6 +35,7 @@ export default function SharedIcon(props: Props): ReactElement {

return (
<button
id={id}
className="icon"
type="button"
onClick={onClick}
Expand Down Expand Up @@ -60,7 +69,7 @@ export default function SharedIcon(props: Props): ReactElement {
}

return (
<i className="icon" style={style}>
<i id={id} className="icon" style={style}>
<style jsx>{`
.icon {
display: inline-block;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import SharedCurrentAccountInformation from "../SharedCurrentAccountInformation"
import { renderWithProviders } from "../../../tests/test-utils"

const name = "Name"
const address = "0x208e0000000000000000000000000000000090cd"
const shortenedAddress = "0x208e…090cd"
const keyringId = "lock"
const lock = "lock"
Expand All @@ -14,6 +15,7 @@ describe("SharedCurrentAccountInformation", () => {
const ui = renderWithProviders(
<SharedCurrentAccountInformation
name={name}
address=""
shortenedAddress=""
avatarURL={undefined}
/>,
Expand All @@ -26,6 +28,7 @@ describe("SharedCurrentAccountInformation", () => {
const ui = renderWithProviders(
<SharedCurrentAccountInformation
name={undefined}
address={address}
shortenedAddress={shortenedAddress}
avatarURL={undefined}
/>,
Expand All @@ -38,6 +41,7 @@ describe("SharedCurrentAccountInformation", () => {
const ui = renderWithProviders(
<SharedCurrentAccountInformation
name={name}
address=""
shortenedAddress=""
avatarURL={undefined}
showLockStatus={false}
Expand All @@ -52,6 +56,7 @@ describe("SharedCurrentAccountInformation", () => {
const ui = renderWithProviders(
<SharedCurrentAccountInformation
name={name}
address=""
shortenedAddress=""
avatarURL={undefined}
showLockStatus
Expand All @@ -68,6 +73,7 @@ describe("SharedCurrentAccountInformation", () => {
const ui = renderWithProviders(
<SharedCurrentAccountInformation
name={name}
address=""
shortenedAddress=""
avatarURL={undefined}
showLockStatus
Expand Down
2 changes: 1 addition & 1 deletion ui/components/SignData/EIP191Info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function EIP191Info({
<>
<div className="message">
<div className="message-title">{t("message")}</div>
<div className="light">{`${signingData}`}</div>
<div id="message-content" className="light">{`${signingData}`}</div>
</div>
<div className="message">
<div className="signed">{t("signed")}</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default function ContractInteractionSummary({
t("newlyCreatedContract")
) : (
<SharedAddress
id="recipientAddress"
address={transactionRequest.to}
name={
annotation !== undefined && "contractInfo" in annotation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ export function TransferSummaryBase({
<div className="container">
<div className="label">{t("sendTo")}</div>
<div className="send_to">
<SharedAddress address={recipientAddress} name={recipientName} />
<SharedAddress
id="recipientAddress"
address={recipientAddress}
name={recipientName}
/>
</div>
</div>
<div className="divider" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ export type TransactionSignatureDetailsProps = {
export default function TransactionSignatureDetails({
transactionRequest,
}: TransactionSignatureDetailsProps): ReactElement {
const { annotation } = transactionRequest
const { annotation, broadcastOnSign } = transactionRequest
const annotatedTransactionType = annotation?.type ?? "contract-interaction"

return (
<>
<div className="standard_width">
<div className="standard_width" data-broadcast-on-sign={broadcastOnSign}>
<TransactionSignatureSummary
transactionRequest={transactionRequest}
annotation={annotation}
Expand Down
8 changes: 7 additions & 1 deletion ui/components/Signing/Signer/SignerBaseFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ export default function SignerBaseFrame({
<>
<div className="signature-details">{children}</div>
<footer>
<TransactionButton size="large" type="secondary" onClick={onReject}>
<TransactionButton
id="reject"
size="large"
type="secondary"
onClick={onReject}
>
{t("reject")}
</TransactionButton>

<TransactionButton
id="sign"
type="primaryGreen"
size="large"
onClick={onConfirm}
Expand Down
2 changes: 2 additions & 0 deletions ui/components/Signing/Signer/TransactionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type TransactionButtonProps = SharedButtonProps & {

// TODO: Rename this to signing button
export default function TransactionButton({
id,
type,
size,
isDisabled,
Expand Down Expand Up @@ -93,6 +94,7 @@ export default function TransactionButton({

const renderButton = () => (
<SharedButton
id={id}
type={type}
size={size}
onClick={onClick}
Expand Down
Loading

0 comments on commit 4a93eba

Please sign in to comment.