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

feat: refactor onboarding #478

Merged
Merged
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
4 changes: 1 addition & 3 deletions frontend/components/Layout/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ export const TopBar = () => {
<DisabledLight />
</TrafficLights>

<Text>
{`Pearl (Optimus) (alpha) ${envName ? `(${envName})` : ''}`.trim()}
</Text>
<Text>{`Pearl (alpha) ${envName ? `(${envName})` : ''}`.trim()}</Text>
</TopBarContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Flex, Tag, theme, Typography } from 'antd';
import { useMemo } from 'react';

import { MiddlewareChain } from '@/client';
import { CardSection } from '@/components/styled/CardSection';
import { UNICODE_SYMBOLS } from '@/constants/symbols';
import { EXPLORER_URL } from '@/constants/urls';
import { StakingProgramId } from '@/enums/StakingProgram';
import { StakingProgramStatus } from '@/enums/StakingProgramStatus';
import { useServices } from '@/hooks/useServices';
import { useStakingProgram } from '@/hooks/useStakingProgram';
import { Maybe } from '@/types/Util';

import { CantMigrateAlert } from './CantMigrateAlert';
import { MigrateButton } from './MigrateButton';
Expand Down Expand Up @@ -41,6 +42,7 @@ export const StakingContractSection = ({
activeStakingProgramMeta,
activeStakingProgramAddress,
} = useStakingProgram();
const { selectedService } = useServices();

// /**
// * Returns `true` if this stakingProgram is active,
Expand Down Expand Up @@ -84,6 +86,9 @@ export const StakingContractSection = ({
);
}, [migrateValidation]);

const chainId: Maybe<keyof typeof EXPLORER_URL> =
selectedService?.home_chain_id;

return (
<>
<CardSection
Expand All @@ -103,12 +108,15 @@ export const StakingContractSection = ({
</Flex>

<StakingContractDetails stakingProgramId={stakingProgramId} />
<a
href={`${EXPLORER_URL[]}/address/${activeStakingProgramAddress}`}
target="_blank"
>
View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>

{chainId && (
<a
href={`${EXPLORER_URL[chainId]}/address/${activeStakingProgramAddress}`}
target="_blank"
>
View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
)}

{!migrateValidation.canMigrate && (
<CantMigrateAlert
Expand Down
5 changes: 3 additions & 2 deletions frontend/components/SetupPage/Create/SetupBackupSigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ export const SetupBackupSigner = () => {
const [form] = Form.useForm();

const handleFinish = (values: { 'backup-signer': string }) => {
// important to lowercase the address before check summing, invalid checksums will cause ethers to throw
// returns null if invalid, ethers type is incorrect...
const checksummedAddress = getAddress(
// important to lowercase the address before checksumming, invalid checksums will cause ethers to throw
values['backup-signer'].toLowerCase(),
) as Address | null; // returns null if invalid, ethers type is incorrect...
) as Address | null;

// If the address is invalid, show an error message
if (!checksummedAddress) {
Expand Down
205 changes: 118 additions & 87 deletions frontend/components/SetupPage/Create/SetupCreateSafe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { CardSection } from '@/components/styled/CardSection';
import { UNICODE_SYMBOLS } from '@/constants/symbols';
import { SUPPORT_URL } from '@/constants/urls';
import { Pages } from '@/enums/Pages';
import { useMultisig } from '@/hooks/useMultisig';
import { usePageState } from '@/hooks/usePageState';
import { useSetup } from '@/hooks/useSetup';
import { useMasterWalletContext } from '@/hooks/useWallet';
Expand All @@ -22,47 +21,89 @@ const capitalizedMiddlewareChainNames = {
[+MiddlewareChain.OPTIMISM]: 'Optimism',
};

const YouWillBeRedirected = ({ text }: { text: string }) => (
<>
<Image src="/onboarding-robot.svg" alt="logo" width={80} height={80} />
<Typography.Title
level={4}
className="m-0 mt-12 loading-ellipses"
style={{ width: '220px' }}
>
{text}
</Typography.Title>
<Text type="secondary">
You will be redirected once the account is created.
</Text>
</>
);

const CreationError = () => (
<>
<Image src="/broken-robot.svg" alt="logo" width={80} height={80} />
<Text type="secondary" className="mt-12">
Error, please restart the app and try again.
</Text>
<Text style={{ fontSize: 'small' }}>
If the issue persists,{' '}
<a href={SUPPORT_URL} target="_blank" rel="noreferrer">
contact Olas community support {UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
.
</Text>
</>
);

export const SetupCreateSafe = () => {
const { goto } = usePageState();
const {
updateWallets,
masterSafeAddressKeyExistsForChain,
masterSafeAddress,
} = useMasterWalletContext();
const { updateMasterSafeOwners } = useMultisig();
const { masterSafes, refetch: updateWallets } = useMasterWalletContext();
// const { updateMasterSafeOwners } = useMultisig();
const { backupSigner } = useSetup();

const masterSafeAddress = useMemo(() => {
if (!masterSafes) return;
return masterSafes[0]?.address;
}, [masterSafes]);

const [isCreatingSafe, setIsCreatingSafe] = useState(false);

const [optimismFailed, setOptimismFailed] = useState(false);
const [ethereumFailed, setEthereumFailed] = useState(false);
const [baseFailed, setBaseFailed] = useState(false);
const [gnosisFailed, setGnosisFailed] = useState(false);
// const [optimismFailed, setOptimismFailed] = useState(false);
// const [ethereumFailed, setEthereumFailed] = useState(false);
// const [baseFailed, setBaseFailed] = useState(false);

const [isOptimismSuccess, setIsOptimismSuccess] = useState(false);
const [isEthereumSuccess, setIsEthereumSuccess] = useState(false);
const [isBaseSuccess, setIsBaseSuccess] = useState(false);
const [isGnosisSuccess, setIsGnosisSuccess] = useState(false);
// const [isOptimismSuccess, setIsOptimismSuccess] = useState(false);
// const [isEthereumSuccess, setIsEthereumSuccess] = useState(false);
// const [isBaseSuccess, setIsBaseSuccess] = useState(false);

const createSafeWithRetries = useCallback(
async (middlewareChain: MiddlewareChain, retries: number) => {
setIsCreatingSafe(true);

// If we have retried too many times, set failed
if (retries <= 0) {
if (middlewareChain === MiddlewareChain.OPTIMISM) {
setOptimismFailed(true);
setIsOptimismSuccess(false);
throw new Error('Failed to create safe on Ethereum');
}
if (middlewareChain === MiddlewareChain.ETHEREUM) {
setEthereumFailed(true);
setIsEthereumSuccess(false);
throw new Error('Failed to create safe on Ethereum');
}
if (middlewareChain === MiddlewareChain.BASE) {
setBaseFailed(true);
setIsBaseSuccess(false);
// if (middlewareChain === MiddlewareChain.OPTIMISM) {
// setOptimismFailed(true);
// setIsOptimismSuccess(false);
// throw new Error('Failed to create safe on Ethereum');
// }
// if (middlewareChain === MiddlewareChain.ETHEREUM) {
// setEthereumFailed(true);
// setIsEthereumSuccess(false);
// throw new Error('Failed to create safe on Ethereum');
// }
// if (middlewareChain === MiddlewareChain.BASE) {
// setBaseFailed(true);
// setIsBaseSuccess(false);
// throw new Error('Failed to create safe on Base');
// }

if (middlewareChain === MiddlewareChain.GNOSIS) {
setGnosisFailed(true);
setIsGnosisSuccess(false);
throw new Error('Failed to create safe on Base');
}

throw new Error('Failed to create safe as chain is not supported');
}

Expand All @@ -71,20 +112,23 @@ export const SetupCreateSafe = () => {
.then(async () => {
// Attempt wallet and master safe updates before proceeding
try {
await updateWallets();
await updateMasterSafeOwners();
await updateWallets?.();
// await updateMasterSafeOwners();
} catch (e) {
console.error(e);
}

// Set states for successful creation
setIsCreatingSafe(false);
setOptimismFailed(false);
// setOptimismFailed(false);
setGnosisFailed(false);
})
.catch(async (e) => {
console.error(e);

// Wait for 5 seconds before retrying
await delayInSeconds(5);

// Retry
const newRetries = retries - 1;
if (newRetries <= 0) {
Expand All @@ -95,7 +139,11 @@ export const SetupCreateSafe = () => {
createSafeWithRetries(middlewareChain, newRetries);
});
},
[backupSigner, updateMasterSafeOwners, updateWallets],
[
backupSigner,
// updateMasterSafeOwners,
updateWallets,
],
);

const creationStatusText = useMemo(() => {
Expand All @@ -109,37 +157,47 @@ export const SetupCreateSafe = () => {
/**
* Avoid creating safes if any of the following conditions are met:
*/
[optimismFailed, baseFailed, ethereumFailed].some((x) => x) || // any of the chains failed
[
// optimismFailed, baseFailed, ethereumFailed
gnosisFailed,
].some((x) => x) || // any of the chains failed
isCreatingSafe //|| // already creating a safe
// [isBaseSuccess, isEthereumSuccess, isOptimismSuccess].some((x) => !x) // any of the chains are not successful
)
return;

const chainsToCreateSafesFor = {
[MiddlewareChain.OPTIMISM]: masterSafeAddressKeyExistsForChain(
MiddlewareChain.OPTIMISM,
),
[MiddlewareChain.ETHEREUM]: masterSafeAddressKeyExistsForChain(
MiddlewareChain.ETHEREUM,
),
[MiddlewareChain.BASE]: masterSafeAddressKeyExistsForChain(
MiddlewareChain.BASE,
),
// [MiddlewareChain.OPTIMISM]: masterSafeAddressKeyExistsForChain(
// MiddlewareChain.OPTIMISM,
// ),
// [MiddlewareChain.ETHEREUM]: masterSafeAddressKeyExistsForChain(
// MiddlewareChain.ETHEREUM,
// ),
// [MiddlewareChain.BASE]: masterSafeAddressKeyExistsForChain(
// MiddlewareChain.BASE,
// ),
[MiddlewareChain.GNOSIS]: !!masterSafeAddress,
};

const safeCreationsRequired = Object.entries(chainsToCreateSafesFor).reduce(
(acc, [chain, safeAddressAlreadyExists]) => {
const middlewareChain = +chain as MiddlewareChain;
if (safeAddressAlreadyExists) {
// switch (middlewareChain) {
// case MiddlewareChain.OPTIMISM:
// setIsOptimismSuccess(true);
// break;
// case MiddlewareChain.ETHEREUM:
// setIsEthereumSuccess(true);
// break;
// case MiddlewareChain.BASE:
// setIsBaseSuccess(true);
// break;
// }

switch (middlewareChain) {
case MiddlewareChain.OPTIMISM:
setIsOptimismSuccess(true);
break;
case MiddlewareChain.ETHEREUM:
setIsEthereumSuccess(true);
break;
case MiddlewareChain.BASE:
setIsBaseSuccess(true);
case MiddlewareChain.GNOSIS:
setIsGnosisSuccess(true);
break;
}
return acc;
Expand Down Expand Up @@ -169,14 +227,16 @@ export const SetupCreateSafe = () => {
}, [
backupSigner,
createSafeWithRetries,
optimismFailed,
masterSafeAddress,
isCreatingSafe,
isBaseSuccess,
isEthereumSuccess,
isOptimismSuccess,
baseFailed,
ethereumFailed,
masterSafeAddressKeyExistsForChain,
// optimismFailed,
// isBaseSuccess,
// isEthereumSuccess,
// isOptimismSuccess,
// baseFailed,
// ethereumFailed,
isGnosisSuccess,
gnosisFailed,
]);

useEffect(() => {
Expand All @@ -193,39 +253,10 @@ export const SetupCreateSafe = () => {
padding="80px 24px"
gap={12}
>
{optimismFailed ? (
<>
<Image src="/broken-robot.svg" alt="logo" width={80} height={80} />
<Text type="secondary" className="mt-12">
Error, please restart the app and try again.
</Text>
<Text style={{ fontSize: 'small' }}>
If the issue persists,{' '}
<a href={SUPPORT_URL} target="_blank" rel="noreferrer">
contact Olas community support {UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
.
</Text>
</>
{gnosisFailed ? (
<CreationError />
) : (
<>
<Image
src="/onboarding-robot.svg"
alt="logo"
width={80}
height={80}
/>
<Typography.Title
level={4}
className="m-0 mt-12 loading-ellipses"
style={{ width: '220px' }}
>
{creationStatusText}
</Typography.Title>
<Text type="secondary">
You will be redirected once the account is created.
</Text>
</>
<YouWillBeRedirected text={creationStatusText} />
)}
</CardSection>
</Card>
Expand Down
Loading
Loading