-
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.
Browse files
Browse the repository at this point in the history
* feat(ui): #2053: implement `SwapClaim` action view * chore: changeset * fix(ui): #2053: fix SwapClaim action view * fix: format
- Loading branch information
Showing
10 changed files
with
279 additions
and
50 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@penumbra-zone/getters': minor | ||
'@penumbra-zone/ui': minor | ||
--- | ||
|
||
Implement `SwapClaim` action view |
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 |
---|---|---|
@@ -1,10 +1,141 @@ | ||
import { useMemo } from 'react'; | ||
import { ArrowRight } from 'lucide-react'; | ||
import { isZero } from '@penumbra-zone/types/amount'; | ||
import { shorten } from '@penumbra-zone/types/string'; | ||
import { uint8ArrayToHex } from '@penumbra-zone/types/hex'; | ||
import { getAmount, getMetadata } from '@penumbra-zone/getters/value-view'; | ||
import { SwapClaimView } from '@penumbra-zone/protobuf/penumbra/core/component/dex/v1/dex_pb'; | ||
import { UnknownAction } from './unknown'; | ||
import { | ||
getOutput1Value, | ||
getOutput2Value, | ||
getSwapClaimFee, | ||
getOutputData, | ||
} from '@penumbra-zone/getters/swap-claim-view'; | ||
import { Density } from '../../Density'; | ||
import { ValueViewComponent } from '../../ValueView'; | ||
import { useDensity } from '../../utils/density'; | ||
import { ActionRow } from './action-row'; | ||
import { ActionWrapper } from './wrapper'; | ||
import { parseSwapFees } from './swap'; | ||
import { GetMetadataByAssetId } from '../types'; | ||
import { ValueView } from '@penumbra-zone/protobuf/penumbra/core/asset/v1/asset_pb'; | ||
|
||
export interface SwapClaimActionProps { | ||
value: SwapClaimView; | ||
/** A helper needed to calculate the SwapClaim fees */ | ||
getMetadataByAssetId?: GetMetadataByAssetId; | ||
} | ||
|
||
export const SwapClaimAction = ({ value }: SwapClaimActionProps) => { | ||
return <UnknownAction label='Swap Claim' opaque={value.swapClaimView.case === 'opaque'} />; | ||
/** | ||
* Based on the visibility of the SwapClaim view, retrieves its values from the `value` | ||
* property for 'visible', and from `outputData` for 'opaque'. | ||
*/ | ||
const useSwapClaimValues = ({ value, getMetadataByAssetId }: SwapClaimActionProps) => { | ||
if (value.swapClaimView.case === 'visible') { | ||
const value1 = getOutput1Value.optional(value); | ||
const value2 = getOutput2Value.optional(value); | ||
|
||
return { | ||
value1, | ||
value2, | ||
}; | ||
} | ||
|
||
const outputData = getOutputData.optional(value); | ||
const value1 = | ||
outputData?.lambda1 && | ||
new ValueView({ | ||
valueView: | ||
outputData.tradingPair?.asset1 && getMetadataByAssetId | ||
? { | ||
case: 'knownAssetId', | ||
value: { | ||
amount: outputData.lambda1, | ||
metadata: getMetadataByAssetId(outputData.tradingPair.asset1), | ||
}, | ||
} | ||
: { | ||
case: 'unknownAssetId', | ||
value: { | ||
amount: outputData.lambda1, | ||
assetId: outputData.tradingPair?.asset1, | ||
}, | ||
}, | ||
}); | ||
|
||
const value2 = | ||
outputData?.lambda2 && | ||
new ValueView({ | ||
valueView: | ||
outputData.tradingPair?.asset2 && getMetadataByAssetId | ||
? { | ||
case: 'knownAssetId', | ||
value: { | ||
amount: outputData.lambda2, | ||
metadata: getMetadataByAssetId(outputData.tradingPair.asset2), | ||
}, | ||
} | ||
: { | ||
case: 'unknownAssetId', | ||
value: { | ||
amount: outputData.lambda2, | ||
assetId: outputData.tradingPair?.asset2, | ||
}, | ||
}, | ||
}); | ||
|
||
return { | ||
value1, | ||
value2, | ||
}; | ||
}; | ||
|
||
export const SwapClaimAction = ({ value, getMetadataByAssetId }: SwapClaimActionProps) => { | ||
const density = useDensity(); | ||
|
||
const { value1, value2 } = useSwapClaimValues({ value, getMetadataByAssetId }); | ||
|
||
const amount1 = getAmount.optional(value1); | ||
const amount2 = getAmount.optional(value2); | ||
|
||
const txId = useMemo(() => { | ||
if (value.swapClaimView.case === 'opaque' || !value.swapClaimView.value?.swapTx) { | ||
return undefined; | ||
} | ||
return uint8ArrayToHex(value.swapClaimView.value.swapTx.inner); | ||
}, [value]); | ||
|
||
const fee = useMemo(() => { | ||
const claimFee = getSwapClaimFee.optional(value); | ||
const asset1 = getMetadata.optional(value1); | ||
const asset2 = getMetadata.optional(value2); | ||
return parseSwapFees(claimFee, asset1, asset2, getMetadataByAssetId); | ||
}, [getMetadataByAssetId, value1, value2, value]); | ||
|
||
return ( | ||
<ActionWrapper | ||
title='Swap Claim' | ||
opaque={value.swapClaimView.case === 'opaque'} | ||
infoRows={ | ||
<> | ||
{!!fee && <ActionRow label='Swap Claim Fee' info={fee} />} | ||
{!!txId && <ActionRow label='Swap Transaction' info={shorten(txId, 8)} copyText={txId} />} | ||
</> | ||
} | ||
> | ||
<Density slim> | ||
<ValueViewComponent | ||
valueView={value1} | ||
showValue={amount1 && !isZero(amount1)} | ||
priority={density === 'sparse' ? 'primary' : 'tertiary'} | ||
/> | ||
<ArrowRight className='size-3 text-neutral-contrast' /> | ||
<ValueViewComponent | ||
valueView={value2} | ||
showValue={amount2 && !isZero(amount2)} | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
import { ActionView } from '@penumbra-zone/protobuf/penumbra/core/transaction/v1/transaction_pb'; | ||
import { AssetId, Metadata } from '@penumbra-zone/protobuf/penumbra/core/asset/v1/asset_pb'; | ||
|
||
export type ActionViewType = Exclude<ActionView['actionView']['case'], undefined>; | ||
|
||
export type ActionViewValueType = Exclude<ActionView['actionView']['value'], undefined>; | ||
|
||
export type GetMetadataByAssetId = (assetId: AssetId) => Metadata | undefined; |
Oops, something went wrong.