Redemptions

Goals

This guide is a technical guide with examples of how to implement Liquid Collective’s redemption workflow into a Platform's workflow. For more information on Liquid Collective’s ETH staking withdrawal architecture, check out Liquid Collective’s LsETH redemption documentation

Pre-read

Review the Authentication Guide for the Alluvial API.

Implementation

The guide will using the Hoodi network for smart contract calls.

For this example, the implementation will use both smart contract calls and offchain calls via the Redemption API.

The Redemption API is an offchain API that exposes:

  • The list of redeem requests for an owner (wallet) including their redemption IDs

  • The status information about redeem requests (including id, redeemed amount, satisfaction status, claim status, etc.)

  • The heights of the withdrawal stack (ETH supplied) and the redeem queue (LsETH queued to redeem). Learn more here on different queues & stacks.

  • Time estimates for redemptions (projected and fulfilled)

Create Redemption Request

The LsETH contract exposes a function called requestRedeem.

As an Platform, you allow users to submit (or to request that you submit on their behalf) the amount of LsETH they wish to redeem.

Note: In some cases, the recipient may be different from the message sender. For example: if using an omnibus model, you may have LsETH in a wallet separate from the user’s ETH wallet. In this case, the LsETH wallet will make the requestRedeem, however, the recipient of ETH will be the ETH wallet.

After successfully calling requestRedeem function an ID will be generated. Keep this redeemRequestId as you will use it later on.

Below is a code snippet that will call the requestRedeem function.

Code uses public RPC as its provider to interact with smart contracts and uses Ethers.js

Contract.json is the ABI associated with the LsETH contract

RequestedRedeem event

When creating a requestRedeem, the LsETH contract will emit a RequestedRedeem event. The event contains the redeem request IDs. Additionally, you can use the Redemption API to retrieve redeem request IDs associated with an owner, which is demonstrated later on in this guide.

Below is a code snippet for listening to the RequestedRedeem event via websocket connection.

Request:

Code uses public RPC as its provider to interact with smart contracts and uses Ethers.js

Contract.json is the ABI associated with the LsETH contract

run in terminal

Response:

As you can see in the response below, the redeem request ID is 18. This is the request ID associated with the request earlier in the “Create Redeem Request” section of this guide.

The full lifecycle method visual can be seen here.

eth/v0/redeems

You can use the Redemption API to list the redeemRequests for a given recipient wallet.

You can get a list of all redemptions associated with a wallet using the curl request below.

Request

Response:

You can see information related to the status of the redemption. Later on, you will see the status update as the redeemRequest becomes satisfied and can be claimed.

For all status combinations check out this Redeem Status Matrix

Timing projections

Now that you have a redeem ID, use the projections endpoint to get an estimate of how long it might take for the redeemRequest to be satisfied and become claimable.

Request:

Response:

The response below displays when the redeemRequest is likely to be redeemable. Once redeemable, you can use resolveRedeemRequests to get the matching withdrawal event ID.

Reported withdrawal event

A withdrawal event is triggered at the time of the protocol’s Oracle report. Oracles report every 24 hours.

Withdrawal event IDs are not generated instantly, even if there is enough supply. Withdrawal event IDs will be generated at the next Oracle report after redeem request is submitted. This is by design to ensure a fair redemption process for all Liquid Collective participants.

Below is an example event.

Request:

This event will emit the newly created withdrawal ID, as you can see below:

Response:

Resolve redemption request

In order to see if a redemption request can be satisfied, use the resolveRedeemRequests function call.

Request:

Response:

You receive a redeem ID of 10. 10 is the specific withdrawal event ID that is produced when the Liquid Collective Protocol has enough ETH to satisfy (either partial or full) the redemption. This means that the redeemRequest has been satisfied and the corresponding withdrawal event ID was returned.

This withdrawal event may fully satisfy or partially satisfy the redeem request ID. To ensure redemption requests are fully satisfied prior to claiming, use the /eth/v0/redeems/{idx} endpoint.

An alternative method to getting the Withdrawal event ID is using the /eth/v0/redeems/{id} endpoint.

Request:

Response:

The response below indicates that this redemption can be fully satisfied, meaning there is enough supply in the withdrawal stack to fulfill this redemption. This is noted via the "status_satisfaction": "FULLY_SATISFIED" and also the claimable_amount_lseth is equal to the total_amount_lseth.

For other potential states, check out the appendix at the bottom of the doc.

Claim redemption requests

With both a request redeem ID and withdrawal event ID you can submit a claim for the redemption calling the claimRedeemRequests function.

Request:

After making a claim there will be two events triggered, which will be inspected next in this guide.

ClaimedRedeemRequest event

On successfully claiming a redeemRequest, a ClaimedRedeemRequest event is emitted. This event indicates the amount of LsETH claimed, the amount of ETH sent to the recipient, and the remaining LsETH amount that has been satisfied but not yet claimed.

A remaining LsETH amount of 0 means the request has been fully claimed. If the amount is greater than 0, the request has been partially claimed and another claim will be required to fully claim the request.

Request:

Response:

SatisfiedRedeemRequest event

On successfully claiming a redemption request one or more SatisfiedRedeemRequest events are emitted.

Those events provide details about the withdrawal events that have satisfied a redemption request.

Request:

Response:

eth/v0/redeems

An alternative approach is to use the Alluvial API to call the /redeems endpoint, as it will return the status of both satisfaction and claim status.

Request:

Response:

Below the endpoint returns that this request redeem has been fully satisfied and claimed.

You are now able to fully implement the redemption process for the Liquid Collective protocol!

Redemption Information

The Alluvial API exposes information about both theWithdrawal stack and Redeem queue.

Redemption height

Platforms who want visibility into the current supply (amount of withdrawals) and demand (amount of redeems) can use the /redeems_info endpoint.

Request:

Response:

Below you can see that the redeem queue is greater than the withdrawal stack. This indicates that more supply is needed to fulfill the redeem requests. Additional supply can enter via more deposits and/or exiting a validator.

amounts returned are denominated in LsETH

In addition to exposing the Withdrawal stack and Redeem queue, Alluvial exposes an estimated time when redeems will be fulfilled.

Request:

Response:

The current projections timestamp logic is:

  • If the timestamp is in the past, it means that there is enough supply to fulfill demand and Alluvial returns the timestamp associated with the latest redeem request.

  • If the timestamp is in the future, it means there isn't enough supply to fulfill demand and time is needed to add supply into the Withdrawal stack.

This is an estimated time and actual times may vary depending on frequency of deposits and redemptions on the Liquid Collective protocol.

Appendix

Full Code

Full code for making deposit transaction

/redeems response payloads

The redemption process is very dynamic. You can see a matrix of all the redeem statuses here. Below will show the difference between response payloads when requesting from either:

  • eth/v0/redeems/18

  • eth/v0/redeems?owner=

NOT_CLAIMED & PENDING_SATISFACTION

Why would this state happen?

  • This is the initial state for all redeem requests.

NOT_CLAIMED & PARTIALLY_SATISFIED

Why would this state happen?

  • This happens when the redemption request can be partially satisfied and the owner has not made a claimRedeemRequest against the redeem request.

  • Notice that the claimable_amount_lseth is greater than 0 but less than the total_amount_lseth.

NOT_CLAIMED & FULLY_SATISFIED

Why would this state happen?

  • The amount of supply can fully satisfy the amount of LsETH being redeemed in this request.

  • Notice that total_amount_lseth == claimable_amount_lseth

PARTIALLY_CLAIMED & PENDING_SATISFACTION

Why would this state happen?

  • The owner has claimed part of redeem request before the redeem request was fully satisfied. More supply will need to be added, hence the withdrawal_event_id is == -1, whereas before there would have been a positive integer associated with the withdrawal_event_id (ex. 0, 1, 2, etc...).

  • Note that claimed_amount_lseth is equal to previously claimed amount.

PARTIALLY_CLAIMED & PARTIALLY_SATISFIED

Why would this state happen?

  • The owner has claimed part of redeem request before the redeem request was fully satisfied. More supply was found, however not enough to fully satisfy this redeem request.

  • In the example below you can see that total_amount_lseth > claimed_amount_lseth + claimable_amount_lseth. There is 40000 LsETH still left to fully satisfy this request.

PARTIALLY_CLAIMED & FULLY_SATISFIED

Why would this state happen?

  • The owner has claimed part of redeem request before the redeem request was fully satisfied.

  • In the example below you can see that total_amount_lseth = claimed_amount_lseth + claimable_amount_lseth.

FULLY_CLAIMED & FULLY_SATISFIED

Why would this state happen?

  • This is final state for all redeem requests. This indicates that the redeem request has been fully satisfied.

  • total_amount_lseth == claimed_amount_lseth and claimable_amount_lseth == 0

  • withdrawal_event_id reflects this state with the -3 ID.

Last updated

Was this helpful?