Skip to content

Commit

Permalink
chore: view asset transactions
Browse files Browse the repository at this point in the history
support opt-in, opt-out, clawback
  • Loading branch information
PatrickDinh authored Apr 16, 2024
1 parent 2c4d520 commit 5eb06c2
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 11 deletions.
11 changes: 6 additions & 5 deletions src/features/common/components/display-asset-amount.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { AssetModel } from '@/features/assets/models'
import { cn } from '../utils'
import Decimal from 'decimal.js'

type Props = {
amount: number | bigint
asset: AssetModel
className?: string
}

export const DisplayAssetAmount = ({ amount, asset }: Props) => {
export const DisplayAssetAmount = ({ amount, asset, className }: Props) => {
// asset decimals value must be from 0 to 19 so it is safe to use .toString() here
const decimals = asset.decimals.toString()
// the amount is uint64, should be safe to be .toString()
const amountAsString = amount.toString()
const amountToDisplay = new Decimal(amount.toString()).div(new Decimal(10).pow(asset.decimals.toString())).toString()

return (
<div>
{new Decimal(amountAsString).div(new Decimal(10).pow(decimals)).toString()} {asset.unitName ?? ''}
<div className={cn(className)}>
{amountToDisplay} {asset.unitName ?? ''}
</div>
)
}
1 change: 1 addition & 0 deletions src/features/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ZERO_ADDRESS = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ'
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<div>
<div
class="relative grid"
style="grid-template-columns: minmax(128px, 128px) repeat(2, 128px); grid-template-rows: repeat(2, 40px);"
>
<div />
<div
class="p-2 flex justify-center"
>
<h1
class="text-l font-semibold"
>
SMO6...ALKU
</h1>
</div>
<div />
<div
class="absolute right-0 -z-10"
style="top: 40px;"
>
<div>
<div
class="p-0"
/>
<div
class="p-0"
style="height: 40px; width: 128px;"
>
<div
class="grid h-full"
style="grid-template-columns: repeat(1, minmax(0, 1fr)); height: 40px;"
>
<div
class="flex justify-center"
>
<div
class="border-muted h-full border-dashed"
style="border-left-width: 2px;"
/>
</div>
</div>
</div>
</div>
</div>
<div
class="p-0 relative pr-8"
>
<div
class="relative h-full p-0 flex items-center px-0"
style="margin-left: 0px;"
>
<div
class="inline"
style="margin-left: 16px;"
>
563MNGE...
</div>
</div>
</div>
<div
class="flex items-center justify-center relative"
data-state="closed"
style="grid-column-start: 2; grid-column-end: 4; color: rgb(126 200 191);"
>
<svg
height="20"
viewBox="0 0 21 21"
width="20"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<g
transform="matrix(1 0 0 1 -153 -143 )"
>
<path
d="M 163.5 143 C 169.38 143 174 147.62 174 153.5 C 174 159.38 169.38 164 163.5 164 C 157.62 164 153 159.38 153 153.5 C 153 147.62 157.62 143 163.5 143 Z "
fill="currentColor"
fill-rule="nonzero"
stroke="none"
/>
</g>
</svg>
<div
style="width: calc(50% - 10px); height: 20px;"
>
<svg
class="relative"
height="19px"
preserveAspectRatio="xMinYMid meet"
style=""
viewBox="159 229 7 10"
width="11px"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<path
d="M 165.8 228.1 L 159.1 234.1 L 165.8 240.1 L 163.5 234.1 L 165.8 228.1 Z"
fill="currentColor"
fill-rule="nonzero"
stroke="none"
/>
</svg>
</div>
<div
class="absolute size-1/2"
style="border-width: 2px; border-radius: 4px; bottom: 1px; right: calc(25% - 4px);"
/>
<div
class="absolute text-foreground right-1/4 w-[40%] flex justify-center"
>
<div
class="w-min pl-1 pr-1 bg-card"
>
0

USDt
</div>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@
class="absolute z-20 bg-card p-2 text-foreground w-20 text-xs"
>
Transfer
<div>
<div
class=""
>
0.3

AKTA
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cn } from '@/features/common/utils'
import { useMemo } from 'react'
import { AssetTransferTransactionModel } from '../models'
import { AssetTransferTransactionModel, AssetTransferTransactionSubType } from '../models'
import { DescriptionList } from '@/features/common/components/description-list'
import { transactionSenderLabel, transactionReceiverLabel, transactionAmountLabel } from './transaction-view-table'
import { DisplayAssetAmount } from '@/features/common/components/display-asset-amount'
Expand All @@ -12,6 +12,7 @@ type Props = {
export const assetLabel = 'Asset'
export const transactionCloseRemainderToLabel = 'Close Remainder To'
export const transactionCloseRemainderAmountLabel = 'Close Remainder Amount'
export const transactionClawbackAddressLabel = 'Clawback From'

export function AssetTransferTransactionInfo({ transaction }: Props) {
const items = useMemo(
Expand All @@ -32,6 +33,18 @@ export function AssetTransferTransactionInfo({ transaction }: Props) {
</a>
),
},
...(transaction.subType === AssetTransferTransactionSubType.Clawback
? [
{
dt: transactionClawbackAddressLabel,
dd: (
<a href="#" className={cn('text-primary underline')}>
{transaction.clawbackFrom}
</a>
),
},
]
: []),
{
dt: assetLabel,
dd: (
Expand Down Expand Up @@ -61,7 +74,15 @@ export function AssetTransferTransactionInfo({ transaction }: Props) {
]
: []),
],
[transaction.sender, transaction.receiver, transaction.asset, transaction.amount, transaction.closeRemainder]
[
transaction.amount,
transaction.asset,
transaction.clawbackFrom,
transaction.closeRemainder,
transaction.receiver,
transaction.sender,
transaction.subType,
]
)

return (
Expand Down
6 changes: 5 additions & 1 deletion src/features/transactions/components/transaction-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cn } from '@/features/common/utils'
import { dateFormatter } from '@/utils/format'
import { DisplayAlgo } from '@/features/common/components/display-algo'
import { useMemo } from 'react'
import { TransactionModel, SignatureType } from '../models'
import { TransactionModel, SignatureType, TransactionType } from '../models'
import { DescriptionList } from '@/features/common/components/description-list'
import { Badge } from '@/features/common/components/badge'
import { BlockLink } from '@/features/blocks/components/block-link'
Expand Down Expand Up @@ -31,6 +31,9 @@ export function TransactionInfo({ transaction }: Props) {
dd: (
<>
{transaction.type}
{transaction.type === TransactionType.AssetTransfer && transaction.subType && (
<Badge variant="outline">{transaction.subType}</Badge>
)}
{transaction.signature?.type === SignatureType.Multi && <Badge variant="outline">Multisig</Badge>}
{transaction.signature?.type === SignatureType.Logic && <Badge variant="outline">LogicSig</Badge>}
</>
Expand Down Expand Up @@ -68,6 +71,7 @@ export function TransactionInfo({ transaction }: Props) {
transaction.id,
transaction.roundTime,
transaction.signature?.type,
transaction.subType,
transaction.type,
]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ describe('asset-transfer-transaction-view-visual', () => {
transactionResult: transactionResultMother['mainnet-JBDSQEI37W5KWPQICT2IGCG2FWMUGJEUYYK3KFKNSYRNAXU2ARUA']().build(),
assetResult: assetResultMother['mainnet-523683256']().build(),
},
{
transactionResult: transactionResultMother['mainnet-563MNGEL2OF4IBA7CFLIJNMBETT5QNKZURSLIONJBTJFALGYOAUA']().build(),
assetResult: assetResultMother['mainnet-312769']().build(),
},
])(
'when rendering transaction $id',
({ transactionResult, assetResult }: { transactionResult: TransactionResult; assetResult: AssetResult }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ const DisplaySelfTransaction = fixedForwardRef(
{transaction.type === TransactionType.Payment && (
<DisplayAlgo className={cn('w-min pl-1 pr-1 bg-card')} amount={transaction.amount} />
)}
{transaction.type === TransactionType.AssetTransfer && (
<DisplayAssetAmount className={cn('w-min pl-1 pr-1 bg-card')} amount={transaction.amount} asset={transaction.asset} />
)}
</div>
</div>
)
Expand Down
27 changes: 27 additions & 0 deletions src/features/transactions/mappers/transaction-mappers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AssetResult, TransactionResult, TransactionSignature } from '@algorandfoundation/algokit-utils/types/indexer'
import {
AssetTransferTransactionModel,
AssetTransferTransactionSubType,
LogicsigModel,
MultisigModel,
PaymentTransactionModel,
Expand All @@ -12,6 +13,7 @@ import { invariant } from '@/utils/invariant'
import { publicKeyToAddress } from '@/utils/publickey-to-addess'
import * as algokit from '@algorandfoundation/algokit-utils'
import { asAsset } from '@/features/assets/mappers/asset-mappers'
import { ZERO_ADDRESS } from '@/features/common/constants'

export const asPaymentTransaction = (transaction: TransactionResult): PaymentTransactionModel => {
invariant(transaction['confirmed-round'], 'confirmed-round is not set')
Expand Down Expand Up @@ -70,9 +72,33 @@ export const asAssetTransferTransaction = (transaction: TransactionResult, asset
invariant(transaction['round-time'], 'round-time is not set')
invariant(transaction['asset-transfer-transaction'], 'asset-transfer-transaction is not set')

const subType = () => {
invariant(transaction['asset-transfer-transaction'], 'asset-transfer-transaction is not set')

if (transaction['asset-transfer-transaction']['close-to']) {
return AssetTransferTransactionSubType.OptOut
}
if (
transaction.sender === transaction['asset-transfer-transaction'].receiver &&
transaction['asset-transfer-transaction'].amount === 0
) {
return AssetTransferTransactionSubType.OptIn
}
if (
transaction.sender === asset.params.clawback &&
transaction['asset-transfer-transaction'].sender &&
transaction['asset-transfer-transaction'].sender !== ZERO_ADDRESS
) {
return AssetTransferTransactionSubType.Clawback
}

undefined
}

return {
id: transaction.id,
type: TransactionType.AssetTransfer,
subType: subType(),
asset: asAsset(asset),
confirmedRound: transaction['confirmed-round'],
roundTime: transaction['round-time'] * 1000,
Expand All @@ -88,5 +114,6 @@ export const asAssetTransferTransaction = (transaction: TransactionResult, asset
}
: undefined,
signature: transformSignature(transaction.signature),
clawbackFrom: transaction['asset-transfer-transaction'].sender,
}
}
9 changes: 9 additions & 0 deletions src/features/transactions/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export enum TransactionType {
AssetTransfer = 'Asset Transfer',
}

export enum AssetTransferTransactionSubType {
OptIn = 'Opt-In',
Clawback = 'Clawback',
OptOut = 'Opt-Out',
}

export type CloseAlgoRemainder = {
to: Address
amount: AlgoAmount
Expand All @@ -36,14 +42,17 @@ export type PaymentTransactionModel = CommonTransactionProperties & {
receiver: Address
amount: AlgoAmount
closeRemainder?: CloseAlgoRemainder
subType?: undefined
}

export type AssetTransferTransactionModel = CommonTransactionProperties & {
type: TransactionType.AssetTransfer
subType?: AssetTransferTransactionSubType
receiver: Address
amount: number | bigint
closeRemainder?: CloseAssetRemainder
asset: AssetModel
clawbackFrom?: Address
}

export type TransactionModel = PaymentTransactionModel | AssetTransferTransactionModel
Expand Down
Loading

0 comments on commit 5eb06c2

Please sign in to comment.