Skip to content

Commit

Permalink
Refactoring create margin account flow (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
IanWoodard authored Oct 8, 2022
1 parent a2e1ccb commit 031078f
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 49 deletions.
37 changes: 22 additions & 15 deletions prime/src/components/borrow/modal/CreateMarginAccountModal.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,55 @@
import { useState } from 'react';
import { FilledStylizedButton } from '../../common/Buttons';
import { Dropdown } from '../../common/Dropdown';
import { CloseableModal, DashedDivider, LABEL_TEXT_COLOR } from '../../common/Modal';
import { Dropdown, DropdownOption } from '../../common/Dropdown';
import { CloseableModal, LABEL_TEXT_COLOR } from '../../common/Modal';
import { Text } from 'shared/lib/components/common/Typography';
import { MODAL_BLACK_TEXT_COLOR } from '../../common/Modal';

export type CreateMarginAccountModalProps = {
open: boolean;
availablePools: { label: string; value: string }[];
isTxnPending: boolean;
availablePools: DropdownOption[];
setOpen: (open: boolean) => void;
onConfirm: (selectedPool: string | null) => void;
onCancel: () => void;
};

export default function CreateMarginAccountModal(props: CreateMarginAccountModalProps) {
const { open, setOpen, onConfirm, onCancel, availablePools } = props;
const [selectedPool, setSelectedPool] = useState<string | null>(
availablePools.length > 0 ? availablePools[0].value : null
const { open, isTxnPending, availablePools, setOpen, onConfirm, onCancel } = props;
const [selectedPool, setSelectedPool] = useState<DropdownOption | null>(
availablePools.length > 0 ? availablePools[0] : null
);
if (selectedPool == null) {
return null;
}
const confirmButtonText = isTxnPending ? 'Pending' : 'Create Margin Account';
return (
<CloseableModal open={open} setOpen={setOpen} onClose={onCancel} title='New'>
<div className='flex justify-between items-center mb-8'>
<Text size='S' weight='medium' color={LABEL_TEXT_COLOR}>
<CloseableModal open={open} setOpen={setOpen} onClose={onCancel} title='New Margin Account'>
<div className='flex flex-col gap-3 mb-8'>
<Text size='M' weight='bold' color={LABEL_TEXT_COLOR}>
Uniswap Pool
</Text>
<DashedDivider />
<Dropdown
options={availablePools}
selectedOption={availablePools[0]}
selectedOption={selectedPool ?? availablePools[0]}
onSelect={(option) => {
setSelectedPool(option.value);
setSelectedPool(option);
}}
small={true}
/>
</div>
<FilledStylizedButton
size='M'
fillWidth={true}
color={MODAL_BLACK_TEXT_COLOR}
onClick={() => {
onConfirm(selectedPool);
const selectedPoolValue = selectedPool?.value;
if (selectedPoolValue) {
onConfirm(selectedPoolValue);
}
}}
disabled={isTxnPending}
>
Create Margin Account
{confirmButtonText}
</FilledStylizedButton>
</CloseableModal>
);
Expand Down
12 changes: 12 additions & 0 deletions prime/src/connector/FactoryActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ import { BigNumber, Contract, ContractReceipt, Signer } from 'ethers';
import FactoryABI from '../assets/abis/Factory.json';
import { ALOE_II_FACTORY_ADDRESS_BUILT_IN_FAUCET_GOERLI } from '../data/constants/Addresses';

/**
*
* @param signer the signer to use for the transaction
* @param poolAddress the pool address to be used for the margin account
* @param ownerAddress the address of the owner of the margin account
* @param commencementCallback a callback to be called when the transaction is sent
* @param completionCallback a callback to be called when the transaction is completed
*/
export async function createMarginAccount(
signer: Signer,
poolAddress: string,
ownerAddress: string,
commencementCallback: () => void,
completionCallback: (receipt?: ContractReceipt) => void
): Promise<void> {
// TODO: Temporarily replacing actual factory with one that has a built-in faucet upon MarginAccount creation
Expand All @@ -28,7 +37,10 @@ export async function createMarginAccount(

try {
const transactionResponse = await factory.createMarginAccount(poolAddress, ownerAddress, transactionOptions);
// The txn was approved, now we wait
commencementCallback();
const receipt = await transactionResponse.wait(BLOCKS_TO_WAIT);
// Tada! The txn is complete
completionCallback(receipt);
} catch (e) {
// User probably rejected in MetaMask or wallet
Expand Down
56 changes: 48 additions & 8 deletions prime/src/data/TokenData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { FeiLogo, UsdcLogo, WbtcLogo, WethLogo, TribeLogo, RaiLogo, LooksLogo } from '../assets/svg/tokens';

export type TokenData = {
address: string;
decimals: number;
ticker?: string;
name?: string;
iconPath?: string;
// TODO: Move this out of here, so that other uses of tokendata don't have to async wait to draw
address: string; // Address of the token
decimals: number; // Number of decimals for the token
ticker?: string; // Ticker of the token
name?: string; // Name of the token
iconPath?: string; // Path to the icon for the token
referenceAddress?: string; // Address of the token that is used to get the price of the token
};

const TokenDataMap = new Map<string, TokenData>([
Expand All @@ -19,6 +19,7 @@ const TokenDataMap = new Map<string, TokenData>([
ticker: 'USDC',
iconPath: UsdcLogo,
decimals: 6,
referenceAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // Mainnet USDC
},
],
// WETH (Goerli)
Expand All @@ -30,6 +31,7 @@ const TokenDataMap = new Map<string, TokenData>([
ticker: 'WETH',
iconPath: WethLogo,
decimals: 18,
referenceAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // Mainnet WETH
},
],
// USDC
Expand All @@ -51,7 +53,8 @@ const TokenDataMap = new Map<string, TokenData>([
name: 'Aloe II USD Coin',
ticker: 'USDC+',
iconPath: UsdcLogo,
decimals: 6,
decimals: 18,
referenceAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // Mainnet USDC
},
],
// WETH
Expand All @@ -65,7 +68,7 @@ const TokenDataMap = new Map<string, TokenData>([
decimals: 18,
},
],
// WETH+ (Goerli)
// WETH+ (Goerli) - USDC
[
'0xea1e4f047caaa24cf855ceeeda77cd353af81aec',
{
Expand All @@ -74,6 +77,43 @@ const TokenDataMap = new Map<string, TokenData>([
ticker: 'WETH+',
iconPath: WethLogo,
decimals: 18,
referenceAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // Mainnet WETH
},
],
// WETH+ (Goerli) - WBTC
[
'0x8fd637b40a6ba572d1dc48fe853d9d06e6ab1ec6',
{
address: '0x8fd637b40a6ba572d1dc48fe853d9d06e6ab1ec6',
name: 'Aloe II Wrapped Ether',
ticker: 'WETH+',
iconPath: WethLogo,
decimals: 18,
referenceAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // Mainnet WETH
},
],
// WBTC (Goerli)
[
'0x886055958cdf2635ff47a2071264a3413d26f959',
{
address: '0x886055958cdf2635ff47a2071264a3413d26f959',
name: 'Wrapped Bitcoin',
ticker: 'WBTC',
iconPath: WbtcLogo,
decimals: 8,
referenceAddress: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', // Mainnet WBTC
},
],
// WBTC+ (Goerli)
[
'0x6950d4431fc13b465f9c93532823614fc8586598',
{
address: '0x6950d4431fc13b465f9c93532823614fc8586598',
name: 'Wrapped Bitcoin',
ticker: 'WBTC+',
iconPath: WbtcLogo,
decimals: 18,
referenceAddress: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', // Mainnet WBTC
},
],
// WBTC
Expand Down
76 changes: 50 additions & 26 deletions prime/src/pages/BorrowAccountsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,26 @@ import { FilledGradientButtonWithIcon } from '../components/common/Buttons';
import { Display } from 'shared/lib/components/common/Typography';
import { createMarginAccount } from '../connector/FactoryActions';
import { fetchMarginAccountPreviews, MarginAccountPreview } from '../data/MarginAccount';
import { ContractReceipt } from 'ethers';

import MarginAccountLensABI from '../assets/abis/MarginAccountLens.json';
import WelcomeModal from '../components/borrow/modal/WelcomeModal';
import useEffectOnce from '../data/hooks/UseEffectOnce';
import { DropdownOption } from '../components/common/Dropdown';

const WELCOME_MODAL_LOCAL_STORAGE_KEY = 'acknowledged-welcome-modal-borrow';
const WELCOME_MODAL_LOCAL_STORAGE_VALUE = 'acknowledged';

const MARGIN_ACCOUNT_OPTIONS: DropdownOption[] = [
{
label: 'USDC/WETH 0.05%',
value: '0xfBe57C73A82171A773D3328F1b563296151be515',
},
{
label: 'WBTC/WETH 0.3%',
value: '0xc0A1c271efD6D6325D5db33db5e7cF42A715CD12',
},
];

const MarginAccountsContainner = styled.div`
${tw`flex items-center justify-start flex-wrap gap-4`}
Expand All @@ -32,6 +48,7 @@ export default function BorrowAccountsPage() {
// --> other
const [showWelcomeModal, setShowWelcomeModal] = useState(false);
const [marginAccounts, setMarginAccounts] = useState<MarginAccountPreview[]>([]);
const [isTxnPending, setIsTxnPending] = useState(false);

// MARK: wagmi hooks
const currentChainId = chain.goerli.id;
Expand Down Expand Up @@ -67,12 +84,39 @@ export default function BorrowAccountsPage() {
}, [address, marginAccountLensContract, provider, blockNumber.data]);

useEffectOnce(() => {
const shouldShowWelcomeModal = localStorage.getItem('acknowledgedWelcomeModal') !== 'true';
const shouldShowWelcomeModal =
localStorage.getItem(WELCOME_MODAL_LOCAL_STORAGE_KEY) !== WELCOME_MODAL_LOCAL_STORAGE_VALUE;
if (shouldShowWelcomeModal) {
setShowWelcomeModal(true);
}
});

function onCommencement() {
setIsTxnPending(false);
setShowConfirmModal(false);
setTimeout(() => {
setShowSubmittingModal(true);
}, 500);
}

function onCompletion(receipt?: ContractReceipt) {
// Reset state (close out of potentially open modals)
if (receipt === undefined) {
setIsTxnPending(false);
return;
}
setShowSubmittingModal(false);
if (receipt?.status === 1) {
setTimeout(() => {
setShowSuccessModal(true);
}, 500);
} else {
setTimeout(() => {
setShowFailedModal(true);
}, 500);
}
}

return (
<AppPage>
<div className='flex gap-8 items-center mb-4'>
Expand All @@ -97,38 +141,18 @@ export default function BorrowAccountsPage() {
<MarginAccountCard key={index} {...marginAccount} />
))}
</MarginAccountsContainner>

<CreateMarginAccountModal
availablePools={[
{
label: 'USDC/WETH 0.05%',
value: '0xfBe57C73A82171A773D3328F1b563296151be515',
},
]}
availablePools={MARGIN_ACCOUNT_OPTIONS}
open={showConfirmModal}
isTxnPending={isTxnPending}
setOpen={setShowConfirmModal}
onConfirm={(selectedPool: string | null) => {
setShowConfirmModal(false);
setTimeout(() => {
setShowSubmittingModal(true);
}, 500);
setIsTxnPending(true);
if (!signer || !address || !selectedPool) {
// TODO
return;
}
createMarginAccount(signer, selectedPool, address, (receipt) => {
setShowSubmittingModal(false);
if (receipt?.status === 1) {
setTimeout(() => {
setShowSuccessModal(true);
}, 500);
} else {
setTimeout(() => {
setShowFailedModal(true);
}, 500);
}
console.log(receipt);
});
createMarginAccount(signer, selectedPool, address, onCommencement, onCompletion);
}}
onCancel={() => {
// TODO
Expand All @@ -147,7 +171,7 @@ export default function BorrowAccountsPage() {
open={showWelcomeModal}
setOpen={setShowWelcomeModal}
onConfirm={() => {
localStorage.setItem('acknowledgedWelcomeModal', 'true');
localStorage.setItem(WELCOME_MODAL_LOCAL_STORAGE_KEY, WELCOME_MODAL_LOCAL_STORAGE_VALUE);
}}
/>
</AppPage>
Expand Down

0 comments on commit 031078f

Please sign in to comment.