Skip to content

Commit d5550a8

Browse files
Merge pull request #843 from threshold-network/feat/add-cross-chain-redemption-support
feat: update components to add crosschain redemption
2 parents 4cf723c + 7e9dd06 commit d5550a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4228
-288
lines changed

craco.config.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,25 @@ module.exports = {
5353
}),
5454
]
5555

56-
// Add node polyfills (webpack 4 style)
57-
webpackConfig.node = {
58-
...webpackConfig.node,
59-
crypto: true,
60-
stream: true,
61-
buffer: true,
62-
}
63-
64-
// Ensure starknet is properly resolved
56+
// Polyfill node modules for webpack 4
6557
webpackConfig.resolve.alias = {
6658
...webpackConfig.resolve.alias,
67-
starknet: require.resolve("starknet"),
6859
crypto: require.resolve("crypto-browserify"),
6960
stream: require.resolve("stream-browserify"),
70-
buffer: require.resolve("buffer/"),
61+
buffer: require.resolve("buffer"),
62+
starknet: require.resolve("starknet"),
7163
}
7264

65+
// Treat .mjs files in node_modules as javascript/auto so CRA's webpack 4 can
66+
// properly handle ESM-only packages. Without this, imports from deps like
67+
// starknet.js, multiformats, uint8arrays (and transitively @keep-network/tbtc-v2.ts)
68+
// can fail with "Module parse failed" or missing named export errors.
69+
webpackConfig.module.rules.push({
70+
test: /\.mjs$/,
71+
include: /node_modules/,
72+
type: "javascript/auto",
73+
})
74+
7375
return webpackConfig
7476
},
7577
},

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@keep-network/keep-ecdsa": "1.8.0",
1919
"@keep-network/random-beacon": "2.0.0",
2020
"@keep-network/tbtc": "1.1.0",
21-
"@keep-network/tbtc-v2.ts": "^2.8.0",
21+
"@keep-network/tbtc-v2.ts": "3.0.0",
2222
"@ledgerhq/connect-kit-loader": "1.1.8",
2323
"@ledgerhq/wallet-api-client": "^1.2.0",
2424
"@ledgerhq/wallet-api-client-react": "^1.1.1",
@@ -119,6 +119,8 @@
119119
},
120120
"devDependencies": {
121121
"@babel/plugin-proposal-logical-assignment-operators": "^7.20.7",
122+
"@babel/plugin-proposal-private-methods": "^7.18.6",
123+
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
122124
"@babel/plugin-transform-class-properties": "^7.22.5",
123125
"@chakra-ui/cli": "2",
124126
"@craco/craco": "6.4.5",

src/components/Modal/TransactionModal/TransactionIsPending.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import ViewInBlockExplorer from "../../ViewInBlockExplorer"
1212
import { ExplorerDataType } from "../../../networks/enums/networks"
1313
import { useWeb3React } from "@web3-react/core"
1414
import { useNonEVMConnection } from "../../../hooks/useNonEVMConnection"
15+
import withBaseModal from "../withBaseModal"
16+
import { BaseModalProps } from "../../../types"
1517

16-
interface Props {
18+
interface Props extends BaseModalProps {
1719
transactionHash: string
1820
}
1921

@@ -55,4 +57,4 @@ const TransactionIsPending: FC<Props> = ({ transactionHash }) => {
5557
)
5658
}
5759

58-
export default TransactionIsPending
60+
export default withBaseModal(TransactionIsPending)

src/components/Modal/tBTC/InitiateUnminting.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,21 @@ const InitiateUnmintingBase: FC<InitiateUnmintingProps> = ({
4949
const { estimatedBTCAmount, thresholdNetworkFee } =
5050
useRedemptionEstimatedFees(unmintAmount)
5151
const threshold = useThreshold()
52+
const isCrossChain = threshold.config.crossChain.isCrossChain
5253

5354
const onSuccess: OnSuccessCallback = (receipt, additionalParams) => {
5455
//@ts-ignore
55-
const { walletPublicKey } = additionalParams
56-
if (walletPublicKey) {
57-
navigate(
58-
buildRedemptionDetailsLink(
59-
receipt.transactionHash,
60-
account!,
61-
walletPublicKey,
62-
btcAddress,
63-
threshold.tbtc.bitcoinNetwork
64-
)
65-
)
56+
const { walletPublicKey, chainName } = additionalParams
57+
const link = buildRedemptionDetailsLink(
58+
account!,
59+
btcAddress,
60+
threshold.tbtc.bitcoinNetwork,
61+
receipt.transactionHash,
62+
walletPublicKey ?? undefined,
63+
chainName ?? undefined
64+
)
65+
if (link) {
66+
navigate(link)
6667
}
6768
closeModal()
6869
}

src/components/Navbar/NetworkButton.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ const getNetworkIcon = (chainId: number, colorMode: string): NetworkIconMap => {
5656
icon: <Icon as={ethereumLogo} boxSize="5" />,
5757
bg: grayBackground,
5858
},
59-
// [SupportedChainIds.ArbitrumSepolia]: {
60-
// icon: <Icon as={Arbitrum} boxSize="5" />,
61-
// bg: grayBackground,
62-
// },
63-
// [SupportedChainIds.BaseSepolia]: {
64-
// icon: <Icon as={Base} boxSize="5" />,
65-
// bg: "blue.500",
66-
// },
59+
[SupportedChainIds.ArbitrumSepolia]: {
60+
icon: <Icon as={Arbitrum} boxSize="5" />,
61+
bg: grayBackground,
62+
},
63+
[SupportedChainIds.BaseSepolia]: {
64+
icon: <Icon as={Base} boxSize="5" />,
65+
bg: "blue.500",
66+
},
6767
}),
6868
}
6969

src/components/ViewInBlockExplorer.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ const ViewInBlockExplorer: FC<ViewInBlockExplorerProps> = ({
6464
// contract. For those cases in particular, the connected chainId
6565
// should be passed as a prop as ethereumNetworkChainId.
6666
const { chainId } = useIsActive()
67-
const explorerChainId =
68-
ethereumNetworkChainId ?? getMainnetOrTestnetChainId(chainId)
67+
const explorerChainId = ethereumNetworkChainId ?? chainId
6968

7069
const link = createLinkToBlockExplorerForChain[chain](
7170
id,

src/components/tBTC/BridgeActivity.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,23 @@ const ActivityItem: FC<BridgeActivityType> = ({
113113

114114
const link =
115115
bridgeProcess === "unmint"
116-
? RedemptionDetailsLinkBuilder.createFromTxHash(txHash)
117-
.withRedeemer(account!)
118-
.withRedeemerOutputScript(
119-
(additionalData as UnmintBridgeActivityAdditionalData)
120-
.redeemerOutputScript
121-
)
122-
.withWalletPublicKeyHash(
123-
(additionalData as UnmintBridgeActivityAdditionalData)
124-
.walletPublicKeyHash
125-
)
126-
.build()
116+
? (() => {
117+
const unmintData =
118+
additionalData as UnmintBridgeActivityAdditionalData
119+
const builder = RedemptionDetailsLinkBuilder.createFromTxHash(txHash)
120+
.withRedeemer(account!)
121+
.withRedeemerOutputScript(unmintData.redeemerOutputScript)
122+
123+
// For cross-chain redemptions, add chainName
124+
// For L1 redemptions, add walletPublicKeyHash
125+
if (unmintData.chainName) {
126+
builder.withChainName(unmintData.chainName)
127+
} else {
128+
builder.withWalletPublicKeyHash(unmintData.walletPublicKeyHash)
129+
}
130+
131+
return builder.build()
132+
})()
127133
: `/tBTC/mint/deposit/${activityKey}`
128134

129135
return (

src/contexts/ThresholdContext.tsx

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
import { createContext, FC, useContext, useEffect, useRef } from "react"
1+
import {
2+
createContext,
3+
FC,
4+
useContext,
5+
useEffect,
6+
useRef,
7+
useState,
8+
} from "react"
29
import { getThresholdLibProvider, threshold } from "../utils/getThresholdLib"
310
import { useLedgerLiveApp } from "./LedgerLiveAppContext"
411
import { useIsActive } from "../hooks/useIsActive"
512
import { useIsEmbed } from "../hooks/useIsEmbed"
613
import { getEthereumDefaultProviderChainId } from "../utils/getEnvVariable"
714
import { useWeb3React } from "@web3-react/core"
815
import { ChainName } from "../threshold-ts/types"
9-
import { isL2Network } from "../networks/utils"
16+
import {
17+
getEthereumNetworkNameFromChainId,
18+
isL2Network,
19+
} from "../networks/utils"
1020
import { useNonEVMConnection } from "../hooks/useNonEVMConnection"
1121

1222
const defaultCrossChainConfig = {
@@ -22,6 +32,7 @@ export const useThreshold = () => {
2232
}
2333

2434
export const ThresholdProvider: FC = ({ children }) => {
35+
const [thresholdState, setThresholdState] = useState(threshold)
2536
const { library } = useWeb3React()
2637
const hasThresholdLibConfigBeenUpdated = useRef(false)
2738
const { ledgerLiveAppEthereumSigner } = useLedgerLiveApp()
@@ -30,6 +41,13 @@ export const ThresholdProvider: FC = ({ children }) => {
3041
useNonEVMConnection()
3142
const { isEmbed } = useIsEmbed()
3243

44+
useEffect(() => {
45+
const unsubscribe = threshold.subscribe(() =>
46+
setThresholdState(Object.create(threshold))
47+
)
48+
return unsubscribe
49+
}, [])
50+
3351
useEffect(() => {
3452
if (isActive && chainId) {
3553
threshold.updateConfig({
@@ -44,39 +62,39 @@ export const ThresholdProvider: FC = ({ children }) => {
4462
bitcoin: threshold.config.bitcoin,
4563
crossChain: {
4664
...defaultCrossChainConfig,
47-
chainName: isL2Network(chainId) ? ChainName.Ethereum : null,
65+
chainName: getEthereumNetworkNameFromChainId(chainId) as ChainName,
4866
isCrossChain: isL2Network(chainId),
4967
},
5068
})
5169
hasThresholdLibConfigBeenUpdated.current = true
5270
}
5371

54-
if (!isActive && hasThresholdLibConfigBeenUpdated.current) {
72+
if (isNonEVMActive) {
5573
threshold.updateConfig({
56-
ethereum: {
57-
...threshold.config.ethereum,
58-
ethereumProviderOrSigner: getThresholdLibProvider(),
59-
account: undefined,
60-
chainId: getEthereumDefaultProviderChainId(),
61-
},
74+
ethereum: threshold.config.ethereum,
6275
bitcoin: threshold.config.bitcoin,
6376
crossChain: {
64-
...threshold.config.crossChain,
77+
isCrossChain: true,
78+
chainName: nonEVMChainName as Exclude<ChainName, ChainName.Ethereum>,
79+
nonEVMProvider: nonEVMProvider,
6580
},
6681
})
67-
hasThresholdLibConfigBeenUpdated.current = false
6882
}
6983

70-
if (isNonEVMActive) {
84+
if (!isActive && hasThresholdLibConfigBeenUpdated.current) {
7185
threshold.updateConfig({
72-
ethereum: threshold.config.ethereum,
86+
ethereum: {
87+
...threshold.config.ethereum,
88+
ethereumProviderOrSigner: getThresholdLibProvider(),
89+
account: undefined,
90+
chainId: undefined,
91+
},
7392
bitcoin: threshold.config.bitcoin,
7493
crossChain: {
75-
isCrossChain: true,
76-
chainName: nonEVMChainName as Exclude<ChainName, ChainName.Ethereum>,
77-
nonEVMProvider: nonEVMProvider,
94+
...defaultCrossChainConfig,
7895
},
7996
})
97+
hasThresholdLibConfigBeenUpdated.current = false
8098
}
8199
}, [
82100
isActive,
@@ -89,7 +107,7 @@ export const ThresholdProvider: FC = ({ children }) => {
89107
])
90108

91109
return (
92-
<ThresholdContext.Provider value={threshold}>
110+
<ThresholdContext.Provider value={thresholdState}>
93111
{children}
94112
</ThresholdContext.Provider>
95113
)

src/hooks/tbtc/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
export * from "./useFetchDepositDetails"
2+
export * from "./useFetchTBTCMetrics"
23
export * from "./useFetchRecentDeposits"
34
export * from "./useFetchTBTCMetrics"
45
export * from "./useRedemptionEstimatedFees"
56
export * from "./useRequestRedemption"
67
export * from "./useRevealDepositTransaction"
8+
export * from "./useApproveL2TBTCToken"
79
export * from "./useSubscribeToOptimisticMintingFinalizedEvent"
810
export * from "./useSubscribeToOptimisticMintingRequestedEvent"
911
export * from "./useSubscribeToRedemptionRequestedEvent"
@@ -13,3 +15,7 @@ export * from "./useTBTCVaultContract"
1315
export * from "./useSubscribeToRedemptionsCompletedEvent"
1416
export * from "./useFindRedemptionInBitcoinTx"
1517
export * from "./useStarknetTBTCBalance"
18+
export * from "./useFetchCrossChainRedemptionDetails"
19+
export * from "./useFetchVaaFromTxHash"
20+
export * from "./useFetchL2RedemptionRequestedEvent"
21+
export * from "./useSubscribeToL1BitcoinRedeemerRedemptionRequestedEvent"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useThreshold } from "../../contexts/ThresholdContext"
2+
import {
3+
OnErrorCallback,
4+
OnSuccessCallback,
5+
useSendTransactionFromFn,
6+
} from "../../web3/hooks"
7+
8+
export const useApproveL2TBTCToken = (
9+
onSuccess?: OnSuccessCallback,
10+
onError?: OnErrorCallback
11+
) => {
12+
const threshold = useThreshold()
13+
const pendingText =
14+
"Approving tBTC for cross-chain redemption. Please sign in your wallet."
15+
16+
return useSendTransactionFromFn(
17+
threshold.tbtc.approveL2TBTCToken,
18+
onSuccess,
19+
onError,
20+
pendingText
21+
)
22+
}

0 commit comments

Comments
 (0)