-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ui): #2053: implement SwapAction view
- Loading branch information
Showing
10 changed files
with
325 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { ReactNode } from 'react'; | ||
import cn from 'clsx'; | ||
import { detailTechnical } from '../../utils/typography'; | ||
import { CopyToClipboardButton } from '../../CopyToClipboardButton'; | ||
import { Density } from '../../Density'; | ||
|
||
export interface ActionRowProps { | ||
label: ReactNode; | ||
info: ReactNode; | ||
copyText?: string; | ||
} | ||
|
||
export const ActionRow = ({ label, copyText, info }: ActionRowProps) => { | ||
return ( | ||
<div className={cn('flex items-center gap-2 text-text-secondary', detailTechnical)}> | ||
{label} | ||
<div className='h-px grow border-t border-dashed border-other-tonalStroke stroke-1' /> | ||
{info} | ||
|
||
{copyText && ( | ||
<Density key='swap-claim' slim> | ||
<div className='size-4 [&>button]:text-neutral-light'> | ||
<CopyToClipboardButton text={copyText} /> | ||
</div> | ||
</Density> | ||
)} | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { useMemo } from 'react'; | ||
import { ArrowRight } from 'lucide-react'; | ||
import { SwapView } from '@penumbra-zone/protobuf/penumbra/core/component/dex/v1/dex_pb'; | ||
import { Metadata, ValueView } from '@penumbra-zone/protobuf/penumbra/core/asset/v1/asset_pb'; | ||
import { | ||
getAsset1Metadata, | ||
getAsset2Metadata, | ||
getClaimFeeFromSwapView, | ||
getClaimTx, | ||
} from '@penumbra-zone/getters/swap-view'; | ||
import { getOneWaySwapValues, isOneWaySwap } from '@penumbra-zone/types/swap'; | ||
import { getAmount, getMetadata } from '@penumbra-zone/getters/value-view'; | ||
import { isZero } from '@penumbra-zone/types/amount'; | ||
import { getFormattedAmtFromValueView } from '@penumbra-zone/types/value-view'; | ||
import { uint8ArrayToHex } from '@penumbra-zone/types/hex'; | ||
import { shorten } from '@penumbra-zone/types/string'; | ||
import { ValueViewComponent } from '../../ValueView'; | ||
import { useDensity } from '../../utils/density'; | ||
import { Density } from '../../Density'; | ||
import { ActionWrapper } from './wrapper'; | ||
import { ActionRow } from './action-row'; | ||
|
||
export interface SwapActionProps { | ||
value: SwapView; | ||
} | ||
|
||
const renderAmount = (value?: ValueView) => { | ||
if (!value) { | ||
return undefined; | ||
} | ||
const symbol = getMetadata.optional(value)?.symbol; | ||
return symbol ? `${getFormattedAmtFromValueView(value)} ${symbol}` : undefined; | ||
}; | ||
|
||
export const SwapAction = ({ value }: SwapActionProps) => { | ||
const density = useDensity(); | ||
|
||
const isOneWay = isOneWaySwap(value); | ||
const swap = isOneWay ? getOneWaySwapValues(value) : undefined; | ||
const showOutput = !!getAmount.optional(swap?.output) && !isZero(getAmount(swap?.output)); | ||
|
||
const unfilled = useMemo(() => { | ||
return renderAmount(swap?.unfilled); | ||
}, [swap]); | ||
|
||
const txId = useMemo(() => { | ||
const claim = getClaimTx.optional(value); | ||
if (!claim) { | ||
return undefined; | ||
} | ||
return uint8ArrayToHex(claim.inner); | ||
}, [value]); | ||
|
||
// This function calculates metadata based on fee's AssetId from input or output metadata. | ||
// TODO: implement fees paid from non-input/output assets (e.g. connect with registry) | ||
const fee = useMemo(() => { | ||
const claimFee = getClaimFeeFromSwapView.optional(value); | ||
if (!claimFee) { | ||
return undefined; | ||
} | ||
|
||
let metadata: Metadata | undefined = undefined; | ||
const asset1 = getAsset1Metadata.optional(value); | ||
const asset2 = getAsset2Metadata.optional(value); | ||
if (claimFee.assetId?.equals(asset1?.penumbraAssetId)) { | ||
metadata = asset1; | ||
} | ||
if (claimFee.assetId?.equals(asset2?.penumbraAssetId)) { | ||
metadata = asset1; | ||
} | ||
|
||
if (metadata) { | ||
return renderAmount( | ||
new ValueView({ | ||
valueView: { | ||
case: 'knownAssetId', | ||
value: { | ||
metadata, | ||
amount: claimFee.amount, | ||
}, | ||
}, | ||
}), | ||
); | ||
} | ||
|
||
return renderAmount( | ||
new ValueView({ | ||
valueView: { | ||
case: 'unknownAssetId', | ||
value: { | ||
assetId: claimFee.assetId, | ||
amount: claimFee.amount, | ||
}, | ||
}, | ||
}), | ||
); | ||
}, [value]); | ||
|
||
if (!isOneWay) { | ||
return ( | ||
<ActionWrapper title='Two-way swap: unsupported' opaque={value.swapView.case === 'opaque'} /> | ||
); | ||
} | ||
|
||
return ( | ||
<ActionWrapper | ||
title='Swap' | ||
opaque={value.swapView.case === 'opaque'} | ||
infoRows={ | ||
<> | ||
{!!fee && <ActionRow label='Swap Claim fee' info={fee} />} | ||
{!!txId && ( | ||
<ActionRow label='Swap Claim Transaction' info={shorten(txId, 8)} copyText={txId} /> | ||
)} | ||
{unfilled && <ActionRow label='Unfilled Amount' info={unfilled} />} | ||
</> | ||
} | ||
> | ||
{value.swapView.case === 'visible' && swap && ( | ||
<Density slim> | ||
<ValueViewComponent | ||
valueView={swap.input} | ||
priority={density === 'sparse' ? 'primary' : 'tertiary'} | ||
/> | ||
<ArrowRight className='size-3 text-neutral-contrast' /> | ||
<ValueViewComponent | ||
valueView={swap.output} | ||
showValue={showOutput} | ||
priority={density === 'sparse' ? 'primary' : 'tertiary'} | ||
/> | ||
</Density> | ||
)} | ||
</ActionWrapper> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Amount } from '@penumbra-zone/protobuf/penumbra/core/num/v1/num_pb'; | ||
|
||
export const AMOUNT_ZERO = new Amount({ | ||
hi: 0n, | ||
lo: 0n, | ||
}); | ||
|
||
export const AMOUNT_999 = new Amount({ | ||
hi: 0n, | ||
lo: 999n, | ||
}); | ||
|
||
export const AMOUNT_123_456_789 = new Amount({ | ||
hi: 0n, | ||
lo: 123_456_789n, | ||
}); |
Oops, something went wrong.