Swapping
Overview
The pair contract for a given pool allows anyone to perform a swap
between the assets in a pair. Depending on the type of assets in the pair, a user could perform two types of swaps:
- Native swap (Native -> Native / Native -> CW20)
- CW20 swap (CW20 -> CW20 / CW20 -> Native)
A native swap will interact with the pair contract directly while a CW20 swap will interact with the CW20 token contract and be processed by the pair
contract as a Cw20HookMsg
.
Native Swap
Performs a native swap in a given pool.
Swap
Endpoint
To perform a native swap, you need to execute a contract message pointing to the swap
endpoint in the pair
contract for a given pool.
The swap
endpoint requires an offer_asset
parameter which contains information about the offer asset itself and the amount
to send.
_15{_15 "swap": {_15 "offer_asset": {_15 "info": {_15 "native_token": {_15 "denom": "uluna"_15 }_15 },_15 "amount": "100000"_15 }, _15 "belief_price": beliefPrice, _15 "max_spread": '0.005', _15 "to": "..."_15 }_15}
Coins
For native swaps, you need to send the native_token
along with the transaction message.
The code in this section is an example of what a swap
message may look like using feather.js to send Coins
with our transaction.
_29const astrolunaAddress = "terra1udsua9w6jljwxwgwsegvt6v657rg3ayfvemupnes7lrggd28s0wq7g8azm";_29_29const swap = new MsgExecuteContract(_29 wallet.key.accAddress('terra'),_29 astrolunaAddress,_29 {_29 "swap": {_29 "offer_asset": {_29 "info": {_29 "native_token": {_29 "denom": "uluna"_29 }_29 },_29 "amount": "100000"_29 }_29 }_29 },_29 new Coins({ uluna: '100000' })_29);_29_29const tx = await wallet.createAndSignTx({_29 msgs: [swap],_29 feeDenoms: ['uluna'],_29 chainID: 'pisco-1',_29});_29_29const result = await lcd.tx.broadcast(tx, 'pisco-1');_29_29console.log(result);
Optional Parameters
The swap
endpoint takes in the following optional parameters:
belief_price
: Expected return amountmax_spread
: The difference between the ask amount before and after the swap operation. If the swap spread exceeds the provided max limit, the swap will fail.to
: Address receiving tokens (if different from sender)
_15{_15 "swap": {_15 "offer_asset": {_15 "info": {_15 "native_token": {_15 "denom": "uluna"_15 }_15 },_15 "amount": "100000"_15 }, _15 "belief_price": beliefPrice, _15 "max_spread": '0.005', _15 "to": "..."_15 }_15}
Belief Price + Max Spread
If belief_price
is provided in combination with max_spread
, the pool will check the difference between the return amount (using belief_price
) and the real pool price.
The belief_price
+/- the max_spread
is the range of possible acceptable prices for this swap.
_15{_15 "swap": {_15 "offer_asset": {_15 "info": {_15 "native_token": {_15 "denom": "uluna"_15 }_15 },_15 "amount": "100000"_15 }, _15 "belief_price": beliefPrice, _15 "max_spread": '0.005', _15 "to": "..."_15 }_15}
Calculating the belief_price
To obtain the belief_price
, this tutorial uses two examples:
- Calculating the
belief_price
using the proportion of pool balances - Querying the
simulation
endpoint in the pair contract for which the swap is taking place
_15{_15 "swap": {_15 "offer_asset": {_15 "info": {_15 "native_token": {_15 "denom": "uluna"_15 }_15 },_15 "amount": "100000"_15 }, _15 "belief_price": beliefPrice, _15 "max_spread": '0.005', _15 "to": "..."_15 }_15}
Pool
Endpoint
To calculate the belief_price
using the proportion of pool balances, we first need to fetch the amount of each asset in the pool. This can be done by calling the pool
endpoint in the pair contract.
The code in this section is an example of using feather.js to query the pair contract, perform calculations with our response, and store the results in a variable to use as an input for our swap message.
_3const astrolunaAddress = "terra1udsua9w6jljwxwgwsegvt6v657rg3ayfvemupnes7lrggd28s0wq7g8azm";_3const { assets } = await lcd.wasm.contractQuery(astrolunaAddress, { "pool": {} });_3const beliefPrice = (assets[0].amount / assets[1].amount).toFixed(18);
Simulation
Enpoint
Astroport's native solution for calculating the belief_price
is the simulation
query.
The query takes in an offer_asset
which contains information about the native token and an amount to send.
_12{_12 "simulation": {_12 "offer_asset": {_12 "info": {_12 "native_token": {_12 "denom": "uluna"_12 }_12 },_12 "amount": "100000"_12 }_12 }_12}
Normalizing Values
Depending on the token decimal for the assets you are swapping, you may need to normalize the response from the simulation
query before passing it into your swap
message.
The code in this section is an example of using feather.js to perform the simulation
query, normalize the response, and store the results for later usage.
_21const astrolunaAddress = "terra1udsua9w6jljwxwgwsegvt6v657rg3ayfvemupnes7lrggd28s0wq7g8azm";_21const offeredlunaAmount = "100000"_21let beliefPrice;_21_21const simulation = await lcd.wasm.contractQuery(_21astrolunaAddress, _21{_21 "simulation": {_21 "offer_asset": {_21 "info": {_21 "native_token": {_21 "denom": "uluna"_21 }_21 },_21 "amount": offeredlunaAmount_21 }_21 }_21}_21).then(result => { beliefPrice = result.return_amount });_21_21beliefPrice = (beliefPrice / offeredlunaAmount).toFixed(18);
Swap
Endpoint
To perform a native swap, you need to execute a contract message pointing to the swap
endpoint in the pair
contract for a given pool.
The swap
endpoint requires an offer_asset
parameter which contains information about the offer asset itself and the amount
to send.
Coins
For native swaps, you need to send the native_token
along with the transaction message.
The code in this section is an example of what a swap
message may look like using feather.js to send Coins
with our transaction.
Optional Parameters
The swap
endpoint takes in the following optional parameters:
belief_price
: Expected return amountmax_spread
: The difference between the ask amount before and after the swap operation. If the swap spread exceeds the provided max limit, the swap will fail.to
: Address receiving tokens (if different from sender)
Belief Price + Max Spread
If belief_price
is provided in combination with max_spread
, the pool will check the difference between the return amount (using belief_price
) and the real pool price.
The belief_price
+/- the max_spread
is the range of possible acceptable prices for this swap.
Calculating the belief_price
To obtain the belief_price
, this tutorial uses two examples:
- Calculating the
belief_price
using the proportion of pool balances - Querying the
simulation
endpoint in the pair contract for which the swap is taking place
Pool
Endpoint
To calculate the belief_price
using the proportion of pool balances, we first need to fetch the amount of each asset in the pool. This can be done by calling the pool
endpoint in the pair contract.
The code in this section is an example of using feather.js to query the pair contract, perform calculations with our response, and store the results in a variable to use as an input for our swap message.
Simulation
Enpoint
Astroport's native solution for calculating the belief_price
is the simulation
query.
The query takes in an offer_asset
which contains information about the native token and an amount to send.
Normalizing Values
Depending on the token decimal for the assets you are swapping, you may need to normalize the response from the simulation
query before passing it into your swap
message.
The code in this section is an example of using feather.js to perform the simulation
query, normalize the response, and store the results for later usage.
_15{_15 "swap": {_15 "offer_asset": {_15 "info": {_15 "native_token": {_15 "denom": "uluna"_15 }_15 },_15 "amount": "100000"_15 }, _15 "belief_price": beliefPrice, _15 "max_spread": '0.005', _15 "to": "..."_15 }_15}
CW20 Swap
Performs a CW20 swap in a given pool.
Cw20HookMsg
To perform a CW20 swap, you need to execute a contract message pointing to the send
endpoint in the CW20 contract of the token you are swapping.
send
includes the contract
the tokens are being sent to (pair contract address), the amount
to send/swap, and a binary encoded msg
containing our contract call.
_20{_20 "send": {_20 "contract": astrolunaAddress, _20 "amount": "1000000", _20 "msg": toBase64(_20 {_20 "swap": {_20 "ask_asset_info": {_20 "native_token": {_20 "denom": "uluna"_20 }_20 }, _20 "belief_price": beliefPrice, _20 "max_spread": "0.005", _20 "to": "..."_20 }_20 }_20 )_20 }_20}
swap
parameters
Our swap message takes in our ask_asset_info
, belief_price
, max_spread
, and the address tokens are being sent to
(if diffent from the sender).
If belief_price
is provided in combination with max_spread
, the pool will check the difference between the return amount (using belief_price
) and the real pool price. The belief_price
+/- the max_spread
creates a range of possible acceptable prices for this swap.
_20{_20 "send": {_20 "contract": astrolunaAddress, _20 "amount": "1000000", _20 "msg": toBase64(_20 {_20 "swap": {_20 "ask_asset_info": {_20 "native_token": {_20 "denom": "uluna"_20 }_20 }, _20 "belief_price": beliefPrice, _20 "max_spread": "0.005", _20 "to": "..."_20 }_20 }_20 )_20 }_20}
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.
_20{_20 "send": {_20 "contract": astrolunaAddress, _20 "amount": "1000000", _20 "msg": toBase64(_20 {_20 "swap": {_20 "ask_asset_info": {_20 "native_token": {_20 "denom": "uluna"_20 }_20 }, _20 "belief_price": beliefPrice, _20 "max_spread": "0.005", _20 "to": "..."_20 }_20 }_20 )_20 }_20}
toBase64
Encoder
The code in this section is an example of what a send
message may look like feather.js to define our custom function and encode our message.
_27const toBase64 = (obj) => {_27 return Buffer.from(JSON.stringify(obj)).toString("base64");_27};_27_27const cw20Swap = new MsgExecuteContract(_27 wallet.key.accAddress('terra'),_27 astroAddress,_27 {_27 "send": {_27 "contract": astrolunaAddress, _27 "amount": "1000000", _27 "msg": toBase64(_27 {_27 "swap": {_27 "ask_asset_info": {_27 "native_token": {_27 "denom": "uluna"_27 }_27 }, _27 "belief_price": beliefPrice, _27 "max_spread": "0.005"_27 }_27 }_27 )_27 }_27 }_27)
Calculating the belief_price
Lastly, calculating the belief_price
for CW20 swaps is similar to doing so for native swaps. To learn more about this topic, refer to the section above.
The exception is the info
parameter in our simulation
query which is derived from an AssetInfo
enum. For CW20 swaps, instead of using native_token
and denom
, use token
and contract_addr
.
_12{_12 "simulation": {_12 "offer_asset": {_12 "info": {_12 "token": {_12 "contract_addr": astrolunaAddress_12 }_12 },_12 "amount": "1000000"_12 }_12 }_12}
Cw20HookMsg
To perform a CW20 swap, you need to execute a contract message pointing to the send
endpoint in the CW20 contract of the token you are swapping.
send
includes the contract
the tokens are being sent to (pair contract address), the amount
to send/swap, and a binary encoded msg
containing our contract call.
swap
parameters
Our swap message takes in our ask_asset_info
, belief_price
, max_spread
, and the address tokens are being sent to
(if diffent from the sender).
If belief_price
is provided in combination with max_spread
, the pool will check the difference between the return amount (using belief_price
) and the real pool price. The belief_price
+/- the max_spread
creates a range of possible acceptable prices for this swap.
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
Encoder
The code in this section is an example of what a send
message may look like feather.js to define our custom function and encode our message.
Calculating the belief_price
Lastly, calculating the belief_price
for CW20 swaps is similar to doing so for native swaps. To learn more about this topic, refer to the section above.
The exception is the info
parameter in our simulation
query which is derived from an AssetInfo
enum. For CW20 swaps, instead of using native_token
and denom
, use token
and contract_addr
.
_20{_20 "send": {_20 "contract": astrolunaAddress, _20 "amount": "1000000", _20 "msg": toBase64(_20 {_20 "swap": {_20 "ask_asset_info": {_20 "native_token": {_20 "denom": "uluna"_20 }_20 }, _20 "belief_price": beliefPrice, _20 "max_spread": "0.005", _20 "to": "..."_20 }_20 }_20 )_20 }_20}