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

Implementation of full staking flow #217

Merged
merged 72 commits into from
Feb 15, 2024
Merged

Conversation

kkosiorowska
Copy link
Contributor

@kkosiorowska kkosiorowska commented Feb 5, 2024

Closes #134
Closes #136
Closes #107

Overall Description

This PR integrates SDK with dApp and implements a full path for staking flow. Staking flow requires two steps. In the first step, a user needs to sign the message with an ETH account. In the next step, the user needs to do a bitcoin transaction by sending a deposit to a specially generated address. After the deposit, we call stake actions. Currently, we call directly the stake function from the SDK but this will be updated. Finally, we should call a bot to do stake.

Details

Integration SDK with dApp

The module responsible for handling the SDK is located in the acre-react directory. This will allow us to easily separate this logic when we want to create a separate package out of it. To use the SDK we need to wap components in a context provider AcreSdkProvider. The next step is to use the useAcreContext hook and initialize the acre object. Initialization involves calling the init method and passing it to the right Ethereum address to create a signer. Example of a solution in the dApp:

export function useInitializeAcreSdk() {
  const { ethAccount } = useWalletContext()
  const { init } = useAcreContext()

  useEffect(() => {
    if (ethAccount?.address) {
      const initSDK = async (ethAddress: string) => {
        await init(ethAddress, ETHEREUM_NETWORK)
      }

      asyncWrapper(initSDK(ethAccount.address))
    }
  }, [ethAccount?.address, init])
}

StakeFlowContext and useStakeFlow hook

Due to the fact that on staking flow is based on several steps and actions are called separately in other modal windows, a special context was created - StakeFlowContext. The context contain 4 properties:

type StakeFlowContextValue = {
  initStake: (
    bitcoinRecoveryAddress: string,
    ethereumAddress: string,
  ) => Promise<void>
  btcAddress?: string
  signMessage: () => Promise<void>
  stake: () => Promise<void>
}

The initStake function, based on the bitcoin and ethereum address, generates the deposit address (to which the user should deposit BTC). The address of the deposit was stored in the btcAddress property. By usingStakeFlow, we can easily refer to the above-mentioned properties.

Handle of staking flow

Staking flow is based on modal windows. Depending on the state of our flow, we should display an auxiliary modal such as loading, pause or success view. For this reason, the ProcessStatus type was created. The right state of the process will allow us to display the correct content.

export const PROCESS_STATUSES = {
  IDLE: "IDLE",
  PAUSED: "PAUSED",
  PENDING: "PENDING",
  LOADING: "LOADING",
  FAILED: "FAILED",
  SUCCEEDED: "SUCCEEDED",
} as const

export type ProcessStatus =
  (typeof PROCESS_STATUSES)[keyof typeof PROCESS_STATUSES]

useSendTransaction hook

I have created this hook to easily trigger transactions and set the status of it. It enables us to easily call out a callback at the time of success or error. It is useful when the stake function is called to set the corresponding process status.

useDepositBTCTransaction and useDepositBTC

This useDepositBTCTransaction is responsible for calling the signAndBroadcastTransaction function from the ledger wallet API. And useDepositBTC calls the previously mentioned function and, at the right moment when the transactionHash is already known, calls the success callback. I've separated this into two hooks but we might as well wrap it up in one.

Calling the stake function

The onDepositBTCSuccess is a callback in case of success for the deposit function. The stake function is called with a delay to avoid an error - funds not found At the moment, let's leave it as it is, and update this logic later.

  const onDepositBTCSuccess = useCallback(() => {
    setStatus(PROCESS_STATUSES.LOADING)
    // Let's call the stake function with a delay,
    // to make sure for the moment that it doesn't return an error about funds not found
    // TODO: Remove the delay when SDK is updated
    setTimeout(() => {
      asyncWrapper(stakeBTC())
    }, 10000)
  }, [setStatus, stakeBTC])

Testing

Tests happen on a test network - bitcoin_testnet and ethereum_sepolia. To make a stake you need to have funds in your BTC and ETH account. The minimum amount to stake is 0.001 BTC. Testing steps:

  • Connect to your ETH and BTC (legacy address) accounts.
  • Press the stake button to move to the correct flow.
  • Complete the stake amount in form and proceed to the next steps.
  • Sign the message for ETH account.
  • Do a BTC deposit.
  • Automatically after 10 seconds the stake function should be called. Sign the transaction.

Additional steps:

  • Make sure that when you close the internal transaction window everything works.
  • Make sure that the pause modal window works as before.

Currently, errors during sending transactions are displayed in the console. In the following steps, we will take care of this and display the right messages on the screen.

@kkosiorowska kkosiorowska added the 🎨 dApp dApp label Feb 5, 2024
@kkosiorowska kkosiorowska self-assigned this Feb 5, 2024
@kkosiorowska kkosiorowska force-pushed the dapp-acre-sdk-final-integration branch from fdb3dd9 to a7ddbf1 Compare February 7, 2024 10:40
@nkuba nkuba changed the base branch from acre-sdk to dapp-acre-sdk-integration February 7, 2024 13:19
@r-czajkowski r-czajkowski changed the base branch from dapp-acre-sdk-integration to main February 7, 2024 14:44
@kkosiorowska kkosiorowska changed the title SDK integration with dapp - staking Implementation of full staking flow Feb 8, 2024
@kkosiorowska kkosiorowska force-pushed the dapp-acre-sdk-final-integration branch from 64ff769 to 5b58b56 Compare February 8, 2024 09:56
r-czajkowski and others added 23 commits February 8, 2024 12:42
Create a signer that sign/send transaction and sign messages using the
Ledger Live Wallet API. Thanks to this we can use the Acre SDK that is
built with ethers lib in Ledger Live dapp. Here we also create a single
instance of the Ledger Live transport that should be used across the
dapp. Otherwise if we create another instance of the transport in eg.
ledger signer class the wallet API throws an error about unhandled
request.
Set correct permissions to sign messages and sign/send transactions.
Keep the hooks and context related to the Acre SDK in a seprate dir so
in the future we can easily extract this package to a separate package
in monorepo and publish npm package.
Add network param to the `init` function to not hardcode this value in
context.
Create a react hook wrapper for Acre SDK staking flow.
We have to pass the Ethereum node url to the signer's provider. We can
do it via env variable.
Use the correct curreny id based on the env variable when requesting
list of accounts via Ledger Live Wallet Api.
And push deployed artifacts to the repo so we can use it in SDK.
Use aliases for monorepo packages for nice imports.
The contracts were deployed to Sepolia with reference to actual tBTC
contracts.
In the stake/unstake modal flow, there are loading and success screens. To correctly display the relevant screens, we need to enter the status of the transaction. To easily handle outgoing transactions with statuses, a special useSendTransaction hook was created. Two comments:

- We now save the status of the transaction in the context to have easy access to it from the modal head window.This is a temporary solution.
- Two transactions were passed to the `useSendTransaction` hook. Ultimately, we will not call the second transaction there, it will be changed.
We should setup `JsonRpcProvider` using an environment variable. This
makes it easy to change addresses.
kkosiorowska and others added 13 commits February 13, 2024 09:28
Co-authored-by: Rafał Czajkowski <57687279+r-czajkowski@users.noreply.github.com>
Co-authored-by: Rafał Czajkowski <57687279+r-czajkowski@users.noreply.github.com>
Co-authored-by: Rafał Czajkowski <57687279+r-czajkowski@users.noreply.github.com>
…tApiReactTransportContext`

Co-authored-by: Rafał Czajkowski <57687279+r-czajkowski@users.noreply.github.com>
Using e makes it easier to validate the requested number instead of counting zeros.
@ledgerhq/wallet-api-client-react uses the bignumber.js and this type is required in eg. useSignAndBroadcastTransaction. However, it is possible to avoid this and pass the amount as a bigint. Let's do it to get rid of the external library.
useSignMessage it's too general and could be misleading. Add our wrapper for this function in StakeFlowProvider.
Previously, logic was divided into two hooks. But it was a bit confusing when to use which. When using signAndBroadcastTransaction, we should check whether the action was successful or not via the transactionHash and error properties. Therefore, we cannot use the useSendTransaction hook.
We cannot use useWalletAPIClient because there is an error from the ledger side, which does not allow us to handle success and error callbacks correctly. Therefore, we need to use the hook useSignAndBroadcastTransaction and use callbacks in the effects. To avoid repeating the logic I created the hook useExecuteFunction to easily handle callbacks. So let's use it in all cases where it is possible.
nkuba added a commit that referenced this pull request Feb 15, 2024
Ref: #217

This PR updates the dapp workflow. The dapp needs `sdk` module as a
dependency so we need to first build SDK module and upload the build
artifacts and then run dapp workflows. Here we extract the SDK build
process into a separate file so we can reuse the same jobs in other
workflows.
@r-czajkowski r-czajkowski merged commit 3ec6159 into main Feb 15, 2024
15 checks passed
@r-czajkowski r-czajkowski deleted the dapp-acre-sdk-final-integration branch February 15, 2024 10:24
r-czajkowski added a commit that referenced this pull request Feb 16, 2024
This PR removes the unnecessary code that has been left from the changes
in #217.
nkuba added a commit that referenced this pull request Feb 28, 2024
~Depends on: #217~
Closes: #167
Closes: #168

This PR adds support to initialize stake requests using a custom
implementation of the `DepositorProxy`. The dapp defines its own
`DepositorProxy` which redirects the stake request to the Open Zeppelin
Defender Relayer which initializes stake on the user's behalf.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Success view Loading view for staking flow Implement Staking Flow in Ledger Live dApp
5 participants