Skip to content
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

Display redemptions in my activity #570

Merged
merged 10 commits into from
Jul 14, 2023
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { useSubscribeToDepositRevealedEvent } from "./hooks/tbtc/useSubsribeToDe
import {
useSubscribeToOptimisticMintingFinalizedEvent,
useSubscribeToOptimisticMintingRequestedEvent,
useSubscribeToRedemptionRequestedEvent,
} from "./hooks/tbtc"
import { useSentry } from "./hooks/sentry"

Expand All @@ -80,6 +81,7 @@ const Web3EventHandlerComponent = () => {
useSubscribeToDepositRevealedEvent()
useSubscribeToOptimisticMintingFinalizedEvent()
useSubscribeToOptimisticMintingRequestedEvent()
useSubscribeToRedemptionRequestedEvent()

return <></>
}
Expand Down
32 changes: 29 additions & 3 deletions src/components/tBTC/BridgeActivity.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FC, createContext, useContext, ReactElement } from "react"
import { useWeb3React } from "@web3-react/core"
import {
Badge,
BodyMd,
Expand All @@ -18,12 +19,14 @@ import {
import {
BridgeActivityStatus,
BridgeActivity as BridgeActivityType,
UnminBridgeActivityAdditionalData,
} from "../../threshold-ts/tbtc"
import emptyHistoryImageSrcDark from "../../static/images/tBTC-bridge-no-history-dark.svg"
import emptyHistoryImageSrcLight from "../../static/images/tBTC-bridge-no-history-light.svg"
import { InlineTokenBalance } from "../TokenBalance"
import Link from "../Link"
import { OutlineListItem } from "../OutlineListItem"
import { RedemptionDetailsLinkBuilder } from "../../utils/tBTC"

export type BridgeActivityProps = {
data: BridgeActivityType[]
Expand Down Expand Up @@ -97,16 +100,36 @@ export const BridgeActivityData: FC<ListProps> = (props) => {
const ActivityItem: FC<BridgeActivityType> = ({
amount,
status,
depositKey,
activityKey,
bridgeProcess,
additionalData,
txHash,
}) => {
const { account } = useWeb3React()

const link =
bridgeProcess === "unmint"
? RedemptionDetailsLinkBuilder.createFromTxHash(txHash)
.withRedeemer(account!)
.withRedeemerOutputScript(
(additionalData as UnminBridgeActivityAdditionalData)
.redeemerOutputScript
)
.withWalletPublicKeyHash(
(additionalData as UnminBridgeActivityAdditionalData)
.walletPublicKeyHash
)
.build()
: `/tBTC/mint/deposit/${activityKey}`

return (
<ActivityItemWrapper>
<LinkOverlay
as={Link}
textDecoration="none"
_hover={{ textDecoration: "none" }}
color="inherit"
to={`/tBTC/mint/deposit/${depositKey}`}
to={link}
>
<InlineTokenBalance tokenAmount={amount} />
</LinkOverlay>
Expand All @@ -116,7 +139,7 @@ const ActivityItem: FC<BridgeActivityType> = ({
}

const renderActivityItem = (item: BridgeActivityType) => (
<ActivityItem key={item.depositKey} {...item} />
<ActivityItem key={`${item.activityKey}-${item.txHash}`} {...item} />
)

const bridgeActivityStatusToBadgeProps: Record<
Expand All @@ -126,6 +149,9 @@ const bridgeActivityStatusToBadgeProps: Record<
[BridgeActivityStatus.MINTED]: {
colorScheme: "green",
},
[BridgeActivityStatus.UNMINTED]: {
colorScheme: "green",
},
[BridgeActivityStatus.PENDING]: {
colorScheme: "yellow",
},
Expand Down
1 change: 1 addition & 0 deletions src/hooks/tbtc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./useFetchDepositDetails"
export * from "./useFetchRecentDeposits"
export * from "./useFetchTBTCMetrics"
export * from "./useRequestRedemption"
export * from "./useSubscribeToRedemptionRequestedEvent"
51 changes: 51 additions & 0 deletions src/hooks/tbtc/useSubscribeToRedemptionRequestedEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useWeb3React } from "@web3-react/core"
import { useSubscribeToContractEvent } from "../../web3/hooks"
import { isSameETHAddress } from "../../web3/utils"
import { useAppDispatch } from "../store"
import { useBridgeContract } from "./useBridgeContract"
import { tbtcSlice } from "../../store/tbtc"
import { BigNumber, Event } from "ethers"
import { useThreshold } from "../../contexts/ThresholdContext"
import { fromSatoshiToTokenPrecision } from "../../threshold-ts/utils"

export const useSubscribeToRedemptionRequestedEvent = () => {
const contract = useBridgeContract()
const dispatch = useAppDispatch()
const { account } = useWeb3React()
const threshold = useThreshold()

useSubscribeToContractEvent(
contract,
"RedemptionRequested",
//@ts-ignore
async (
walletPublicKeyHash: string,
redeemerOutputScript: string,
redeemer: string,
requestedAmount: BigNumber,
treasuryFee: BigNumber,
txMaxFee: BigNumber,
event: Event
) => {
if (!account || !isSameETHAddress(redeemer, account)) return

const redemptionKey = threshold.tbtc.buildRedemptionKey(
walletPublicKeyHash,
redeemerOutputScript
)

dispatch(
tbtcSlice.actions.redemptionRequested({
// TODO: Take into account fees, see
// https://github.com/threshold-network/token-dashboard/pull/569
amount: fromSatoshiToTokenPrecision(requestedAmount).toString(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not forget about this TODO

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

txHash: event.transactionHash,
redemptionKey,
blockNumber: event.blockNumber,
additionalData: { redeemerOutputScript, walletPublicKeyHash },
})
)
},
[null, null, account]
)
}
1 change: 1 addition & 0 deletions src/hooks/tbtc/useSubsribeToDepositRevealedEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const useSubscribeToDepositRevealedEvent = () => {
txHash: event.transactionHash,
depositor: depositor,
depositKey: depositKeyFromEvent,
blockNumber: event.blockNumber,
})
)
},
Expand Down
78 changes: 74 additions & 4 deletions src/store/tbtc/tbtcSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { createSlice } from "@reduxjs/toolkit"
import { PayloadAction } from "@reduxjs/toolkit/dist/createAction"
import { MintingStep, TbtcStateKey, TbtcState } from "../../types/tbtc"
import { UpdateStateActionPayload } from "../../types/state"
import { BridgeActivityStatus, BridgeActivity } from "../../threshold-ts/tbtc"
import {
BridgeActivityStatus,
BridgeActivity,
UnminBridgeActivityAdditionalData,
} from "../../threshold-ts/tbtc"
import { featureFlags } from "../../constants"
import { startAppListening } from "../listener"
import {
Expand Down Expand Up @@ -54,9 +58,10 @@ export const tbtcSlice = createSlice({
amount: string
depositor: string
txHash: string
blockNumber: number
}>
) => {
const { amount, txHash, depositKey } = action.payload
const { amount, txHash, depositKey, blockNumber } = action.payload
const history = state.bridgeActivity.data
const { itemToUpdate } = findActivityByDepositKey(history, depositKey)

Expand All @@ -66,7 +71,14 @@ export const tbtcSlice = createSlice({

// Add item only if there is no item with the same deposit key.
state.bridgeActivity.data = [
{ amount, txHash, status: BridgeActivityStatus.PENDING, depositKey },
{
amount,
txHash,
status: BridgeActivityStatus.PENDING,
activityKey: depositKey,
bridgeProcess: "mint",
blockNumber,
},
...state.bridgeActivity.data,
]
},
Expand Down Expand Up @@ -108,6 +120,45 @@ export const tbtcSlice = createSlice({
}
}>
) => {},
redemptionRequested: (
state,
action: PayloadAction<{
redemptionKey: string
blockNumber: number
amount: string
txHash: string
additionalData: UnminBridgeActivityAdditionalData
}>
) => {
const {
payload: { amount, redemptionKey, blockNumber, txHash, additionalData },
} = action

const { itemToUpdate } = findRedemptionActivity(
state.bridgeActivity.data,
redemptionKey,
txHash
)

// Do not update an array if there is already an item with the same
// redemption key and transaction hash- just in case duplicated Ethereum
// events.
if (itemToUpdate) return

// Add item only if there is no item with the same deposit key.
state.bridgeActivity.data = [
{
amount,
txHash,
status: BridgeActivityStatus.PENDING,
activityKey: redemptionKey,
bridgeProcess: "unmint",
blockNumber,
additionalData,
},
...state.bridgeActivity.data,
]
},
},
})

Expand All @@ -116,7 +167,26 @@ function findActivityByDepositKey(
depositKey: string
) {
const activityIndexItemToUpdate = bridgeActivities.findIndex(
(item) => item.depositKey === depositKey
(item) => item.activityKey === depositKey
)

if (activityIndexItemToUpdate < 0) return { index: -1, itemToUpdate: null }

const activityItemToUpdate = bridgeActivities[activityIndexItemToUpdate]

return {
index: activityIndexItemToUpdate,
itemToUpdate: activityItemToUpdate,
}
}

function findRedemptionActivity(
Copy link
Contributor

@michalsmiarowski michalsmiarowski Jul 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you agree with #570 (comment) then we might also rename this one to findRedemptionBridgeActivity

bridgeActivities: BridgeActivity[],
redemptionKey: string,
txHash: string
) {
const activityIndexItemToUpdate = bridgeActivities.findIndex(
(item) => item.activityKey === redemptionKey && item.txHash === txHash
)

if (activityIndexItemToUpdate < 0) return { index: -1, itemToUpdate: null }
Expand Down
Loading
Loading