-
Notifications
You must be signed in to change notification settings - Fork 1
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
[DO NOT MERGE - Iceboxed] Add Iframe and Summary card for the KYC #127
Changes from all commits
d345c90
93f3bf6
a2f475b
6172629
cddc8ca
171066d
9d5fc4e
dc6f6d0
bda9638
f253afc
52d2749
bc019e6
1ef6395
24afd1e
0080740
942a397
3d52961
9647226
e7635cd
4ced67a
88e5887
fc92db8
8b08240
37304c5
f78ae4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ types/ | |
coverage/ | ||
gql/ | ||
signer-service | ||
mooncontracts/ | ||
|
||
*.d.ts | ||
*.config.* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import React from 'preact/compat'; | ||
import { BaseLayout } from '../../layouts'; | ||
import { SummaryCard, SummaryCardProps } from '../../components/SummaryCard'; | ||
|
||
export interface IframeProps extends SummaryCardProps { | ||
src: string; | ||
title: string; | ||
subtitle: string; | ||
} | ||
|
||
export const IframeComponent: React.FC<IframeProps> = ({ | ||
src, title, subtitle, assetIn, assetOut, fromAmount, toAmount | ||
}) => { | ||
|
||
const main = ( | ||
<div className="flex flex-col justify-center items-center p-4 w-full"> | ||
<div className="md:w-[535px] w-full"> | ||
<div className="text-center"> | ||
<h1 className="text-2xl font-bold text-blue-700 mb-4 mt-4">{title}</h1> | ||
</div> | ||
<div className="flex justify-center items-center w-full"> | ||
<SummaryCard {...{ | ||
assetIn, | ||
assetOut, | ||
fromAmount, | ||
toAmount, | ||
}} /> | ||
</div> | ||
<div className="text-center"> | ||
<h2 className="text-md mb-4 mt-4">{subtitle}</h2> | ||
</div> | ||
</div> | ||
<div className="flex justify-center items-center relative w-full h-[50vh] md:w-[535px] "> | ||
<iframe | ||
Sharqiewicz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
title="Anchor KYC" | ||
src={src} | ||
style={{ border: 'border-0' }} | ||
className="absolute top-0 left-0 w-full h-full" | ||
allowFullScreen | ||
/> | ||
</div> | ||
</div> | ||
); | ||
return <BaseLayout main={main} />; | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
interface LowerSummaryCardProps { | ||
label: string; | ||
amount: string; | ||
startIcon?: string | JSX.Element; | ||
endIcon?: string | JSX.Element; | ||
symbol?: string; | ||
remarked?: boolean; | ||
} | ||
|
||
export const LowerSummaryCard = ({ label, amount, startIcon, endIcon, symbol, remarked }: LowerSummaryCardProps) => ( | ||
<div | ||
className={`px-3 py-1 h-auto flex flex-col justify-between space-y-0 rounded ${ | ||
remarked ? 'bg-blue-100 bg-opacity-50' : '' | ||
}`} | ||
> | ||
<div className="place-self-start"> | ||
<span className="text-xs md:text-sm font-thin">{label}</span> | ||
</div> | ||
<div className="flex items-center w-full"> | ||
<div className="pr-1 p-0"> | ||
{startIcon && typeof startIcon === 'string' ? ( | ||
<img src={startIcon} className="w-3 md:w-5 h-3 md:h-5" /> | ||
) : ( | ||
startIcon | ||
)} | ||
</div> | ||
<span className="text-xs md:text-lg mr-1">{amount}</span> | ||
<div className="flex items-center"> | ||
{endIcon && typeof endIcon === 'string' ? <img src={endIcon} className="w-3 md:w-5 h-3 md:h-5" /> : endIcon} | ||
{symbol && <span className="ml-1 text-xs md:text-lg">{symbol}</span>} | ||
</div> | ||
</div> | ||
</div> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
interface UpperSummaryCardProps { | ||
label: string; | ||
amount: string; | ||
icon: string; | ||
symbol: string; | ||
} | ||
|
||
export const UpperSummaryCard = ({ label, amount, icon, symbol }: UpperSummaryCardProps) => ( | ||
<div className="border rounded px-3 py-1 h-auto flex flex-col justify-between space-y-0"> | ||
<div className="place-self-start"> | ||
<span className="text-xs md:text-sm font-thin">{label}</span> | ||
</div> | ||
<div className="flex justify-between items-center w-full"> | ||
<span className="text-md md:text-xl font-medium text-blue-800">{amount}</span> | ||
<div className="flex items-center mr-2"> | ||
<img src={icon} className="w-4 md:w-6 h-4 md:h-6" /> | ||
<span className="ml-1 text-blue-800">{symbol}</span> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use everywhere text-blue-700 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to avoid such confusion I think we should make a class like
|
||
</div> | ||
</div> | ||
</div> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { FC } from 'preact/compat'; | ||
import { useGetIcon } from '../../hooks/useGetIcon'; | ||
import { InputTokenType, OutputTokenType, INPUT_TOKEN_CONFIG, OUTPUT_TOKEN_CONFIG } from '../../constants/tokenConfig'; | ||
import Big from 'big.js'; | ||
import { calculateTotalReceive } from '../FeeCollapse'; | ||
import { roundDownToSignificantDecimals } from '../../helpers/parseNumbers'; | ||
import { UpperSummaryCard } from './UpperSummaryCard'; | ||
import { LowerSummaryCard } from './LowerSummaryCard'; | ||
import LocalGasStationIcon from '@mui/icons-material/LocalGasStation'; | ||
export interface SummaryCardProps { | ||
assetIn: InputTokenType; | ||
assetOut: OutputTokenType; | ||
fromAmount: Big; | ||
toAmount: Big; | ||
} | ||
|
||
export const SummaryCard: FC<SummaryCardProps> = ({ assetIn, assetOut, fromAmount, toAmount }) => { | ||
const assetInSymbol = INPUT_TOKEN_CONFIG[assetIn].assetSymbol; | ||
const assetOutSymbol = OUTPUT_TOKEN_CONFIG[assetOut].fiat.symbol; | ||
|
||
const assetInIcon = useGetIcon(INPUT_TOKEN_CONFIG[assetIn].polygonAssetIcon); | ||
const assetOutIcon = useGetIcon(OUTPUT_TOKEN_CONFIG[assetOut].fiat.assetIcon); | ||
|
||
const receiveAmount = calculateTotalReceive(toAmount.toString(), OUTPUT_TOKEN_CONFIG[assetOut]); | ||
|
||
const approximateExchangeRate = roundDownToSignificantDecimals(toAmount.div(fromAmount), 2).toString(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't it be better to also use 4 decimals as on the details box on the main page? E.g., reuse the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use |
||
const offrampFees = roundDownToSignificantDecimals(toAmount.sub(receiveAmount), 2).toString(); | ||
|
||
return ( | ||
<div className="bg-white card p-4 rounded-lg border w-full shadow"> | ||
<div className="grid grid-cols-2 gap-4 mb-2"> | ||
<UpperSummaryCard | ||
label="You withdraw" | ||
amount={roundDownToSignificantDecimals(fromAmount, 2).toString()} | ||
icon={assetInIcon} | ||
symbol={assetInSymbol} | ||
/> | ||
<UpperSummaryCard label="You receive" amount={receiveAmount} icon={assetOutIcon} symbol={assetOutSymbol} /> | ||
</div> | ||
|
||
<div className="grid grid-cols-10 gap-4"> | ||
<div className="col-span-3"> | ||
<LowerSummaryCard | ||
label="Your quote" | ||
amount={roundDownToSignificantDecimals(toAmount, 2).toString()} | ||
endIcon={assetOutIcon} | ||
symbol={assetOutSymbol} | ||
remarked={true} | ||
/> | ||
</div> | ||
<div className="col-span-4"> | ||
<LowerSummaryCard | ||
label="Exchange rate" | ||
amount={`1 ${assetInSymbol} ≈ ${approximateExchangeRate} ${assetOutSymbol}`} | ||
/> | ||
</div> | ||
<div className="col-span-3"> | ||
<LowerSummaryCard | ||
label="Offramp fees" | ||
amount={offrampFees} | ||
startIcon={<LocalGasStationIcon className="text-blue-700" fontSize="small" />} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I argue that we should remove the gas station icon: #102 (comment) |
||
endIcon={assetOutIcon} | ||
symbol={assetOutSymbol} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ import { ExclamationCircleIcon } from '@heroicons/react/20/solid'; | |
import { OfframpingPhase, OfframpingState } from '../../services/offrampingFlow'; | ||
import { Box } from '../../components/Box'; | ||
import { BaseLayout } from '../../layouts'; | ||
import { SigningBox } from '../../components/SigningBox'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two imports are not used. |
||
import { SigningPhase } from '../../hooks/useMainProcess'; | ||
|
||
const OFFRAMPING_PHASE_MESSAGES: Record<OfframpingPhase, string> = { | ||
prepareTransactions: 'Preparing transactions', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ import { SuccessPage } from '../success'; | |
import { FailurePage } from '../failure'; | ||
import { useInputTokenBalance } from '../../hooks/useInputTokenBalance'; | ||
import { UserBalance } from '../../components/UserBalance'; | ||
import { IframeComponent, IframeProps } from '../../components/Iframe'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
||
const Arrow = () => ( | ||
<div className="flex justify-center w-full my-5"> | ||
|
@@ -37,6 +38,17 @@ export const SwapPage = () => { | |
const formRef = useRef<HTMLDivElement | null>(null); | ||
const [api, setApi] = useState<ApiPromise | null>(null); | ||
|
||
// This is used to store the values that were submitted to the form. We need to store them because the form values | ||
// might change due to price fluctuations, but we need to keep the original values to submit the transaction. | ||
// This is important for the summary shown above the iframe. | ||
const [committedFormValues, setCommittedFormValues] = useState< | ||
| { | ||
fromAmount: Big; | ||
toAmount: Big; | ||
} | ||
| undefined | ||
>(undefined); | ||
|
||
const { isDisconnected } = useAccount(); | ||
|
||
useEffect(() => { | ||
|
@@ -110,6 +122,12 @@ export const SwapPage = () => { | |
|
||
console.log('starting ....'); | ||
|
||
// Commit the amounts so that we can show them in the summary above the iframe | ||
setCommittedFormValues({ | ||
fromAmount: new Big(fromAmountString), | ||
toAmount: new Big(minimumOutputAmount.preciseString), | ||
}); | ||
|
||
handleOnSubmit({ | ||
inputTokenType: from as InputTokenType, | ||
outputTokenType: to as OutputTokenType, | ||
|
@@ -234,6 +252,26 @@ export const SwapPage = () => { | |
if (offrampingState !== undefined || offrampingStarted) { | ||
const showMainScreenAnyway = | ||
offrampingState === undefined || ['prepareTransactions', 'squidRouter'].includes(offrampingState.phase); | ||
|
||
if ( | ||
sep24Url && | ||
committedFormValues && | ||
showMainScreenAnyway && | ||
fromAmount && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before we changed to using |
||
tokenOutData.data?.amountOut.preciseBigDecimal | ||
) { | ||
return ( | ||
<IframeComponent | ||
src={sep24Url} | ||
title="Verify Your Identity" | ||
subtitle="Please follow the steps below to complete the identity verification." | ||
assetIn={from} | ||
assetOut={to} | ||
fromAmount={committedFormValues.fromAmount} | ||
toAmount={committedFormValues.toAmount} | ||
/> | ||
); | ||
} | ||
if (!showMainScreenAnyway) { | ||
return <ProgressPage offrampingState={offrampingState} />; | ||
} | ||
|
@@ -268,23 +306,11 @@ export const SwapPage = () => { | |
<section className="flex items-center justify-center w-full mt-5"> | ||
<BenefitsList amount={fromAmount} currency={from} /> | ||
</section> | ||
{sep24Url !== undefined ? ( | ||
<a | ||
href={sep24Url} | ||
target="_blank" | ||
rel="noreferrer" | ||
className="w-full mt-5 text-white bg-blue-700 btn rounded-xl" | ||
onClick={resetSep24Url} | ||
> | ||
Enter details | ||
</a> | ||
) : ( | ||
<SwapSubmitButton | ||
text={isInitiating ? 'Confirming' : offrampingStarted ? 'Processing Details' : 'Confirm'} | ||
disabled={Boolean(getCurrentErrorMessage()) || !inputAmountIsStable} | ||
pending={isInitiating || offrampingStarted || offrampingState !== undefined} | ||
/> | ||
)} | ||
<SwapSubmitButton | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a breaking change here. The button text has been changed in the mean time, can you please change accordingly? (also the logic for the |
||
text={offrampingStarted ? 'Offramping in Progress' : 'Start Offramping'} | ||
disabled={Boolean(getCurrentErrorMessage()) || !inputAmountIsStable} | ||
pending={offrampingStarted || offrampingState !== undefined} | ||
/> | ||
</form> | ||
</main> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -186,9 +186,9 @@ export async function sep12First(sessionParams: IAnchorSessionParams): Promise<v | |
}*/ | ||
|
||
export async function sep24First(sessionParams: IAnchorSessionParams): Promise<ISep24Intermediate> { | ||
if (config.test.mockSep24) { | ||
return { url: 'https://www.example.com', id: '1234' }; | ||
} | ||
// if (config.test.mockSep24) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove, not comment out. |
||
// return { url: 'https://www.example.com', id: '1234' }; | ||
// } | ||
|
||
const { token, tomlValues } = sessionParams; | ||
const { sep24Url } = tomlValues; | ||
|
@@ -227,11 +227,13 @@ export async function sep24Second( | |
const { sep24Url } = tomlValues; | ||
|
||
if (config.test.mockSep24) { | ||
// sleep 15 seconds, mock user completion of KYC | ||
await new Promise((resolve) => setTimeout(resolve, 150000)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually 150 seconds, not 15 seconds. |
||
return { | ||
amount: sessionParams.offrampAmount, | ||
memo: 'MYK1722323689', | ||
memoType: 'text', | ||
offrampingAccount: (await fetchSigningServiceAccountId()).stellar.public, | ||
offrampingAccount: 'GSAPDFASJFPASFOKNASOFKNAS', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this change? The previous setting is better in my opinion as it sends the funds back to the funding account I use locally. |
||
}; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,7 +125,7 @@ export interface ExecutionContext { | |
setSigningPhase: (n: SigningPhase) => void; | ||
} | ||
|
||
const OFFRAMPING_STATE_LOCAL_STORAGE_KEY = 'offrampingState'; | ||
export const OFFRAMPING_STATE_LOCAL_STORAGE_KEY = 'offrampingState'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this exported now? It is not used outside this file. |
||
|
||
export interface InitiateStateArguments { | ||
sep24Id: string; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember that we discussed once that we want to reduce double scroll and the that the design solution was to prevent scrolling of the outer screen by making the iframe always fit into the screen (i.e., scrolling only happens within the iframe).
We then discussed the other option: make the iframe large enough that it will not scroll and only the outer screen is scrolling.
I actually remember that we decided to use that latter option, am I wrong (I don't find notes about this).
Same for the width of the iframe: it feels right now like looking through a peephole and I don't think that this is such a good UX.