Skip to main content

Withdraw Liquidity

To withdraw liquidity from a pool, a remove liquidity transaction needs to be generated by calling the Liquidity Remove endpoint in the Rest API and then broadcast to a chain.

The Remove Liquidity parameters are the following:

pair
lp_allocation
timeout
cross_chain_addresses

We will go through all the steps needed to get each of the parameters.

Steps

The following steps describe the workflow to remove liquidity from a pool using the Euclid Layer:

1. Get all available pools

The first step of the process will be retrieving all the available VLP. This can be done using the All VLPS query:

note

You can use pagination to iterate through all the pools as you like.

query All_vlps {
router {
all_vlps {
vlps {
vlp
token_1
token_2
}
}
}
}

This will return all the available pools in the Euclid Layer:

{
"data": {
"router": {
"all_vlps": {
"vlps": [
{
"vlp": "nibi1gd52zq92wexpv0jwzktkma5krxzgkuupqlltx6qxqv4u8xp39d3qa5jdxk",
"token_1": "osmo",
"token_2": "sol"
},
{
"vlp": "nibi1x34fkar6puj4v3n0h84xf5y03u3uw5z5ggk95asql2cey6u8pygqlfups2",
"token_1": "osmo",
"token_2": "usdt"
},
{
"vlp": "nibi15gt9jedsst7ggvnm70x4jvplzy050npgmtlej87zdlys8tj2w0jsypk42k",
"token_1": "pepe",
"token_2": "usdt"
},
{
"vlp": "nibi1aqxyhput7y6g5hq8mssrgs86yzkfe7wkrruz6ymhh2589rg5am8sw927mk",
"token_1": "usdc",
"token_2": "usdt"
}
]
}
}
}
}

Using this data, you can prompt the user to select the pool they wish to remove liquidity from. You will also need the address of the VLP, so make sure to keep that saved.

2. Select the chain to remove liquidity from

Now that we’ve selected the token pair for withdrawing liquidity, the next step is to identify the available chains where this pair is supported for liquidity withdrawal. This can be done using the All Pools query:

note

Use the contract address of the VLP contract for the token pair selected by the user.

query Vlp($contract: String!) {
vlp(contract: $contract) {
all_pools {
pools {
chain_uid
pool {
reserve_1
reserve_2
lp_shares
}
}
}
}
}

The response will retrieve the chains where this pair exists (usdc-usdt in this example):

{
"data": {
"vlp": {
"all_pools": {
"pools": [
{
"chain_uid": "ethereum",
"pool": {
"reserve_1": "9998505649856",
"reserve_2": "10001756242906",
"lp_shares": "10000129999349"
}
},
{
"chain_uid": "osmosis",
"pool": {
"reserve_1": "9998375670523",
"reserve_2": "10001626221316",
"lp_shares": "9999999998900"
}
}
]
}
}
}
}
note

The user will only be able to withdraw liquidity from the pools they have added liquidity to in the past.

The user can select the chain they wish to withdraw from.

3. Get the contract address for the LP tokens

The third step will be getting the contract address for the LP tokens that were transferred to the user when liquidity was added. This address can be fetched using the Get Token Address query:

query Get_token_address($vlpAddress: String!, $chainUid: String!) {
factory(chain_uid: $chainUid) {
get_token_address(vlp_address: $vlpAddress) {
token_address
}
}
}

The response will return the CW20 contract address of the LP tokens.

{
"data": {
"factory": {
"get_token_address": {
"token_address": "wasm1mx573kf90nwgatgw6ukesr5pyhk5uemtfgapnk9rzvymy6dxtlwscrq8eg"
}
}
}
}

4. Check the user's balance and select the amount to wihtdraw

Before prompting the user to specify the amount to withdraw, we have to get the balance of LP tokens for the user to make sure they do not try to withdraw an amount they do not have. The balance can be fetched using the CW20 Balance query:

tip

Use the connected wallet for the address field.

query Cw($contract: String!, $chainUid: String!, $address: String!) {
cw(contract: $contract, chain_uid: $chainUid) {
balance(address: $address) {
balance
}
}
}

The response will return the amount of LP tokens the user has:

{
"data": {
"cw": {
"balance": {
"balance": "10000019998932"
}
}
}
}

Now when the user specifies the amount, you can do a check to make sure the amount does not exceed their balance.

5. Generate Remove Liquidity transaction

note
  • Use the responses we got in all the previous steps for the fields.
  • For sender address and chain_uid use the ones from the connected chain. In the example below, we are using a Keplr wallet.
  • The cross_chain_addresses are taken as an input from the user. The addresses for different chains can be fetched from the wallet using the chain Id.

const msg = await REST_AXIOS.post("/execute/liquidity/remove", {
lp_allocation: data.lp_allocation, // amount to withdraw
vlp_address: data.vlp_address, // contract address of VLP
sender: {
address: wallet!.bech32Address, //wallet address
chain_uid: chain!.chain_uid,
},
}).then((res) => res.data as TxResult);

6. Broadcast the transaction to chain

The final step will be broadcasting this transaction to the chain and signing it with the connected wallet:

 const tx = await client!.executeMultiple(
wallet!.bech32Address,
msg.msgs,
"auto",
"Remove Liquidity"
);
return tx;