From 1e4e3ec09a0e1113a17027b6e2963ca1fe0aeb5f Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Thu, 18 Apr 2024 15:48:20 +0200 Subject: [PATCH 1/2] Use lazy loading for tbtc sdk initialization Here we use lazy loading for tbtc sdk initialization in our threshold-ts lib. Instead of keeping the sdk object we actually store the promise itself in `_sdkPromise` property. This promise is set during the construction of the SDK class and is meant to be resolved once the SDK is fully initialized. The promise is used to ensure that the SDK is initialized only once and that all subsequent retrievals of the SDK instance await this promise, thereby ensuring that the SDK is ready for use before any operations are performed. The promise also facilitates updating the SDK instance dynamically: if a new initialization is triggered (e.g., when a user logs in and provides a new signer), it ensures that the new SDK object replaces any previously pending SDK object, even if the original promise has not yet resolved. To retrieve the SDK object, use the `getSdk()` method. This method will either return the already resolved SDK object or wait until the promise resolves before returning the SDK. Additionally I've changed the `getTransactionConfirmations` method implementation - it does not have to use SDK. --- src/threshold-ts/tbtc/index.ts | 81 +++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/src/threshold-ts/tbtc/index.ts b/src/threshold-ts/tbtc/index.ts index 3aaa0921f..d03759a3d 100644 --- a/src/threshold-ts/tbtc/index.ts +++ b/src/threshold-ts/tbtc/index.ts @@ -189,8 +189,6 @@ export interface ITBTC { readonly tokenContract: Contract - readonly sdk: SDK | undefined - readonly deposit: Deposit | undefined /** @@ -199,12 +197,11 @@ export interface ITBTC { * connected) or Signer (if wallet is connected). * @param account Connected ethereum address (optional, needed only if user * connected his wallet). - * @returns Instance of the TBTC class from tbtc-v2.ts lib */ initializeSdk( providerOrSigner: providers.Provider | Signer, account?: string - ): Promise + ): Promise /** * Initiates a Deposit object from bitcoin recovery address. * @param btcRecoveryAddress The bitcoin address in which the user will @@ -424,7 +421,26 @@ export class TBTC implements ITBTC { private _bitcoinConfig: BitcoinConfig private readonly _satoshiMultiplier = BigNumber.from(10).pow(10) private _redemptionTreasuryFeeDivisor: BigNumber | undefined - private _sdk: SDK | undefined + + /** + * Holds the promise for the asynchronously initialized SDK instance. + * This promise is set during the construction of the SDK class and is meant + * to be resolved once the SDK is fully initialized. The promise is used to + * ensure that the SDK is initialized only once and that all subsequent + * retrievals of the SDK instance await this promise, thereby ensuring that + * the SDK is ready for use before any operations are performed. + * + * The promise also facilitates updating the SDK instance dynamically: if a + * new initialization is triggered (e.g., when a user logs in and provides a + * new signer), it ensures that the new SDK object replaces any previously + * pending SDK object, even if the original promise has not yet resolved. + * + * To retrieve the SDK object, use the `getSdk()` method. This method will + * either return the already resolved SDK object or wait until the promise + * resolves before returning the SDK. + */ + + private _sdkPromise: Promise private _deposit: Deposit | undefined constructor( @@ -489,9 +505,12 @@ export class TBTC implements ITBTC { this._multicall = multicall this._ethereumConfig = ethereumConfig this._bitcoinConfig = bitcoinConfig + this._sdkPromise = new Promise((resolve) => resolve(undefined)) + + this.initializeSdk(providerOrSigner, account) } - async initializeSdk( + async _initializeSdk( providerOrSigner: providers.Provider | Signer, account?: string ): Promise { @@ -512,12 +531,11 @@ export class TBTC implements ITBTC { ? getSepoliaDevelopmentContracts(signer) : await loadEthereumContracts(signer, ethereumNetwork) - this._sdk = await SDK.initializeCustom(tbtcContracts, this._bitcoinClient) + const sdk = await SDK.initializeCustom(tbtcContracts, this._bitcoinClient) - depositorAddress && - this._sdk?.deposits.setDefaultDepositor(depositorAddress) + depositorAddress && sdk.deposits.setDefaultDepositor(depositorAddress) - return this._sdk + return sdk } const initializeFunction = @@ -525,13 +543,20 @@ export class TBTC implements ITBTC { ? SDK.initializeMainnet : SDK.initializeSepolia - this._sdk = await initializeFunction(signer) + const sdk = await initializeFunction(signer) - return this._sdk + return sdk } - get sdk(): SDK | undefined { - return this._sdk + async initializeSdk( + providerOrSigner: providers.Provider | Signer, + account?: string | undefined + ): Promise { + try { + this._sdkPromise = this._initializeSdk(providerOrSigner, account) + } catch (err) { + throw new Error(`Something went wrong when initializing tbtc sdk: ${err}`) + } } get deposit(): Deposit | undefined { @@ -558,9 +583,16 @@ export class TBTC implements ITBTC { return this._tokenContract } + private _getSdk = async (): Promise => { + const sdk = await this._sdkPromise + if (!sdk) throw new EmptySdkObjectError() + + return sdk + } + initiateDeposit = async (btcRecoveryAddress: string): Promise => { - if (!this._sdk) throw new EmptySdkObjectError() - this._deposit = await this._sdk.deposits.initiateDeposit(btcRecoveryAddress) + const sdk = await this._getSdk() + this._deposit = await sdk.deposits.initiateDeposit(btcRecoveryAddress) return this._deposit } @@ -571,7 +603,7 @@ export class TBTC implements ITBTC { initiateDepositFromDepositScriptParameters = async ( depositScriptParameters: DepositScriptParameters ): Promise => { - if (!this._sdk) throw new EmptySdkObjectError() + const sdk = await this._getSdk() const { blindingFactor, walletPublicKeyHash, @@ -590,8 +622,8 @@ export class TBTC implements ITBTC { this._deposit = await Deposit.fromReceipt( depositReceipt, - this._sdk.tbtcContracts, - this._sdk.bitcoinClient + sdk.tbtcContracts, + sdk.bitcoinClient ) return this._deposit } @@ -695,8 +727,8 @@ export class TBTC implements ITBTC { } getRevealedDeposit = async (utxo: BitcoinUtxo): Promise => { - if (!this._sdk) throw new EmptySdkObjectError() - const deposit = await this._sdk.tbtcContracts.bridge.deposits( + const sdk = await this._getSdk() + const deposit = await sdk.tbtcContracts.bridge.deposits( utxo.transactionHash, utxo.outputIndex ) @@ -709,9 +741,8 @@ export class TBTC implements ITBTC { getTransactionConfirmations = async ( transactionHash: string ): Promise => { - if (!this._sdk) throw new EmptySdkObjectError() const bitcoinTransactionHash = BitcoinTxHash.from(transactionHash) - return this._sdk.bitcoinClient.getTransactionConfirmations( + return this._bitcoinClient.getTransactionConfirmations( bitcoinTransactionHash ) } @@ -1010,7 +1041,7 @@ export class TBTC implements ITBTC { walletPublicKey: string } }> => { - if (!this._sdk) throw new EmptySdkObjectError() + const sdk = await this._getSdk() if (this._isValidBitcoinAddressForRedemption(btcAddress)) { throw new Error( @@ -1019,7 +1050,7 @@ export class TBTC implements ITBTC { } const { targetChainTxHash, walletPublicKey } = - await this._sdk.redemptions.requestRedemption( + await sdk.redemptions.requestRedemption( btcAddress, BigNumber.from(amount) ) From c4726957457d839c62e96f485e19158b7d8840c0 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Thu, 18 Apr 2024 15:53:55 +0200 Subject: [PATCH 2/2] Remove IsSdkInitializingContext The context is not needed anymore when we've implemented a lazy loading in 1e4e3ec09a0e1113a17027b6e2963ca1fe0aeb5f. --- src/components/SubmitTxButton.tsx | 4 +- src/contexts/ThresholdContext.tsx | 74 +------------------ .../useRequestEthereumAccount.ts | 3 - src/hooks/tbtc/useFetchRedemptionDetails.ts | 9 +-- src/hooks/useFetchTvl.ts | 5 +- src/hooks/useIsActive.ts | 3 - src/pages/tBTC/Bridge/Mint.tsx | 56 +++++--------- .../tBTC/Bridge/Minting/MintingFlowRouter.tsx | 18 +---- src/pages/tBTC/Bridge/Unmint.tsx | 9 +-- 9 files changed, 31 insertions(+), 150 deletions(-) diff --git a/src/components/SubmitTxButton.tsx b/src/components/SubmitTxButton.tsx index c919933ea..c8306fc20 100644 --- a/src/components/SubmitTxButton.tsx +++ b/src/components/SubmitTxButton.tsx @@ -1,7 +1,6 @@ import { FC } from "react" import { Button, ButtonProps } from "@chakra-ui/react" import { useIsActive } from "../hooks/useIsActive" -import { useIsTbtcSdkInitializing } from "../contexts/ThresholdContext" import { useConnectWallet } from "../hooks/useConnectWallet" interface Props extends ButtonProps { @@ -15,14 +14,13 @@ const SubmitTxButton: FC = ({ ...buttonProps }) => { const { isActive } = useIsActive() - const { isSdkInitializedWithSigner } = useIsTbtcSdkInitializing() const connectWallet = useConnectWallet() const onConnectWalletClick = () => { connectWallet() } - if (isActive && isSdkInitializedWithSigner) { + if (isActive) { return (