Skip to content

Commit

Permalink
Use lazy loading for tbtc sdk initialization
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
michalsmiarowski committed Apr 18, 2024
1 parent 6441d90 commit 1e4e3ec
Showing 1 changed file with 56 additions and 25 deletions.
81 changes: 56 additions & 25 deletions src/threshold-ts/tbtc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ export interface ITBTC {

readonly tokenContract: Contract

readonly sdk: SDK | undefined

readonly deposit: Deposit | undefined

/**
Expand All @@ -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<SDK>
): Promise<void>
/**
* Initiates a Deposit object from bitcoin recovery address.
* @param btcRecoveryAddress The bitcoin address in which the user will
Expand Down Expand Up @@ -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<SDK | undefined>
private _deposit: Deposit | undefined

constructor(
Expand Down Expand Up @@ -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<SDK> {
Expand All @@ -512,26 +531,32 @@ 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 =
this.bitcoinNetwork === BitcoinNetwork.Mainnet
? 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<void> {
try {
this._sdkPromise = this._initializeSdk(providerOrSigner, account)
} catch (err) {
throw new Error(`Something went wrong when initializing tbtc sdk: ${err}`)
}
}

get deposit(): Deposit | undefined {
Expand All @@ -558,9 +583,16 @@ export class TBTC implements ITBTC {
return this._tokenContract
}

private _getSdk = async (): Promise<SDK> => {
const sdk = await this._sdkPromise
if (!sdk) throw new EmptySdkObjectError()

return sdk
}

initiateDeposit = async (btcRecoveryAddress: string): Promise<Deposit> => {
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
}

Expand All @@ -571,7 +603,7 @@ export class TBTC implements ITBTC {
initiateDepositFromDepositScriptParameters = async (
depositScriptParameters: DepositScriptParameters
): Promise<Deposit> => {
if (!this._sdk) throw new EmptySdkObjectError()
const sdk = await this._getSdk()
const {
blindingFactor,
walletPublicKeyHash,
Expand All @@ -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
}
Expand Down Expand Up @@ -695,8 +727,8 @@ export class TBTC implements ITBTC {
}

getRevealedDeposit = async (utxo: BitcoinUtxo): Promise<DepositRequest> => {
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
)
Expand All @@ -709,9 +741,8 @@ export class TBTC implements ITBTC {
getTransactionConfirmations = async (
transactionHash: string
): Promise<number> => {
if (!this._sdk) throw new EmptySdkObjectError()
const bitcoinTransactionHash = BitcoinTxHash.from(transactionHash)
return this._sdk.bitcoinClient.getTransactionConfirmations(
return this._bitcoinClient.getTransactionConfirmations(
bitcoinTransactionHash
)
}
Expand Down Expand Up @@ -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(
Expand All @@ -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)
)
Expand Down

0 comments on commit 1e4e3ec

Please sign in to comment.