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 Holesky environment 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)
For Contract Addresses: view this page. Make sure you use the Contract Address when sending txs.
For ABIs: This guide uses Goerli testnet and interacts with two contracts: LsETH and RedeemManager. RedeemManger contract is only needed if listening to RedeemManager contract events.
Ethereum Network | Proxy | Implementation |
---|---|---|
LsETH | 0x1d8b30cC38Dba8aBce1ac29Ea27d9cFd05379A09 | 0x6edbde63319df1c54ee94075191c3d2ac5a1bf81 |
RedeemManager | 0x0693875efbF04dDAd955c04332bA3324472DF980 | 0x3b377e3ac2cc844d8d27b8930f6a3035d3a3fc5b |
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 Chainstack 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 Chainstack websocket as its provider to interact with smart contracts.
RedeemManger.json is the ABI for the RedeemManager contract. ABIs can be found in Etherscan.
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.
A response of…
-1 means that the request is not satisfied yet
-2 means that the request is out of bounds
-3 means that the request has already been claimed
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.
Before claiming, ensure you have correct Withdrawal event ID. Withdrawal events IDs will change based on redemptions happening on the protocol.
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:
Non-finalized blocks are returned in the Alluvial API.
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
Code is meant for testing purposes and should not be used directly for production workloads.
/redeems response payloads
The redemption process is very dynamic. You can see a matrix of all the redeem statuses here. Below will show the differnce 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 thetotal_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 thewithdrawal_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
andclaimable_amount_lseth
== 0withdrawal_event_id
reflects this state with the-3
ID.
Last updated