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

Acre SDK - staking module #106

Merged
merged 75 commits into from
Feb 7, 2024
Merged

Acre SDK - staking module #106

merged 75 commits into from
Feb 7, 2024

Conversation

r-czajkowski
Copy link
Contributor

@r-czajkowski r-czajkowski commented Jan 1, 2024

Closes #147
Depends on: #91

This PR adds staking module to the Acre SDK. The Acre SDK is built on top of the tbtc-v2.ts lib and exposes interfaces that should be implemented for a given chain to communicate with Acre network. In this PR we add Ethereum implementation and developers can initialize the SDK for the Ethereum chain.

What has been done:

  • define SDK file structure,
  • create abstract interfaces that should depend on the chain implementation eg. TBTCDepositor, ChainEIP712Signer and ChainSignedMessage,
  • add Ethereum implementation of Acre smart contracts and typed data signer,
  • create staking module that initializes the staking flow,
  • add unit tests,
  • create necessary wrappers for interfaces from tbtc-v2.ts lib that are used in SDK and are exposed outside the SDK eg Hex, ChainIdentifier, EthereumAddress and BitcoinRawTxVectors.

The SDK file structure

lib - shared library components

Contains all components used to build Acre features eg. staking, inspired by tbtc-v2.ts lib.

  • bitcoin: Contains all interfaces to interact with Bitcoin chain,
  • contracts: Includes abstract interfaces to interact with Acre smart contracts. Should be implemented for a given chain eg. Ethereum.
  • eip712-signer: An abstract layer for typed structured data signer. The main idea is to hide the signing process under the exact implementation for a given chain and not expose the external library outside the SDK. For example, we can use ethers lib for Ethereum implementation, but different lib for other chains.
  • ethereum: Provides Ethereum implementation of Acre smart contract and signer interfaces. Should contain other implementation of components that should depend on the chain implementation.
  • utils: General utility functions.

modules - Acre network features

Provides access to the Acre network features such as staking.

  • staking - provides access to the staking flow for BTC stakers.

Staking module

initializeStake

Initializes the Acre staking flow and returns StakeInitialization object that exposes staking flow steps:

  1. getBitcoinAddress - returns Bitcoin address corresponding to this deposit. The user should send BTC to this address to stake tokens.
  2. signMessage - signs the staking message and stores it in object instance to use it in stake function. The signed message is required by Acre staking flow.
  3. stake - Stakes BTC based on the Bitcoin funding transaction via TBTCDepositor contract. It requires signed staking message, which means stake should be called after message signing. By default, it detects and uses the outpoint of the recent Bitcoin funding transaction and throws if such a transaction does not exist. The staking message must be signed first otherwise throws an error.

Unit tests

Decided to switch from mocha and chain to jest. Jest testing framework has built-in support for mocks, stubs, and spies. Chai requires the installation of additional dependencies but most of them are no longer maintained. I also tried using the chai with ethereum-waffle package, which adds support for mocking contracts, but it only supports ethers in v5, we want to use the latest version of ethers - it is v6.

@r-czajkowski r-czajkowski added the 🔌 sdk TypeScript SDK Library label Jan 1, 2024
@r-czajkowski r-czajkowski self-assigned this Jan 1, 2024
@r-czajkowski r-czajkowski changed the title Staking module in Acre SDK Acre SDK - staking module Jan 2, 2024
sdk/src/lib/messages/messages.ts Outdated Show resolved Hide resolved
sdk/src/lib/messages/messages.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/index.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/staking.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/staking.ts Outdated Show resolved Hide resolved
@nkuba nkuba mentioned this pull request Jan 11, 2024
sdk/src/lib/eip712-signer/eip712.ts Show resolved Hide resolved
sdk/src/modules/staking/stake-initialization.ts Outdated Show resolved Hide resolved
}

const types: Types = {
Stake: [{ name: "receiver", type: "address" }],
Copy link
Member

Choose a reason for hiding this comment

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

Let's also add the Bitcoin refund account property.
And also leave a TODO note to revisit the message structure when working on unstaking messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sdk/src/modules/staking/stake-initialization.ts Outdated Show resolved Hide resolved
@r-czajkowski r-czajkowski marked this pull request as ready for review January 17, 2024 18:15
sdk/src/lib/contracts/index.ts Outdated Show resolved Hide resolved
sdk/src/index.ts Outdated Show resolved Hide resolved
sdk/src/index.ts Outdated Show resolved Hide resolved
sdk/src/index.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/index.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/stake-initialization.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/stake-initialization.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/stake-initialization.ts Outdated Show resolved Hide resolved
Comment on lines 162 to 167
const { depositor: _, ...restDepositReceipt } = this.#deposit.getReceipt()

const revealDepositInfo = {
fundingOutputIndex: outputIndex,
...restDepositReceipt,
}
Copy link
Member

Choose a reason for hiding this comment

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

Could you please explain what are we doing here with the depositor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We want to get all deposit receipt fields w/o depositor. Since depositor is unused variable the eslint throws an error and to fix it we need to rename it _.

sdk/src/lib/eip712-signer/eip712.ts Show resolved Hide resolved
EthereumEIP712Signer,
EthereumAddress,
} from "../../../src/lib/ethereum"
import { EthereumSignedMessage } from "../../../src/lib/ethereum/eip712-signer/signed-message"
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use an absolute path in files that have such nesting?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm just thinking about using absolute path, eg: "src/lib" instead of relative paths like "../../../src"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm I can't do that, eslint throws an error Unable to resolve path to module 'src'. I can dig into it in spare cycles but now I improved imports so the paths are much simpler see 023a33d.

sdk/src/index.ts Outdated
_tbtc: TBTC,
) {
this.contracts = _contracts
this.#tbtc = _tbtc
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for confirmation of the naming convention, do we use the _ prefix for private class members and # for read-only/protected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

# is a hard private field in js/ts see https://www.typescriptlang.org/docs/handbook/2/classes.html#caveats.
I use _ in constructor just to indicate that it is a constructor parameter.

sdk/src/lib/eip712-signer/eip712.ts Show resolved Hide resolved
sdk/src/lib/ethereum/contract.ts Show resolved Hide resolved
sdk/src/lib/ethereum/tbtc-depositor.ts Outdated Show resolved Hide resolved
sdk/src/lib/ethereum/tbtc-depositor.ts Show resolved Hide resolved
sdk/src/acre.ts Outdated Show resolved Hide resolved
sdk/src/lib/ethereum/index.ts Outdated Show resolved Hide resolved
sdk/src/lib/ethereum/tbtc-depositor.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/index.ts Outdated Show resolved Hide resolved
sdk/src/modules/staking/index.ts Show resolved Hide resolved
sdk/src/modules/staking/index.ts Show resolved Hide resolved
sdk/src/modules/staking/stake-initialization.ts Outdated Show resolved Hide resolved
r-czajkowski and others added 21 commits February 7, 2024 13:10
Use `TbtcDeposit` alias for `Deposit` import and rename the field in the
`StakeInitialization` class to `tbtcDepositor`. To indicate this is
deposit from tbtc-v2.ts SDK.
The contract name is `TbtcDepositor` not `TBTCDepositor`.
The message should contain the Bitcoin recovery address instead of the
public key hash of this address.
The latest version of the `tbtc-v2.ts` lib adds support for revealing
deposit with extra data. We need this feature to stake BTC(tBTC) on
user's behalf.
The `TBTCDepositor` should implement the `DepositorProxy` interface to
reveal the deposit with extra data on user's behalf. Here we also add
`encodeExtraData` and `decodeExtraData` functions to encodes and decodes
extra data passed to the tBTC Bridge contract. The Acre extra data is
staker address and referral number.
Adujst staking module to the new TBTCDepositor interface and the latest
version of the `tbtc-v2.ts` lib. We need to initiate the deposit with
extra data using the `tbtc-v2.ts` SDK by injecting our implementation of
the `DepositorProxy`.
Adjust unit tests to the latest version of tbtc-v2.ts lib that adds
support for revealing deposits with extra data via depositor proxy.
We can get the referral and staker from tBTC deposit object.
Expose shared components, feature modules and the `Acre` entry point
class from the root `index.ts` file. The `Acre` entry point class
currently provides static function to initialize the Acre SDK for
Ethereum network.
Pass the `bitcoinRecoveryAddress` to the `StakeInitialization` class.
Since we can't easily determine if we should use `true` or `false` in
`BitcoinAddressConverter.publicKeyHashToAddress` to convert public key
hash to `P2PKH` or `P2WPKH` we can use what the input was w/o doing a
conversion.

Here we also get rid of:
- the bitcoin client from the `StakeInitailization` class because at
  least for now it is unnecessary,
- `referral` field - it is decoded and passed to the contract function
  under the hood.
We need `build` and `typechain` artifacts from `core` package in `sdk`
because we import artifacts and types generated by `typechain` in `sdk`
package. To achieve this, we extract a reusable workflow that builds the
`core` package and uploads necessary artifacts. Then we use this
reusable workflow to run successfully the `sdk` jobs.

Here we also update the `jest` config - we should ignore tests inside
`dist` dir if exists.
We want to omit the `signerOrProvider` because it points to ethers v5.
We use ethers v6 in Acre SDK.
Ignore `sdk` monorepo package - `sdk` package has own prettier config.
According to the contract source code, the referral should be `uint16`.
Here we also add more unit tests to cover more cases eg. when a referral
is `0` (min `uint16`) and `65535` (max `uint16`).
We do not expect to support it.
And create the ethereum contract instance based on this artifact.
`receiver` -> `ethereumStakerAddress`. Add more context to the name of
field for clarity when user sees it on the device, so they know what the
value means.
Check if the staker address is a valid ethereum and non-zero address.
Based on the #91. We need this
contract to get types generated by `typechain` and import them in `sdk`.
Currently our SDK uses only `initializeStakeRequest` function and there
is no need to add more functions like in #91.
@r-czajkowski r-czajkowski changed the base branch from tbtc-depositor to main February 7, 2024 13:30
Pass the `staker` value the same as was used in this function input
parameter and use it insied `StakeInitialization` constructor to
initialize the value of `#staker` field, instead of recovering it from
the ` _tbtcDeposit.getReceipt()` extra data, as this is an external
library that can be compromised and return invalid value.
@nkuba nkuba merged commit 2b0d3ba into main Feb 7, 2024
12 checks passed
@nkuba nkuba deleted the acre-sdk branch February 7, 2024 14:12
r-czajkowski added a commit that referenced this pull request Feb 8, 2024
Depends on: #106 

Added getting of tbtc deposit receipt for StakeInitialization.
nkuba added a commit that referenced this pull request Feb 21, 2024
We decided to rename receiver to staker in the Depositor contract and
SDK.
See: #106 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔌 sdk TypeScript SDK Library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement stake request initialization
3 participants