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

fix(wrw): refactor unsigned sweep flow to change exposed fields depending on isTSS #510

Draft
wants to merge 1 commit 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
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,14 @@

const { maxFeePerGas, maxPriorityFeePerGas, ...rest } =
await updateKeysFromIds(coin, values);
const recoverData = await window.commands.recover(coin, {

Check failure on line 139 in src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx

View workflow job for this annotation

GitHub Actions / test

Argument of type '{ eip1559: { maxFeePerGas: number; maxPriorityFeePerGas: number; } | undefined; replayProtectionOptions: { chain: number; hardfork: "london"; }; bitgoKey: string; ignoreAddressTypes: never[]; ... 7 more ...; isTss: boolean | undefined; }' is not assignable to parameter of type 'RecoverParams & { rootAddress?: string | undefined; gasLimit?: number | undefined; gasPrice?: number | undefined; eip1559?: { maxFeePerGas: number; maxPriorityFeePerGas: number; } | undefined; ... 7 more ...; ethCommonParams?: EvmCcrNonBitgoCoinConfigType | undefined; }'.
...rest,
eip1559: getEip1559Params(coin, maxFeePerGas, maxPriorityFeePerGas),
replayProtectionOptions: {
chain: getEthLikeRecoveryChainId(coin, bitGoEnvironment),
hardfork: 'london',
},
bitgoKey: '',
bitgoKey: values.bitgoKey || '',
ignoreAddressTypes: [],
});
assert(
Expand Down
141 changes: 91 additions & 50 deletions src/containers/BuildUnsignedSweepCoin/EthLikeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,18 @@ import { allCoinMetas } from '~/helpers/config';

const validationSchema = Yup.object({
apiKey: Yup.string().required(),
backupKey: Yup.string().required(),
backupKey: Yup.string().when('isTss', {
is: false,
then: Yup.string().required(),
otherwise: Yup.string().notRequired(),
}),
bitgoKey: Yup.string().when('isTss', {
is: true,
then: Yup.string().required(),
otherwise: Yup.string().notRequired(),
}),
backupKeyId: Yup.string(),
seed: Yup.string(),
gasLimit: Yup.number()
.typeError('Gas limit must be a number')
.integer()
Expand All @@ -16,7 +26,11 @@ const validationSchema = Yup.object({
maxFeePerGas: Yup.number().required(),
maxPriorityFeePerGas: Yup.number().required(),
recoveryDestination: Yup.string().required(),
userKey: Yup.string().required(),
userKey: Yup.string().when('isTss', {
is: false,
then: Yup.string().required(),
otherwise: Yup.string().notRequired(),
}),
userKeyId: Yup.string(),
walletContractAddress: Yup.string().required(),
isTss: Yup.boolean(),
Expand All @@ -39,6 +53,8 @@ export function EthLikeForm({ onSubmit, coinName }: EthLikeFormProps) {
apiKey: '',
backupKey: '',
backupKeyId: '',
bitgoKey: '',
seed: '',
gasLimit: allCoinMetas[coinName]?.defaultGasLimitNum ?? 500000,
maxFeePerGas: 20,
maxPriorityFeePerGas: 10,
Expand All @@ -57,46 +73,79 @@ export function EthLikeForm({ onSubmit, coinName }: EthLikeFormProps) {
<h4 className="tw-text-body tw-font-semibold tw-border-b-0.5 tw-border-solid tw-border-gray-700 tw-mb-4">
Self-managed cold wallet details
</h4>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your user public key, as found on your recovery KeyCard."
Label="User Public Key"
name="userKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your user Key ID, as found on your KeyCard. Most wallets will not have this and you can leave it blank."
Label="User Key ID (optional)"
name="userKeyId"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The backup public key for the wallet, as found on your recovery KeyCard."
Label="Backup Public Key"
name="backupKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your backup Key ID, as found on your KeyCard. Most wallets will not have this and you can leave it blank."
Label="Backup Key ID (optional)"
name="backupKeyId"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The ETH address of the wallet contract. This is also the wallet's base address."
Label="Wallet Contract Address"
name="walletContractAddress"
Width="fill"
/>
</div>
{allCoinMetas[coinName].isTssSupported && (
<div className="tw-mb-4" role="group">
<label>
<Field type="checkbox" name="isTss" />
Is TSS recovery?
</label>
</div>
)}
{formik.values.isTss ? null : (
<div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your user public key, as found on your recovery KeyCard."
Label="User Public Key"
name="userKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your user Key ID, as found on your KeyCard. Most wallets will not have this and you can leave it blank."
Label="User Key ID (optional)"
name="userKeyId"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The backup public key for the wallet, as found on your recovery KeyCard."
Label="Backup Public Key"
name="backupKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your backup Key ID, as found on your KeyCard. Most wallets will not have this and you can leave it blank."
Label="Backup Key ID (optional)"
name="backupKeyId"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The ETH address of the wallet contract. This is also the wallet's base address."
Label="Wallet Contract Address"
name="walletContractAddress"
Width="fill"
/>
</div>
</div>
)}
{formik.values.isTss ? (
<div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your BitGo public key, also known as the common keychain public key."
Label="BitGo Public Key"
name="bitgoKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Your user seed as found on your KeyCard as Key ID. Most wallets will not have this and you can leave it blank."
Label="Seed (optional)"
name="seed"
Width="fill"
/>
</div>
</div>
) : null
}
<div className="tw-mb-4">
<FormikTextfield
HelperText="The address your recovery transaction will send to."
Expand Down Expand Up @@ -143,14 +192,6 @@ export function EthLikeForm({ onSubmit, coinName }: EthLikeFormProps) {
Width="fill"
/>
</div>
{allCoinMetas[coinName].isTssSupported && (
<div className="tw-mb-4" role="group">
<label>
<Field type="checkbox" name="isTss" />
Is TSS recovery?
</label>
</div>
)}
<div className="tw-flex tw-flex-col-reverse sm:tw-justify-between sm:tw-flex-row tw-gap-1 tw-mt-4">
<Button Tag={Link} to="/" Variant="secondary" Width="hug">
Cancel
Expand Down
33 changes: 23 additions & 10 deletions src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,24 @@ export function mapSdkErrorToAlert(message: string): string {

export async function includePubsFor<
TValues extends {
userKey: string;
userKey?: string;
userKeyId?: string;
backupKey: string;
backupKey?: string;
backupKeyId?: string;
bitgoKey?: string;
}
>(coin: string, values: TValues) {
if (!values.userKey && !values.backupKey && !values.bitgoKey) {
throw new Error('No keys provided');
}
const userKey = values.userKey || values.bitgoKey;
const backupKey = values.backupKey || values.bitgoKey;

const userXpub = values.userKeyId
? (
await window.queries.deriveKeyWithSeed(
coin,
values.userKey,
userKey!,
values.userKeyId
)
).key
Expand All @@ -128,7 +134,7 @@ export async function includePubsFor<
? (
await window.queries.deriveKeyWithSeed(
coin,
values.backupKey,
backupKey!,
values.backupKeyId
)
).key
Expand Down Expand Up @@ -183,10 +189,11 @@ export async function isDerivationPath(id: string, description: string) {
}

export type UpdateKeysFromsIdsDefaultParams = {
userKey: string;
userKey?: string;
userKeyId?: string;
backupKeyId?: string;
backupKey: string;
backupKey?: string;
bitgoKey?: string;
}

export async function updateKeysFromIds<
Expand All @@ -196,16 +203,22 @@ export async function updateKeysFromIds<
params: TParams,
): Promise<Omit<TParams, 'userKeyId' | 'backupKeyId'>> {
const { userKeyId, backupKeyId, ...copy } = params;
if (!copy.bitgoKey && !copy.userKey && !copy.backupKey) {
throw new Error('No keys provided');
}
// Either both userKey and backupKey are provided, or only bitgoKey is provided.
const userKey = copy.userKey || copy.bitgoKey;
const backupKey = copy.backupKey || copy.bitgoKey;
const data = [
{
id: userKeyId,
key: copy.userKey,
key: userKey,
description: 'User Key Id',
name: 'userKey',
},
{
id: backupKeyId,
key: copy.backupKey,
key: backupKey,
description: 'Backup Key Id',
name: 'backupKey',
},
Expand All @@ -215,12 +228,12 @@ export async function updateKeysFromIds<
if (item.id) {
if (await isDerivationPath(item.id, item.description)) {
copy[item.name] = await window.queries.deriveKeyByPath(
item.key,
item.key!,
item.id,
);
} else {
copy[item.name] = (
await window.queries.deriveKeyWithSeed(coin, item.key, item.id)
await window.queries.deriveKeyWithSeed(coin, item.key!, item.id)
).key;
}
}
Expand Down
Loading