Skip to content

Commit

Permalink
feat(sui): add sui token support
Browse files Browse the repository at this point in the history
  • Loading branch information
bhavidhingra committed Sep 18, 2024
1 parent 733a00d commit a6ce929
Show file tree
Hide file tree
Showing 11 changed files with 743 additions and 134 deletions.
2 changes: 1 addition & 1 deletion electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import * as ecc from 'tiny-secp256k1';
import { Hbar, Thbar } from '@bitgo/sdk-coin-hbar';
import { Algo, Talgo } from '@bitgo/sdk-coin-algo';
import { EthLikeCoin, TethLikeCoin } from '@bitgo/sdk-coin-ethlike';
import { Sui, Tsui } from '@bitgo/sdk-coin-sui';
import { Sui, Tsui } from '@bitgo-beta/sdk-coin-sui';
import { loadWebAssembly } from '@bitgo/sdk-opensslbytes';

const bip32 = BIP32Factory(ecc);
Expand Down
482 changes: 358 additions & 124 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
}
},
"dependencies": {
"@bitgo-beta/sdk-coin-sui": "^1.4.1-alpha.204",
"@bitgo/abstract-cosmos": "11.0.4",
"@bitgo/abstract-utxo": "8.14.1",
"@bitgo/sdk-opensslbytes": "^2.0.0",
"@bitgo/sdk-api": "1.54.0",
"@bitgo/sdk-coin-ada": "4.2.13",
"@bitgo/sdk-coin-algo": "2.1.33",
Expand Down Expand Up @@ -44,13 +44,13 @@
"@bitgo/sdk-coin-polygon": "21.0.4",
"@bitgo/sdk-coin-sei": "3.0.4",
"@bitgo/sdk-coin-sol": "4.5.1",
"@bitgo/sdk-coin-sui": "5.6.3",
"@bitgo/sdk-coin-tia": "3.0.4",
"@bitgo/sdk-coin-trx": "2.0.35",
"@bitgo/sdk-coin-xlm": "3.2.9",
"@bitgo/sdk-coin-xrp": "2.1.16",
"@bitgo/sdk-coin-zec": "2.0.35",
"@bitgo/sdk-coin-zeta": "3.0.4",
"@bitgo/sdk-opensslbytes": "^2.0.0",
"@bitgo/utxo-lib": "10.3.0",
"@ethereumjs/common": "2.6.5",
"@lottiefiles/react-lottie-player": "3.4.9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import {
import { TronForm } from '~/containers/BuildUnsignedConsolidation/TronForm';
import { TronTokenForm } from '~/containers/BuildUnsignedConsolidation/TronTokenForm';
import { CoinsSelectAutocomplete } from '~/components';
import { buildUnsignedConsolidationCoins } from '~/helpers/config';
import { buildUnsignedConsolidationCoins, tokenParentCoins } from '~/helpers/config';
import { BackToHomeHelperText } from '~/components/BackToHomeHelperText';
import { ConsolidationRecoveryBatch } from '@bitgo/sdk-coin-trx';
import { useAlertBanner } from '~/contexts';
import { GenericEcdsaForm } from '~/containers/BuildUnsignedConsolidation/GenericEcdsaForm';
import { SolForm } from '~/containers/BuildUnsignedConsolidation/SolForm';
import { SolTokenForm } from '~/containers/BuildUnsignedConsolidation/SolTokenForm';
import { SuiTokenForm } from '~/containers/BuildUnsignedConsolidation/SuiTokenForm';

type ConsolidationFormProps = {
coin?: string;
Expand All @@ -25,10 +26,9 @@ type ConsolidationFormProps = {
function isRecoveryConsolidationTransaction(
result: any
): result is ConsolidationRecoveryBatch {
const consolidationRecoveryBatch = result as ConsolidationRecoveryBatch;
return (
consolidationRecoveryBatch &&
consolidationRecoveryBatch.transactions !== undefined
('txRequests' in result && !!result['txRequests']) ||
('transactions' in result && !!result['transactions'])
);
}

Expand Down Expand Up @@ -343,6 +343,59 @@ function ConsolidationForm({ coin, environment }: ConsolidationFormProps) {
console.log(e);
}

setSubmitting(false);
}
}}
/>
);
case 'suiToken':
case 'tsuiToken':
return (
<SuiTokenForm
onSubmit={async (values, { setSubmitting }) => {
setSubmitting(true);
try {
await window.commands.setBitGoEnvironment(environment);
const parentCoin = tokenParentCoins[coin];
const chainData = await window.queries.getChain(parentCoin);
const consolidateData = await window.commands.recoverConsolidations(parentCoin, {
bitgoKey: values.bitgoKey.replace(/\s+/g, ''),
tokenContractAddress: values.packageId,
seed: values.seed,
});

if (consolidateData instanceof Error) {
throw consolidateData;
}

const showSaveDialogData = await window.commands.showSaveDialog({
filters: [
{
name: 'Custom File Type',
extensions: ['json'],
},
],
defaultPath: `~/${chainData}-unsigned-consolidation-${Date.now()}.json`,
});
if (!showSaveDialogData.filePath) {
throw new Error('No file path selected');
}

await window.commands.writeFile(
showSaveDialogData.filePath,
JSON.stringify(consolidateData, null, 2),
{ encoding: 'utf8' }
);
navigate(
`/${environment}/build-unsigned-consolidation/${coin}/success`
);
} catch (e) {
if (e instanceof Error) {
setAlert(e.message);
} else {
console.log(e);
}

setSubmitting(false);
}
}}
Expand Down
136 changes: 136 additions & 0 deletions src/containers/BuildUnsignedConsolidation/SuiTokenForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { Form, FormikHelpers, FormikProvider, useFormik } from 'formik';
import { Link } from 'react-router-dom';
import * as Yup from 'yup';
import {
Button,
FormikPasswordfield,
FormikTextarea,
FormikTextfield,
} from '~/components';

const validationSchema = Yup.object({
userKey: Yup.string(),
backupKey: Yup.string(),
bitgoKey: Yup.string().required(),
packageId: Yup.string().required(),
walletPassphrase: Yup.string(),
startingScanIndex: Yup.number(),
endingScanIndex: Yup.number().moreThan(
Yup.ref('startingScanIndex'),
'Ending scan index must be greater than starting scan index'
),
seed: Yup.string(),
}).required();

export type SuiFormValues = Yup.Asserts<typeof validationSchema>;

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

export function SuiTokenForm({ onSubmit }: SuiTokenFormValues) {
const formik = useFormik<SuiFormValues>({
onSubmit,
initialValues: {
userKey: '',
backupKey: '',
bitgoKey: '',
packageId: '',
walletPassphrase: '',
startingScanIndex: 1,
endingScanIndex: 21,
seed: undefined,
},
});

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 cold or Hot wallet details
</h4>
<div className="tw-mb-4">
<FormikTextarea
HelperText="Your user public key, as found on your recovery KeyCard. Required for hot wallets."
Label="User Public Key (optional)"
name="userKey"
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 className="tw-mb-4">
<FormikTextarea
HelperText="The backup public key for the wallet, as found on your recovery KeyCard. Required for hot wallets."
Label="Backup Public Key (optional)"
name="backupKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikPasswordfield
HelperText="Your wallet passphrase, required for hot wallets."
Label="Wallet Passphrase (optional)"
name="walletPassphrase"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The BitGo public key for the wallet, as found on your recovery KeyCard."
Label="BitGo Public Key"
name="bitgoKey"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The package ID of the SUI token to recover. This is unique to each token, and is NOT your wallet address."
Label="Package Id"
name="packageId"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The starting index (inclusive) of addresses to consolidate"
Label="Starting Scan Index"
name="startingScanIndex"
Width="fill"
/>
</div>
<div className="tw-mb-4">
<FormikTextfield
HelperText="The ending index (exclusive) of addresses to consolidate"
Label="Ending Scan Index"
name="endingScanIndex"
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 ? 'Consolidating...' : 'Consolidate Funds'}
</Button>
</div>
</Form>
</FormikProvider>
);
}
68 changes: 68 additions & 0 deletions src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { TronForm } from './TronForm';
import { TronTokenForm } from './TronTokenForm';
import { SolanaForm } from './SolanaForm';
import { SolanaTokenForm } from './SolanaTokenForm';
import { SuiTokenForm } from './SuiTokenForm';
import { CardanoForm } from './CardanoForm';
import { BackToHomeHelperText } from '~/components/BackToHomeHelperText';
import { buildUnsignedSweepCoins, tokenParentCoins } from '~/helpers/config';
Expand Down Expand Up @@ -1179,6 +1180,73 @@ function Form() {
{ 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 'suiToken':
case 'tsuiToken':
return (
<SuiTokenForm
key={coin}
onSubmit={async (values, { setSubmitting }) => {
setAlert(undefined);
setSubmitting(true);
try {
await window.commands.setBitGoEnvironment(bitGoEnvironment, coin);
const parentCoin = tokenParentCoins[coin];
const chainData = coin;
const recoverData = await window.commands.recover(parentCoin, {
bitgoKey: values.bitgoKey.replace(/\s+/g, ''),
tokenContractAddress: values.packageId,
recoveryDestination: values.recoveryDestination,
seed: values.seed,
ignoreAddressTypes: [],
userKey: '',
backupKey: ''
});
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(
{
...recoverData,
...(await includePubsFor(coin, values)),
},
null,
2
),
{ encoding: 'utf-8' }
);

navigate(
`/${bitGoEnvironment}/build-unsigned-sweep/${coin}/success`
);
Expand Down
Loading

0 comments on commit a6ce929

Please sign in to comment.