Providing/Withdrawing Liquidity
Overview
A user can provide liquidity to a pool by calling provide_liquidity
. Before executing the provide_liqudity
operation, a user must allow the pool contract to take tokens from their wallet for all CW20 tokens in a given pair.
Users can also withdraw liquidity by calling withdraw_liquidity
. To receive the underlying liquidity back plus accrued LP fees, LPs must burn their liquidity tokens.
Providing Liquidity
increase_allowance
Before we can provide liquidity to a pool, we need to increase the token allowance for all CW20 tokens in the pair.
The increase_allowance
endpoint for a given CW20 token contract contains:
- A
spender
(the pair address we are depositing to in our example) - The
amount
to increase the allowance by - An optional expiration time
_9{_9 "increase_allowance": {_9 "spender": astrolunaAddress,_9 "amount": "1000000000000",_9 "expires": {_9 "never": {}_9 }_9 }_9}
provide_liquidity
To provide liquidity, you need to execute a contract message pointing to the provide_liquidity
endpoint in the pair
contract for the selected pool.
assets
is the only required parameter and contains information about each token in the pair, including the contract address or native denomination and the amount to deposit.
For new pools, you can deposit any ratio of tokens in a pair. For existing pairs, the contract will throw an error message if the proper balance of ratios between tokens is not met.
_25{_25 "provide_liquidity": {_25 "assets": [_25 {_25 "info": {_25 "token": {_25 "contract_addr": astroAddress_25 }_25 },_25 "amount": beliefPrice_25 },_25 {_25 "info": {_25 "native_token": {_25 "denom": "uluna"_25 }_25 },_25 "amount": "500000"_25 }_25 ],_25 "slippage_tolerance": "0.005",_25 "auto_stake": false, _25 "receiver": "..."_25 }_25}
Optional Parameters
provide_liqudity
takes up the following optional parameters:
slippage_tolerance
: Allows liquidity provision while the price of assets in a pool stays within a certain rangeauto_stake
: Determines whether the LP tokens minted for the user are auto staked in the Generator contract.receiver
: The receiver of LP tokens (if different from sender)
_25{_25 "provide_liquidity": {_25 "assets": [_25 {_25 "info": {_25 "token": {_25 "contract_addr": astroAddress_25 }_25 },_25 "amount": beliefPrice_25 },_25 {_25 "info": {_25 "native_token": {_25 "denom": "uluna"_25 }_25 },_25 "amount": "500000"_25 }_25 ],_25 "slippage_tolerance": "0.005",_25 "auto_stake": false, _25 "receiver": "..."_25 }_25}
Coins
If the pair you are providing liquidity to contains a native asset, you will also need to send the native token along with the transaction message.
The code in this section is an example of what a provide_liquidity
message may look like using feather.js to send Coins with our transaction.
_44const astroAddress = 'terra167dsqkh2alurx997wmycw9ydkyu54gyswe3ygmrs4lwume3vmwks8ruqnv';_44_44const provideLiquidity = new MsgExecuteContract(_44 wallet.key.accAddress('terra'),_44 astrolunaAddress,_44 {_44 "provide_liquidity": {_44 "assets": [_44 {_44 "info": {_44 "token": {_44 "contract_addr": astroAddress_44 }_44 },_44 "amount": beliefPrice_44 },_44 {_44 "info": {_44 "native_token": {_44 "denom": "uluna"_44 }_44 },_44 "amount": "500000"_44 }_44 ],_44 "slippage_tolerance": "0.005",_44 "auto_stake": false_44 }_44 }, _44 new Coins({ "uluna": "500000" })_44);_44_44_44const fee = new Fee(2000000, { uluna: 200000 });_44_44const tx = await wallet.createAndSignTx({_44 msgs: [provideLiquidity],_44 fee,_44 chainID: 'pisco-1',_44});_44_44const result = await lcd.tx.broadcast(tx, 'pisco-1');_44_44console.log(result);
Calculating Deposit Amount
As noted above, the contract will throw an error message if the proper balance of ratios between tokens is not met.
In order to obtain the ratio of tokens that we need, we can simulate a swap and input our response as the amount
for one of our deposits.
_24{_24 "provide_liquidity": {_24 "assets": [_24 {_24 "info": {_24 "token": {_24 "contract_addr": astroAddress_24 }_24 },_24 "amount": beliefPrice_24 },_24 {_24 "info": {_24 "native_token": {_24 "denom": "uluna"_24 }_24 },_24 "amount": "500000"_24 }_24 ],_24 "slippage_tolerance": "0.005",_24 "auto_stake": false_24 }_24}
simulation
The simulation
endpoint contains information about our offer asset and the amount to swap.
Our input amount
and response will gives us the proper ratio of tokens that we need to provide_liquidity
.
_12{_12 "simulation": {_12 "offer_asset": {_12 "info": {_12 "native_token": {_12 "denom": "uluna"_12 }_12 },_12 "amount": "500000"_12 }_12 }_12}
increase_allowance
Before we can provide liquidity to a pool, we need to increase the token allowance for all CW20 tokens in the pair.
The increase_allowance
endpoint for a given CW20 token contract contains:
- A
spender
(the pair address we are depositing to in our example) - The
amount
to increase the allowance by - An optional expiration time
provide_liquidity
To provide liquidity, you need to execute a contract message pointing to the provide_liquidity
endpoint in the pair
contract for the selected pool.
assets
is the only required parameter and contains information about each token in the pair, including the contract address or native denomination and the amount to deposit.
For new pools, you can deposit any ratio of tokens in a pair. For existing pairs, the contract will throw an error message if the proper balance of ratios between tokens is not met.
Optional Parameters
provide_liqudity
takes up the following optional parameters:
slippage_tolerance
: Allows liquidity provision while the price of assets in a pool stays within a certain rangeauto_stake
: Determines whether the LP tokens minted for the user are auto staked in the Generator contract.receiver
: The receiver of LP tokens (if different from sender)
Coins
If the pair you are providing liquidity to contains a native asset, you will also need to send the native token along with the transaction message.
The code in this section is an example of what a provide_liquidity
message may look like using feather.js to send Coins with our transaction.
Calculating Deposit Amount
As noted above, the contract will throw an error message if the proper balance of ratios between tokens is not met.
In order to obtain the ratio of tokens that we need, we can simulate a swap and input our response as the amount
for one of our deposits.
simulation
The simulation
endpoint contains information about our offer asset and the amount to swap.
Our input amount
and response will gives us the proper ratio of tokens that we need to provide_liquidity
.
_9{_9 "increase_allowance": {_9 "spender": astrolunaAddress,_9 "amount": "1000000000000",_9 "expires": {_9 "never": {}_9 }_9 }_9}
Withdrawing Liquidity
withdraw_liquidity
To withdraw_liquidity
, you need to execute a contract message pointing to the send
endpoint in the CW20 contract of the LP token associated with the pair.
send includes the contract the tokens are being sent to (pair contract address), the amount to send (withdraw), and a binary encoded msg containing our contract call (withdraw: {}
).
_11{_11 "send": {_11 "contract": astrolunaAddress,_11 "amount": "10000000",_11 "msg": toBase64(_11 {_11 "withdraw_liquidity": {}_11 }_11 )_11 }_11}
Encoding our Msg
To encode our message, there are two common options:
- An online base64 encoder
- A custom function
The code in this section uses a custom function (toBase64
) to display our binary message - this function needs to be defined elsewhere to be used. The actual string representation of our message would be an encoded binary.
_11{_11 "send": {_11 "contract": astrolunaAddress,_11 "amount": "10000000",_11 "msg": toBase64(_11 {_11 "withdraw_liquidity": {}_11 }_11 )_11 }_11}
toBase64
The code in this section is an example of a withdraw_liquidity
message using feather.js to define our custom function and encode our message.
_35const astrolunaAddress = 'terra1udsua9w6jljwxwgwsegvt6v657rg3ayfvemupnes7lrggd28s0wq7g8azm';_35const astrolunaLPAddress = 'terra1886vn036tc9e7ejx8pe4nkhts3gwpdfegwc4n3u77n0q76fjdthqarl8uc';_35_35const toBase64 = (obj) => {_35 return Buffer.from(JSON.stringify(obj)).toString("base64");_35};_35_35const withdraw = new MsgExecuteContract(_35 wallet.key.accAddress('terra'),_35 astrolunaLPAddress,_35 {_35 "send": {_35 "contract": astrolunaAddress,_35 "amount": "10000000",_35 "msg": toBase64(_35 {_35 "withdraw_liquidity": {}_35 }_35 )_35 }_35 }_35)_35_35const fee = new Fee(2000000, { uluna: 200000 });_35_35// // BROADCAST TRANSACTION_35const tx = await wallet.createAndSignTx({_35 msgs: [withdraw],_35 fee,_35 chainID: 'pisco-1',_35});_35_35const result = await lcd.tx.broadcast(tx, 'pisco-1');_35_35console.log(result);
withdraw_liquidity
To withdraw_liquidity
, you need to execute a contract message pointing to the send
endpoint in the CW20 contract of the LP token associated with the pair.
send includes the contract the tokens are being sent to (pair contract address), the amount to send (withdraw), and a binary encoded msg containing our contract call (withdraw: {}
).
Encoding our Msg
To encode our message, there are two common options:
- An online base64 encoder
- A custom function
The code in this section uses a custom function (toBase64
) to display our binary message - this function needs to be defined elsewhere to be used. The actual string representation of our message would be an encoded binary.
toBase64
The code in this section is an example of a withdraw_liquidity
message using feather.js to define our custom function and encode our message.
_11{_11 "send": {_11 "contract": astrolunaAddress,_11 "amount": "10000000",_11 "msg": toBase64(_11 {_11 "withdraw_liquidity": {}_11 }_11 )_11 }_11}