diff --git a/electron/types.ts b/electron/types.ts index b3e895cf..84fb38f0 100644 --- a/electron/types.ts +++ b/electron/types.ts @@ -7,7 +7,7 @@ import { Dot, Tdot } from '@bitgo/sdk-coin-dot'; import { Sol, Tsol } from '@bitgo/sdk-coin-sol'; import { Hbar, Thbar } from '@bitgo/sdk-coin-hbar'; import { Algo, Talgo } from '@bitgo/sdk-coin-algo'; -import { Sui, Tsui } from '@bitgo-beta/sdk-coin-sui'; +import { Sui, Tsui } from '@bitgo/sdk-coin-sui'; export type createAdaBroadcastableSweepTransactionParameters = | Parameters[0] diff --git a/package-lock.json b/package-lock.json index ac7dcff4..210d3953 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "@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-sui": "^5.7.0", "@bitgo/sdk-coin-tia": "3.0.4", "@bitgo/sdk-coin-trx": "2.0.35", "@bitgo/sdk-coin-xlm": "3.2.9", @@ -4301,14 +4301,14 @@ } }, "node_modules/@bitgo/sdk-coin-sui": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@bitgo/sdk-coin-sui/-/sdk-coin-sui-5.6.3.tgz", - "integrity": "sha512-6EcCWpB2ftvtKkoS/hvx5pL7UB6HoFlX4mG27U1gdedkq+7K1fH7BUxFjsH9VCz4Q8OH/Cly8BeJ9gGXL5pHhg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@bitgo/sdk-coin-sui/-/sdk-coin-sui-5.7.0.tgz", + "integrity": "sha512-kntUIJjWOJ1Y1QaMAU2FmRoGbSOxwk+oAUjnPQAxgKKm7ClRTMsqGeojNvZH6kQqcS988FUDefLNtnqf6qgYUQ==", "dependencies": { "@bitgo/blake2b": "^3.2.4", - "@bitgo/sdk-core": "^28.4.0", + "@bitgo/sdk-core": "^28.6.0", "@bitgo/sdk-lib-mpc": "^10.0.0", - "@bitgo/statics": "^49.4.0", + "@bitgo/statics": "^49.6.0", "@mysten/bcs": "^0.7.0", "bignumber.js": "^9.0.0", "bs58": "^4.0.1", @@ -4547,15 +4547,15 @@ } }, "node_modules/@bitgo/sdk-core": { - "version": "28.4.0", - "resolved": "https://registry.npmjs.org/@bitgo/sdk-core/-/sdk-core-28.4.0.tgz", - "integrity": "sha512-s4wZuaKKpn9iwloc5Jh0Rn9XwATNZIbkcHWsXR6kgILD5JRQbn1oZgT3xEdjbJj74ZMhnIAX1U6P/oHOo1eTXg==", + "version": "28.6.0", + "resolved": "https://registry.npmjs.org/@bitgo/sdk-core/-/sdk-core-28.6.0.tgz", + "integrity": "sha512-W7MND1XVMPYh2fz24UMAEhfxN/saJ/t1qKgUOEfeZsQf1Eonr4S7J7bTPeXkNDTtzcHnNOLH4yy4GVchILiW4w==", "dependencies": { "@bitgo/bls-dkg": "^1.3.1", "@bitgo/public-types": "2.33.4", "@bitgo/sdk-lib-mpc": "^10.0.0", "@bitgo/sjcl": "^1.0.1", - "@bitgo/statics": "^49.4.0", + "@bitgo/statics": "^49.6.0", "@bitgo/utxo-lib": "^10.3.0", "@noble/secp256k1": "1.6.3", "@stablelib/hex": "^1.0.0", @@ -4729,9 +4729,9 @@ "license": "(BSD-2-Clause OR GPL-2.0-only)" }, "node_modules/@bitgo/statics": { - "version": "49.4.0", - "resolved": "https://registry.npmjs.org/@bitgo/statics/-/statics-49.4.0.tgz", - "integrity": "sha512-KNc/FvrCun85mzWfE8Tk8oid8PZE1ML2i7qWfKiR647MCAp4Tk771qvJIfKimL7OQs7topMuOuiyo+qkxlCzhA==" + "version": "49.6.0", + "resolved": "https://registry.npmjs.org/@bitgo/statics/-/statics-49.6.0.tgz", + "integrity": "sha512-zfjPsAi0GDVhDiGOubpOw7nsf1fRsb+W0Fp//FLzuXnsD3CFMouo5Jualkuh/eaiy+s74RLWIiMmzOx1XmtXsA==" }, "node_modules/@bitgo/unspents": { "version": "0.47.10", diff --git a/package.json b/package.json index a6a3a09a..5073fbfb 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "dependencies": { "@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", @@ -44,13 +43,14 @@ "@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-sui": "5.7.0", "@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", diff --git a/src/containers/BuildUnsignedConsolidation/BuildUnsignedConsolidationCoin.tsx b/src/containers/BuildUnsignedConsolidation/BuildUnsignedConsolidationCoin.tsx index dce3dda9..4d4d144e 100644 --- a/src/containers/BuildUnsignedConsolidation/BuildUnsignedConsolidationCoin.tsx +++ b/src/containers/BuildUnsignedConsolidation/BuildUnsignedConsolidationCoin.tsx @@ -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; @@ -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']) ); } @@ -343,6 +343,60 @@ function ConsolidationForm({ coin, environment }: ConsolidationFormProps) { console.log(e); } + setSubmitting(false); + } + }} + /> + ); + case 'suiToken': + case 'tsuiToken': + return ( + { + 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, { + ...(await updateKeysFromIds(parentCoin, values)), + 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); } }} diff --git a/src/containers/BuildUnsignedConsolidation/SuiTokenForm.tsx b/src/containers/BuildUnsignedConsolidation/SuiTokenForm.tsx new file mode 100644 index 00000000..61793596 --- /dev/null +++ b/src/containers/BuildUnsignedConsolidation/SuiTokenForm.tsx @@ -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().required(), + backupKey: Yup.string().required(), + 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; + +export type SuiTokenFormValues = { + onSubmit: ( + values: SuiFormValues, + formikHelpers: FormikHelpers + ) => void | Promise; +}; + +export function SuiTokenForm({ onSubmit }: SuiTokenFormValues) { + const formik = useFormik({ + onSubmit, + initialValues: { + userKey: '', + backupKey: '', + bitgoKey: '', + packageId: '', + walletPassphrase: '', + startingScanIndex: 1, + endingScanIndex: 21, + seed: undefined, + }, + }); + + return ( + +
+

+ Self-managed cold or Hot wallet details +

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
+ ); +} diff --git a/src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx b/src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx index e01189d1..00da3d67 100644 --- a/src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx +++ b/src/containers/BuildUnsignedSweepCoin/BuildUnsignedSweepCoin.tsx @@ -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'; @@ -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 ( + { + 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` ); diff --git a/src/containers/BuildUnsignedSweepCoin/SuiTokenForm.tsx b/src/containers/BuildUnsignedSweepCoin/SuiTokenForm.tsx new file mode 100644 index 00000000..73edee89 --- /dev/null +++ b/src/containers/BuildUnsignedSweepCoin/SuiTokenForm.tsx @@ -0,0 +1,93 @@ +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({ + userKey: Yup.string().required(), + backupKey: Yup.string().required(), + bitgoKey: Yup.string().required(), + packageId: Yup.string().required(), + recoveryDestination: Yup.string().required(), + seed: Yup.string(), +}).required(); + +type SuiFormValues = Yup.Asserts; + +export type SuiTokenFormProps = { + onSubmit: ( + values: SuiFormValues, + formikHelpers: FormikHelpers + ) => void | Promise; +}; + +export function SuiTokenForm({ onSubmit }: SuiTokenFormProps) { + const formik = useFormik({ + onSubmit, + initialValues: { + userKey: '', + backupKey: '', + bitgoKey: '', + packageId: '', + recoveryDestination: '', + seed: undefined, + }, + validationSchema, + }); + + return ( + +
+

+ Self-managed cold wallet details +

+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
+ ); +} diff --git a/src/containers/CreateBroadcastableTransaction/CreateBroadcastableTransactionIndex.tsx b/src/containers/CreateBroadcastableTransaction/CreateBroadcastableTransactionIndex.tsx index 49ef8060..2cbc416d 100644 --- a/src/containers/CreateBroadcastableTransaction/CreateBroadcastableTransactionIndex.tsx +++ b/src/containers/CreateBroadcastableTransaction/CreateBroadcastableTransactionIndex.tsx @@ -72,7 +72,8 @@ export function CreateBroadcastableTransactionIndex() { assert(isSignedTransaction(tx), 'Signed transaction not found'); - const coin = tx.signatureShares[0].txRequest.walletCoin; + let coin = tx.signatureShares[0].txRequest.walletCoin; + coin = (coin as string).split(':')[0]; const chainData = await window.queries.getChain(coin); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const broadcastTx: Error | BroadcastableSweepTransaction = diff --git a/src/containers/NonBitGoRecoveryCoin/NonBitGoRecoveryCoin.tsx b/src/containers/NonBitGoRecoveryCoin/NonBitGoRecoveryCoin.tsx index 45ba2632..3f12b862 100644 --- a/src/containers/NonBitGoRecoveryCoin/NonBitGoRecoveryCoin.tsx +++ b/src/containers/NonBitGoRecoveryCoin/NonBitGoRecoveryCoin.tsx @@ -954,6 +954,8 @@ function Form() { ); case 'trxToken': case 'ttrxToken': + case 'suiToken': + case 'tsuiToken': return ( = { Icon: 'sui', value: 'sui', }, + suiToken: { + Title: 'SUI Token', + Description: 'Sui Token', + Icon: 'sui', + value: 'suiToken', + }, tsui: { Title: 'TSUI', Description: 'Testnet Sui', Icon: 'sui', value: 'tsui', }, + tsuiToken: { + Title: 'TSUI Token', + Description: 'Testnet Sui Token', + Icon: 'sui', + value: 'tsuiToken', + }, tbtc: { Title: 'TBTC', Description: 'Testnet Bitcoin', @@ -606,6 +618,7 @@ export const buildUnsignedConsolidationCoins: Record< allCoinMetas.sol, allCoinMetas.solToken, allCoinMetas.sui, + allCoinMetas.suiToken, ], test: [ allCoinMetas.ttrx, @@ -615,6 +628,7 @@ export const buildUnsignedConsolidationCoins: Record< allCoinMetas.tsol, allCoinMetas.tsolToken, allCoinMetas.tsui, + allCoinMetas.tsuiToken, ], }; @@ -656,6 +670,7 @@ export const buildUnsignedSweepCoins: Record< allCoinMetas.hbar, allCoinMetas.algo, allCoinMetas.sui, + allCoinMetas.suiToken, ] as const, test: [ allCoinMetas.tbtc, @@ -684,6 +699,7 @@ export const buildUnsignedSweepCoins: Record< allCoinMetas.talgo, allCoinMetas.tbsc, allCoinMetas.tsui, + allCoinMetas.tsuiToken, ] as const, }; @@ -733,6 +749,7 @@ export const nonBitgoRecoveryCoins: Record = allCoinMetas.hbar, allCoinMetas.algo, allCoinMetas.sui, + allCoinMetas.suiToken, ] as const, test: [ allCoinMetas.tbtc, @@ -771,6 +788,7 @@ export const nonBitgoRecoveryCoins: Record = allCoinMetas.thbar, allCoinMetas.talgo, allCoinMetas.tsui, + allCoinMetas.tsuiToken, ] as const, }; @@ -928,6 +946,10 @@ export const tokenParentCoins = { topethToken: 'topeth', polygonToken: 'polygon', tpolygonToken: 'tpolygon', + suiToken: 'sui', + tsuiToken: 'tsui', + trxToken: 'trx', + ttrxToken: 'ttrx' }; export type EvmCcrNonBitgoCoinConfigType = {