Skip to content

Commit

Permalink
chore: add support arbitrum
Browse files Browse the repository at this point in the history
this change adds support for
arbitrum in WRW

Ticket: WIN-1118
  • Loading branch information
sachushaji committed Nov 28, 2023
1 parent 190b993 commit c39cb95
Show file tree
Hide file tree
Showing 9 changed files with 964 additions and 24 deletions.
3 changes: 3 additions & 0 deletions electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ process.env.PUBLIC = app.isPackaged

/* eslint-disable @typescript-eslint/unbound-method */
import { Atom, Tatom } from '@bitgo/sdk-coin-atom';
import { Arbeth, Tarbeth } from '@bitgo/sdk-coin-arbeth';
import { Bld, Tbld } from '@bitgo/sdk-coin-bld';
import { Coreum, Tcoreum } from '@bitgo/sdk-coin-coreum';
import { Hash, Thash } from '@bitgo/sdk-coin-hash';
Expand Down Expand Up @@ -97,6 +98,8 @@ sdk.register('trx', Trx.createInstance);
sdk.register('ttrx', Ttrx.createInstance);
sdk.register('avaxc', AvaxC.createInstance);
sdk.register('tavaxc', TavaxC.createInstance);
sdk.register('arbeth', Arbeth.createInstance);
sdk.register('tarbeth', Tarbeth.createInstance);
sdk.register('near', Near.createInstance);
sdk.register('tnear', TNear.createInstance);
sdk.register('dot', Dot.createInstance);
Expand Down
511 changes: 492 additions & 19 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
"dependencies": {
"@bitgo/abstract-cosmos": "1.12.0",
"@bitgo/abstract-utxo": "3.22.0",
"@bitgo/sdk-api": "1.28.0",
"@bitgo/sdk-api": "1.29.0",
"@bitgo/sdk-coin-ada": "2.21.0",
"@bitgo/sdk-coin-arbeth": "6.0.0",
"@bitgo/sdk-coin-atom": "3.12.0",
"@bitgo/sdk-coin-avaxc": "2.13.0",
"@bitgo/sdk-coin-bch": "1.5.17",
Expand Down
3 changes: 2 additions & 1 deletion src/components/CryptocurrencyIcon/CryptocurrencyIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import clsx from 'clsx';
export interface CryptocurrencyIconProps {
Name: 'ada' | 'atom' | 'avax' | 'bch' | 'bld' | 'bsv' | 'btc' | 'btg' | 'coreum' | 'dash' | 'doge' | 'dot' | 'eos' | 'eth' | 'hash' | 'injective' | 'ltc' | 'near' | 'osmo' | 'polygon' | 'sei' | 'sol' | 'tia' | 'trx' | 'xec' | 'xlm' | 'xrp' | 'zec' | 'zeta';
Name: 'ada' | 'atom' | 'avax' | 'bch' | 'bld' | 'bsv' | 'btc' | 'btg' | 'coreum' | 'dash' | 'doge' | 'dot' | 'eos' | 'eth' | 'hash' | 'injective' | 'ltc' | 'near' | 'osmo' | 'polygon' | 'sei' | 'sol' | 'tia' | 'trx' | 'xec' | 'xlm' | 'xrp' | 'zec' | 'zeta' | 'arbeth';
Size: 'small' | 'medium' | 'large';
}

Expand All @@ -19,6 +19,7 @@ export interface CryptocurrencyIconProps {
'tw-w-8 tw-h-8': Size === 'large',
})} {...hostProps}><g fill="none"><circle cx="16" cy="16" r="16" fill="#2E3148"/><g transform="translate(6 5)" fill="#FFF"><path d="M10.02.53c-1.295 0-2.345 4.697-2.345 10.49s1.05 10.49 2.345 10.49c1.294 0 2.344-4.697 2.344-10.49S11.314.53 10.02.53zm.162 20.387c-.148.198-.297.05-.297.05-.596-.692-.894-1.975-.894-1.975-1.043-3.357-.795-10.564-.795-10.564.49-5.721 1.382-7.073 1.685-7.373a.185.185 0 01.238-.019c.44.313.81 1.617.81 1.617 1.09 4.048.991 7.848.991 7.848.099 3.308-.546 7.01-.546 7.01-.497 2.814-1.192 3.406-1.192 3.406z"/><path d="M19.118 5.8c-.645-1.124-5.24.303-10.267 3.186-5.027 2.883-8.573 6.13-7.93 7.254.645 1.124 5.241-.303 10.268-3.186 5.027-2.883 8.574-6.131 7.93-7.254zM1.515 16.085c-.246-.03-.19-.234-.19-.234.302-.86 1.266-1.758 1.266-1.758 2.393-2.575 8.769-5.946 8.769-5.946 5.206-2.422 6.823-2.32 7.233-2.208a.185.185 0 01.135.198c-.05.537-1 1.507-1 1.507-2.966 2.961-6.312 4.768-6.312 4.768-2.82 1.732-6.353 3.013-6.353 3.013-2.688.968-3.548.66-3.548.66z"/><path d="M19.095 16.277c.65-1.12-2.887-4.383-7.898-7.288C6.187 6.085 1.593 4.641.944 5.763c-.65 1.123 2.888 4.383 7.9 7.288 5.013 2.904 9.602 4.348 10.251 3.226zM1.375 6.196c-.097-.228.106-.283.106-.283.897-.17 2.157.217 2.157.217 3.427.78 9.538 4.608 9.538 4.608 4.705 3.292 5.427 4.743 5.535 5.154a.185.185 0 01-.103.215c-.49.225-1.805-.11-1.805-.11-4.05-1.086-7.289-3.075-7.289-3.075-2.91-1.57-5.788-3.985-5.788-3.985-2.187-1.842-2.35-2.74-2.35-2.74l-.002-.001z"/><circle cx="9.995" cy="10.995" r="1.234"/><circle cx="15.055" cy="6.256" r="1"/><circle cx="3.306" cy="8.774" r="1"/><circle cx="8.539" cy="17.856" r="1"/></g></g></svg>;
case 'avax':
case 'arbeth':
return <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 32 32" style={{}} xmlSpace="preserve" xmlnsXlink="http://www.w3.org/1999/xlink" className={clsx('tw-inline-flex tw-fill-current', {
'tw-w-4 tw-h-4': Size === 'small',
'tw-w-6 tw-h-6': Size === 'medium',
Expand Down
147 changes: 147 additions & 0 deletions src/containers/BuildUnsignedSweepCoin/ArbitrumForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { Form, FormikHelpers, FormikProvider, useFormik } from 'formik';
import { Link } from 'react-router-dom';
import * as Yup from 'yup';
import { Button, FormikTextfield } from '~/components';

const validationSchema = Yup.object({
apiKey: Yup.string().required(),
backupKey: Yup.string().required(),
backupKeyId: Yup.string(),
gasLimit: Yup.number()
.typeError('Gas limit must be a number')
.integer()
.positive('Gas limit must be a positive integer')
.required(),
gasPrice: Yup.number()
.typeError('Gas price must be a number')
.integer()
.positive('Gas price must be a positive integer')
.required(),
recoveryDestination: Yup.string().required(),
userKey: Yup.string().required(),
userKeyId: Yup.string(),
walletContractAddress: Yup.string().required(),
}).required();

export type ArbitrumFormProps = {
onSubmit: (
values: ArbitrumFormValues,
formikHelpers: FormikHelpers<ArbitrumFormValues>
) => void | Promise<void>;
};

type ArbitrumFormValues = Yup.Asserts<typeof validationSchema>;

export function ArbitrumForm({ onSubmit }: ArbitrumFormProps) {
const formik = useFormik<ArbitrumFormValues>({
onSubmit,
initialValues: {
apiKey: '',
backupKey: '',
backupKeyId: '',
gasLimit: 500000,
gasPrice: 30,
recoveryDestination: '',
userKey: '',
userKeyId: '',
walletContractAddress: '',
},
validationSchema,
});

return (
<FormikProvider value={formik}>
<Form>
<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 hot 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 Arbitrum address of the wallet contract. This is also the wallet's base address."
Label="Wallet Contract Address"
name="walletContractAddress"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The address your recovery transaction will send to."
Label="Destination Address"
name="recoveryDestination"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="An API-Key Token from arbiscan.com required for Arbitrum mainnet recoveries."
Label="API Key"
name="apiKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Gas limit for the Arbitrum transaction. The value should be between 30,000 and 20,000,000. The default is 500,000 units of gas."
Label="Gas limit"
name="gasLimit"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="Gas price for the Arbitrum transaction. The default is 30 Gwei."
Label="Gas Price"
name="gasPrice"
Width="fill"
/>
</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
</Button>
<Button
Variant="primary"
Width="hug"
type="submit"
Disabled={formik.isSubmitting}
disabled={formik.isSubmitting}
>
{formik.isSubmitting ? 'Recovering...' : 'Recover Funds'}
</Button>
</div>
</Form>
</FormikProvider>
);
}
77 changes: 74 additions & 3 deletions src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { SolanaForm } from './SolanaForm';
import { CardanoForm } from './CardanoForm';
import { BackToHomeHelperText } from '~/components/BackToHomeHelperText';
import { buildUnsignedSweepCoins } from '~/helpers/config';
import { ArbitrumForm } from './ArbitrumForm';

function Form() {
const { env, coin } = useParams<'env' | 'coin'>();
Expand Down Expand Up @@ -258,10 +259,80 @@ function Form() {
}}
/>
);
case 'avaxc':
case 'tavaxc':
case 'avaxc':
case 'tavaxc':
return (
<AvalancheCForm
key={coin}
onSubmit={async (values, { setSubmitting }) => {
setAlert(undefined);
setSubmitting(true);
try {
await window.commands.setBitGoEnvironment(
bitGoEnvironment,
coin,
values.apiKey
);
const chainData = await window.queries.getChain(coin);

const recoverData = await window.commands.recover(coin, {
...(await updateKeysFromIds(coin, values)),
gasPrice: toWei(values.gasPrice),
bitgoKey: '',
ignoreAddressTypes: [],
});
assert(
isRecoveryTransaction(recoverData),
'Fully-signed recovery transaction not detected.'
);

const showSaveDialogData = await window.commands.showSaveDialog({
filters: [
{
name: 'Custom File Type',
extensions: ['json'],
},
],
defaultPath: `~/${chainData}-unsigned-sweep-${Date.now()}.json`,
});

if (!showSaveDialogData.filePath) {
throw new Error('No file path selected');
}

await window.commands.writeFile(
showSaveDialogData.filePath,
JSON.stringify(
includePubsInUnsignedSweep
? {
...recoverData,
...(await includePubsFor(coin, values)),
}
: recoverData,
null,
2
),
{ encoding: 'utf-8' }
);

navigate(
`/${bitGoEnvironment}/build-unsigned-sweep/${coin}/success`
);
} catch (err) {
if (err instanceof Error) {
setAlert(err.message);
} else {
console.error(err);
}
setSubmitting(false);
}
}}
/>
);
case 'arbeth':
case 'tarbeth':
return (
<AvalancheCForm
<ArbitrumForm
key={coin}
onSubmit={async (values, { setSubmitting }) => {
setAlert(undefined);
Expand Down
Loading

0 comments on commit c39cb95

Please sign in to comment.