Skip to content

Commit

Permalink
General revamp of the typescript library (#705)
Browse files Browse the repository at this point in the history
Closes: #698

Here we present a comprehensive refactoring of the tBTC v2 typescript
library (a.k.a. typescript SDK). So far, the library was basically a bag
of various utility functions, and the responsibility of using them
correctly was on the library clients' side. This approach was enough for
the first phases of protocol development where the library was used
mainly for internal purposes. However, as the protocol becomes more
mature, it makes sense to encourage external integrators. This, in turn,
requires us to improve the developer experience provided by the SDK and
reduce the overhead for users. This pull request aims to achieve that
goal.

The initial plan was to open several PRs one after another but, given
the fact that #695 was
happening simultaneously and had precedence, it was easier to track
progress and resolve conflicts within a single pull request. Because of
the size, I strongly recommend reviewing commit by commit. The history
of changes clearly shows all the steps that were taken. Worth noting
that there are very few changes in the logic itself. Most of them are
file/directory structure changes, renames, and public API improvements.
Here is a detailed description of specific steps:

### Rework of the file and directory structure

So far, the file structure of the library was flat and grouped related
functions into files like `bitcoin.ts` or `deposit.ts`. This quickly led
to poor readability and encapsulation. The new approach uses a
hierarchical approach dividing code into two distinct categories:
- Shared libraries living under `lib` directory
- Feature services living under `services` directory

#### Shared libraries

This category groups all code components that are used across different
features. Specific modules are:
- `lib/bitcoin`: Contains all interfaces and utilities necessary to
interact with the Bitcoin chain
- `lib/contracts`: Provides chain-agnostic interfaces allowing to
interact with tBTC v2 smart contracts
- `lib/electrum`: Contains an Electrum-based implementation of the
Bitcoin client
- `lib/ethereum`: Provides implementations of tBTC v2 smart contract
interfaces for Ethereum chain
- `lib/utils`: Holds some general utility functions

Each aforementioned module contains an `index.ts` file that re-exports
components from specific sub-modules in order to flatten import paths
used by library clients.

#### Feature services

This category holds services providing access to specific features of
the tBTC v2 system:
- `services/deposits`: Provides access to the tBTC v2 deposit flow for
BTC depositors through the `DepositsService` component
- `services/redemptions`: Provides access to the tBTC v2 redemption flow
for TBTC redeemers through the `RedemptionsService` component
- `services/maintenance`: Provides access to authorized maintenance
actions for maintainers (e.g. optimistic minting guardians) through the
`MaintenanceService` component

Just as for shared libraries, each module contains an `index.ts` that
re-exports all exported components from specific sub-modules.

### Provide a simple entry point with embedded chain configurations

So far, the library has not provided any unified entry point that could
be used by external clients. The root `index.ts` just exported the most
important components without any further guidance. Here we aim to change
that by introducing the `TBTC` entry point class. The main purpose of it
is to provide some static functions allowing to quickly initialize the
SDK and expose specific feature services in a simple way. As for now,
the `TBTC` component can be initialized using the following functions:
- `initializeMainnet` which initializes the SDK to point tBTC v2
contracts on Ethereum and use mainnet as Bitcoin network
- `initializeGoerli` which initializes the SDK to point tBTC v2
contracts on Goerli and use testnet as Bitcoin network
- `initializeCustom` which allows using custom tBTC v2 contracts (e.g.
local) and use an arbitrary Bitcoin network (e.g. regtest or simnet)

Once initialized, the `TBTC` component provides easy access to specific
feature services. To address unforeseen needs, it also gives low-level
direct access to the underlying tBTC v2 smart contracts and the Bitcoin
client:

```
// Initialize SDK
const signer = (...) 
const sdk = await TBTC.initializeMainnet(signer) 

// Access feature services
sdk.deposits.(...)
sdk.redemptions.(...)

// Access tBTC v2 smart contracts and Bitcoin client directly
sdk.tbtcContracts.bridge.(...)
sdk.bitcoinClient.(...)
```

### Other changes

Apart from the ones mentioned above, there were other important changes
that had to be made. First and foremost, this PR integrates `bcoin`
removal done as part of
#695. The integration was
achieved by applying changes from specific PRs in separate commits here.
Secondly, the unit tests file structure was adjusted to reflect the new
approach with `lib` and `services` top-level directories.

### Usage examples

Changes made as part of this work greatly facilitated access to the two
core use cases of the tBTC v2 system: depositing and redeeming. Here are
some examples of how it looks like now:
```
// Initialize SDK
const signer = (...) 
const sdk = await TBTC.initializeMainnet(signer) 

// Deposit flow
const bitcoinRecoveryAddress = "" // take this from user input
const deposit = await sdk.deposits.initiateDeposit(bitcoinRecoveryAddress)
const depositAddress = await deposit.getBitcoinAddress() // present that to the user
await deposit.initiateMinting() // this will initiate minting if BTC were sent to the deposit address

// Redemption flow
const bitcoinRedeemerAddress = "" // take this from user input
const amount = "" // take this from user input
await sdk.redemptions.requestRedemption(bitcoinRedeemerAddress, amount)
```
  • Loading branch information
tomaszslabon authored Oct 16, 2023
2 parents 099f9eb + 4bdc2a1 commit 05679d1
Show file tree
Hide file tree
Showing 98 changed files with 26,781 additions and 11,582 deletions.
4 changes: 2 additions & 2 deletions typescript/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ toc::[]

Please make sure you have the following prerequisites installed on your machine:

- https://nodejs.org[Node.js] >14.17.4
- https://yarnpkg.com[Yarn] >1.22.10
- https://nodejs.org[Node.js] >=16
- https://yarnpkg.com[Yarn] >=1.22.19

=== Install dependencies

Expand Down
4 changes: 2 additions & 2 deletions typescript/scripts/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ toc::[]

Please make sure you have the following prerequisites installed on your machine:

- https://nodejs.org[Node.js] >14.18.0
- https://yarnpkg.com[Yarn] >1.22.19
- https://nodejs.org[Node.js] >=16
- https://yarnpkg.com[Yarn] >=1.22.19

tBTCv2 system prerequisite is that you can refund your BTC only if it was not used
for minting tBTC and after `refundLocktime` has passed.
Expand Down
32 changes: 19 additions & 13 deletions typescript/scripts/refund.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { BigNumber } from "ethers"
import { Deposit } from "../src/deposit"
import { submitDepositRefundTransaction } from "../src/deposit-refund"
import { TransactionHash, UnspentTransactionOutput } from "../src/bitcoin"
import { Client as ElectrumClient } from "../src/electrum"
import { program } from "commander"
import fs from "fs"
import * as fs from "fs"
import {
BitcoinTxHash,
BitcoinUtxo,
DepositReceipt,
DepositRefund,
DepositScript,
ElectrumClient,
ElectrumCredentials,
} from "../src"

program
.version("0.0.1")
Expand Down Expand Up @@ -49,13 +54,12 @@ const electrumCredentials = {
host: options.host,
port: options.port,
protocol: options.protocol,
}
} as ElectrumCredentials

const depositJson = JSON.parse(fs.readFileSync(depositJsonPath, "utf-8"))

const deposit: Deposit = {
const deposit: DepositReceipt = {
depositor: depositJson.depositor,
amount: BigNumber.from(refundAmount),
walletPublicKeyHash: depositJson.walletPublicKeyHash,
refundPublicKeyHash: depositJson.refundPublicKeyHash,
blindingFactor: depositJson.blindingFactor,
Expand All @@ -73,19 +77,21 @@ console.log("electrum credentials:", electrumCredentials)
console.log("=====================================")

async function run(): Promise<void> {
const client = new ElectrumClient(electrumCredentials)
const client = new ElectrumClient([electrumCredentials])

const depositUtxo: UnspentTransactionOutput = {
transactionHash: TransactionHash.from(transactionId),
const depositUtxo: BitcoinUtxo = {
transactionHash: BitcoinTxHash.from(transactionId),
outputIndex: Number(transactionIndex),
value: BigNumber.from(refundAmount),
}

const refundTxHash = await submitDepositRefundTransaction(
const depositScript = DepositScript.fromReceipt(deposit)
const depositRefund = DepositRefund.fromScript(depositScript)

const refundTxHash = await depositRefund.submitTransaction(
client,
BigNumber.from(fee),
depositUtxo,
deposit,
recoveryAddress,
refunderPrivateKey
)
Expand Down
Loading

0 comments on commit 05679d1

Please sign in to comment.