diff --git a/packages/common/src/services/wallet-client/WalletClient.ts b/packages/common/src/services/wallet-client/WalletClient.ts index 7b9c66f2971..22f8b20c734 100644 --- a/packages/common/src/services/wallet-client/WalletClient.ts +++ b/packages/common/src/services/wallet-client/WalletClient.ts @@ -99,6 +99,14 @@ export class WalletClient { { permitTxHash } ) + const permitReceipt = + await ethereum.publicClient.waitForTransactionReceipt({ + hash: permitTxHash + }) + if (permitReceipt.status !== 'success') { + throw new Error('AUDIO permit transaction failed.') + } + const transferTxHash = await ethereum.wormholeTransferTokens({ amount: balance, recipient: `0x${account.address.toBuffer().toString('hex')}` diff --git a/packages/identity-service/src/typed-routes/ethereum/ethRpc.ts b/packages/identity-service/src/typed-routes/ethereum/ethRpc.ts index 84c418ff791..679ce08fd1b 100644 --- a/packages/identity-service/src/typed-routes/ethereum/ethRpc.ts +++ b/packages/identity-service/src/typed-routes/ethereum/ethRpc.ts @@ -40,6 +40,9 @@ type RelayerWallet = { const ethRelayerWallets = config.get('ethRelayerWallets') +const ensureHex = (str: string): Hex => + str.startsWith('0x') ? (str as Hex) : `0x${str}` + const walletClient = createWalletClient({ chain: mainnet, transport: http(config.get('ethProviderUrl')) @@ -204,9 +207,7 @@ const createRouter = () => { const res = await withLock( generateETHWalletLockKey(relayer.publicKey), async () => { - const account = privateKeyToAccount( - ('0x' + relayer.privateKey) as Hex - ) + const account = privateKeyToAccount(ensureHex(relayer.privateKey)) const transactionRequest = toTransactionRequest(body.params[0]) logger.debug(transactionRequest, 'Sending transaction...') const hash = await walletClient.sendTransaction({ diff --git a/packages/web/src/pages/settings-page/components/desktop/WormholeConversionSettingsCard.tsx b/packages/web/src/pages/settings-page/components/desktop/WormholeConversionSettingsCard.tsx index 5709a26e2f1..5a3f9bd1b5e 100644 --- a/packages/web/src/pages/settings-page/components/desktop/WormholeConversionSettingsCard.tsx +++ b/packages/web/src/pages/settings-page/components/desktop/WormholeConversionSettingsCard.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useEffect } from 'react' import { useCurrentUserId, @@ -33,13 +33,15 @@ const messages = { ethBalance: 'ERC-20 $AUDIO Balance', noBalance: 'No ERC-20 $AUDIO to migrate', loading: 'Loading...', + migrationInProgress: 'Migration in progress', success: 'Migration transaction sent!', error: 'Migration failed, please try again', tooltip: 'The migration process usually takes 60 minutes to complete. You can navigate away, and your balance will automatically return to your built-in wallet upon completion.' } -const WORMHOLE_MIGRATION_COMPLETED_KEY = 'wormholeMigrationCompleted' +const WORMHOLE_MIGRATION_STARTED_KEY = 'wormholeMigrationCompleted' +const WORMHOLE_MIGRATION_STARTED_TTL_MS = 24 * 60 * 60 * 1000 export const WormholeConversionSettingsCard = () => { const dispatch = useDispatch() @@ -58,12 +60,34 @@ export const WormholeConversionSettingsCard = () => { const { mutate: transferEthToSol, isPending: isConverting } = useTransferEthToSol() - const [isMigrationCompleted, setIsMigrationCompleted] = useLocalStorage( - WORMHOLE_MIGRATION_COMPLETED_KEY, - false - ) + const [migrationStartedAt, setMigrationStartedAt, removeMigrationStartedAt] = + useLocalStorage( + WORMHOLE_MIGRATION_STARTED_KEY, + null + ) const hasBalance = ethBalance && ethBalance > BigInt(0) + const isLegacyMigrationStarted = migrationStartedAt === true + const migrationStartedAtMs = + typeof migrationStartedAt === 'number' ? migrationStartedAt : null + const isMigrationInProgress = + isLegacyMigrationStarted || + (migrationStartedAtMs !== null && + Date.now() - migrationStartedAtMs <= WORMHOLE_MIGRATION_STARTED_TTL_MS) + + useEffect(() => { + if (isLegacyMigrationStarted) { + setMigrationStartedAt(Date.now()) + } else if (migrationStartedAtMs !== null && !isMigrationInProgress) { + removeMigrationStartedAt() + } + }, [ + isLegacyMigrationStarted, + isMigrationInProgress, + migrationStartedAtMs, + removeMigrationStartedAt, + setMigrationStartedAt + ]) const handleConvert = useCallback(() => { if (!hasBalance || isConverting || !user?.erc_wallet) return @@ -78,7 +102,7 @@ export const WormholeConversionSettingsCard = () => { type: 'info' }) ) - setIsMigrationCompleted(true) + setMigrationStartedAt(Date.now()) }, onError: (error) => { dispatch( @@ -97,7 +121,7 @@ export const WormholeConversionSettingsCard = () => { user?.erc_wallet, transferEthToSol, dispatch, - setIsMigrationCompleted + setMigrationStartedAt ]) const formattedBalance = ethBalance @@ -105,9 +129,9 @@ export const WormholeConversionSettingsCard = () => { : '0' const isButtonDisabled = - !hasBalance || isConverting || isBalanceLoading || isMigrationCompleted + !hasBalance || isConverting || isBalanceLoading || isMigrationInProgress - if (!hasBalance && !isMigrationCompleted) { + if (!hasBalance && !isMigrationInProgress) { return null } @@ -136,13 +160,13 @@ export const WormholeConversionSettingsCard = () => { fullWidth disabled={isButtonDisabled} iconRight={ - isConverting || isMigrationCompleted ? undefined : IconArrowRight + isConverting || isMigrationInProgress ? undefined : IconArrowRight } > {isConverting ? messages.buttonTextConverting - : isMigrationCompleted - ? messages.success + : isMigrationInProgress + ? messages.migrationInProgress : messages.buttonText}