AMM (Automated Market Maker)

This tutorial explains how to set up all the smart contracts using CLI for the creation of an AMM application. For this tutorial we are going to deploy one of the most popular AMMs built with CosmWasm, Astroport.

Prerequisites

To complete this tutorial, you need to:

  • Install rust and cargo.
  • Have a general understanding of how the Coreum blockchain works.
  • Follow the instruction to install cored binary.
  • Install the required util: jq.
  • Set the network variables for the development (testnet is preferable).

Getting Started

  • Generate a new wallet that is going to be the admin account of the contracts.
RES=$(cored keys add wallet $COREUM_CHAIN_ID_ARGS --output json)
OWNER=$(echo $RES | jq -r '.address')
echo $OWNER

Output example:

testcore1hpgxerhcnzjqpxpt4qpncrr7sdyzvuekzendeh
  • Use the faucet to fund your account

  • Clone the astroport repository with all the smart contracts.

git clone [email protected]:astroport-fi/astroport-core.git
  • Build all optimized smart contracts:
./scripts/build_release.sh

This will generate all the optimized smart contracts that we are going to deploy in the /artifacts directory.

Deploy and Instantiate Contracts

We are going to deploy all the contracts that we need first, store their Code ID and instantiate them with example configurations to set up an initial version of the AMM.

  • Deploy the token contract.
RES=$(cored tx wasm store artifacts/astroport_token.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_TOKEN=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_TOKEN

Output example:

138

This contract is a CW20 token implementation. It will be used to create our AMM token, which will be used for rewarding liquidity providers and allowing users to stake it on a staking contract to obtain fees generated by the AMM. It can also be used for governance if we decide to make our AMM decentralized and run by the stakers of our token. For simplicity we are not going to include the governance contracts in this tutorial. On top of this, it will also be used by liquidity pools to create their LP token representation.

  • Create our AMM token.

For simplicity, we are going to create our AMM token without any recipients. In reality, these tokens are created with initial addresses receiving it or sent to a contract that will airdrop them to users or sell them using an ICO, for example.

INIT='{"name":"MYAMMTOKEN", "symbol":"TOKENSYMBOL", "decimals":6, "initial_balances": [],"mint":{"minter":'\""$OWNER"\"'}}'
cored tx wasm instantiate $CODE_ID_TOKEN "$INIT" --from wallet --label "mytoken" -b block -y --no-admin $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
  • Check the contract address.
cored q wasm list-contract-by-code $CODE_ID_TOKEN --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_TOKEN=$(cored q wasm list-contract-by-code $CODE_ID --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_TOKEN

Output example:

{"contracts":["testcore19ns9lr7rmqykjrmphlwqg4x452aanelp36kj6hfy2zjhgy70e7ns6h7q4m"],"pagination":{"next_key":null,"total":"0"}}
testcore19ns9lr7rmqykjrmphlwqg4x452aanelp36kj6hfy2zjhgy70e7ns6h7q4m

This contract address is the contract of our AMM token. We will use it for the instantiation of future contracts in this documentation.

  • Deploy the pool contracts. For this example we are going to deploy two contracts, one for a normal xyk pool and one for a stablecoin pool.
RES=$(cored tx wasm store artifacts/astroport_pair.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_PAIR=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_PAIR

Output example:

139
RES=$(cored tx wasm store artifacts/astroport_pair_stable.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_PAIR_STABLE=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_PAIR_STABLE

Output example:

141

These two contract IDs will be used by the factory contract that will control the creation of these pools.

  • Deploy the whitelist contract.

This contract is used to store 3rd party rewards. We might not use this contract but the code is required by other contracts in case it is used, so we will also deploy it.

RES=$(cored tx wasm store artifacts/astroport_whitelist.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_WHITELIST=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_WHITELIST

Output example:

142
  • Deploy and instantiate the coin registry contract.

This contract keeps information regarding coins and is updated by the owner of the contract.

RES=$(cored tx wasm store artifacts/astroport_native_coin_registry.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_REGISTRY=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_REGISTRY

Output example:

143
INIT='{"owner":'\""$OWNER"\"'}'
cored tx wasm instantiate $CODE_ID_REGISTRY "$INIT" --from wallet --label "registry" -b block -y --no-admin $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Check the contract address.

cored q wasm list-contract-by-code $CODE_ID_REGISTRY --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_REGISTRY=$(cored q wasm list-contract-by-code $CODE_ID_REGISTRY --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_REGISTRY

Output example:

{"contracts":["testcore1u8qeahf3aql7xzx25lamtwafrrc63khtwwsg32t9x8azaqa3p6zs2nsekz"],"pagination":{"next_key":null,"total":"0"}}
testcore1u8qeahf3aql7xzx25lamtwafrrc63khtwwsg32t9x8azaqa3p6zs2nsekz
  • Deploy and instantiate the factory contract.

This is a key contract in the functionality of the AMM. It will keep manage the creation of pools and will also be used by a router contract to route the trades that users perform to the correct pools.

RES=$(cored tx wasm store artifacts/astroport_factory.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_FACTORY=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_FACTORY

Output example:

144
INIT='{"pair_configs":[{"code_id":'"$CODE_ID_PAIR"', "pair_type": {"xyk":{}}, "total_fee_bps": 1000, "maker_fee_bps": 500, "is_disabled":false, "is_generator_disabled":false}, {"code_id":'"$CODE_ID_PAIR_STABLE"', "pair_type": {"stable":{}}, "total_fee_bps": 1000, "maker_fee_bps": 500, "is_disabled":false, "is_generator_disabled":false}], "token_code_id": '"$CODE_ID_TOKEN"', "owner": '\""$OWNER"\"', "whitelist_code_id": '"$CODE_ID_WHITELIST"', "coin_registry_address": '\""$CONTRACT_ADDRESS_REGISTRY"\"'}'
cored tx wasm instantiate $CODE_ID_FACTORY "$INIT" --from wallet --label "factory" -b block -y --no-admin $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Here we are instantiating the factory providing the two types of pools that we can create from it. We are also providing two types of fees: the total fees taken from each swap of that particular pool and what part of the fees are going to the maker contract, which will decide the split between staking contract and governance contract, if they exist.

Check the contract address.

cored q wasm list-contract-by-code $CODE_ID_FACTORY --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_FACTORY=$(cored q wasm list-contract-by-code $CODE_ID_FACTORY --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_FACTORY

Output example:

{"contracts":["testcore1elu53425cx02hh372j5ernkqndjmg524jfvwug6fgee8kte9p0xs937nxq"],"pagination":{"next_key":null,"total":"0"}}
testcore1elu53425cx02hh372j5ernkqndjmg524jfvwug6fgee8kte9p0xs937nxq
  • Deploy and instantiate the router contract.

This contract will interact with the factory contract to route the swaps to the correct pools.

RES=$(cored tx wasm store artifacts/astroport_router.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_ROUTER=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_ROUTER

Output example:

145

Now we instantiate the contract

INIT='{"astroport_factory": '\""$CONTRACT_ADDRESS_FACTORY"\"'}'
cored tx wasm instantiate $CODE_ID_ROUTER "$INIT" --from wallet --label "router" -b block -y --no-admin $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Check the contract address.

cored q wasm list-contract-by-code $CODE_ID_ROUTER --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_ROUTER=$(cored q wasm list-contract-by-code $CODE_ID_ROUTER --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_ROUTER

Output example:

{"contracts":["testcore1z8v4w2qsv3eww9jwwh2a7ha2vzez6w52tnu0mvqxd4gwq3j72ytqa8h82q"],"pagination":{"next_key":null,"total":"0"}}
testcore1z8v4w2qsv3eww9jwwh2a7ha2vzez6w52tnu0mvqxd4gwq3j72ytqa8h82q
  • Deploy and instantiate the vesting contract.

This contract is the contract that will store the funds of the AMM token that we created before so that liquidity providers can be rewarded. We will define a vesting schedule for the rewards and the generator contract will claim the rewards for the users using this vesting contract and send it to them (if the vesting period of the claimable amount has passed). The admin will be in charge of sending the funds to this vesting contract to define the vesting schedules for the generator so that users can claim their rewards.

RES=$(cored tx wasm store artifacts/astroport_vesting.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_VESTING=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_VESTING

Output example:

146
INIT='{"owner": '\""$OWNER"\"', "vesting_token": {"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}}'
cored tx wasm instantiate $CODE_ID_VESTING "$INIT" --from wallet --label "vesting" -b block -y --no-admin $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Check the contract address.

cored q wasm list-contract-by-code $CODE_ID_VESTING --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_VESTING=$(cored q wasm list-contract-by-code $CODE_ID_VESTING --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_VESTING

Output example:

{"contracts":["testcore1w0thqs07f4plnthqxhss0gxqayvsdhdlg6sma5waat5647h5z5zqysr2v5"],"pagination":{"next_key":null,"total":"0"}}
testcore1w0thqs07f4plnthqxhss0gxqayvsdhdlg6sma5waat5647h5z5zqysr2v5
  • Deploy and instantiate the generator contract.
RES=$(cored tx wasm store artifacts/astroport_generator.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_GENERATOR=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_GENERATOR

Output example:

147
INIT='{"owner": '\""$OWNER"\"', "factory": '\""$CONTRACT_ADDRESS_FACTORY"\"', "astro_token": {"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}, "tokens_per_block": "100", "start_block": "400000", "vesting_contract": '\""$CONTRACT_ADDRESS_VESTING"\"', "whitelist_code_id": '"$CODE_ID_WHITELIST"'}'
cored tx wasm instantiate $CODE_ID_GENERATOR "$INIT" --from wallet --label "generator" -b block -y --no-admin --gas auto --gas-adjustment 1.3  $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Check the contract address.

cored q wasm list-contract-by-code $CODE_ID_GENERATOR --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_GENERATOR=$(cored q wasm list-contract-by-code $CODE_ID_GENERATOR --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_GENERATOR

Output example:

{"contracts":["testcore1jj99qm2de8eqdyfzzqdny7cj40gt0c84j3wesatlrx4gl98hzq5qx76mf4"],"pagination":{"next_key":null,"total":"0"}}
testcore1jj99qm2de8eqdyfzzqdny7cj40gt0c84j3wesatlrx4gl98hzq5qx76mf4

Now that we have set up our generator and vesting contract, users that provide liquidity to the pool can interact with the generator contract to claim rewards from the vesting contract that have been previously sent by the admin/owner of the AMM.

  • Deploy and instantiate the staking contract.

This contract will be used by the users who want to earn AMM fees. They will stake the AMM token that they've previously bought or received for providing liquidity into this contract and they can claim their share of the collected fees that are sent here by the Maker contract.

RES=$(cored tx wasm store artifacts/astroport_staking.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_STAKING=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_STAKING

Output example:

148
INIT='{"owner": '\""$OWNER"\"', "token_code_id": '"$CODE_ID_TOKEN"', "deposit_token_addr": '\""$CONTRACT_ADDRESS_TOKEN"\"'}'
cored tx wasm instantiate $CODE_ID_STAKING "$INIT" --from wallet --label "staking" -b block -y --no-admin --gas auto --gas-adjustment 1.3 $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
cored q wasm list-contract-by-code $CODE_ID_STAKING --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_STAKING=$(cored q wasm list-contract-by-code $CODE_ID_STAKING --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_STAKING

Output example:

{"contracts":["testcore1rec0q89ufhj49hy0z799fz5mnhpx3getcndd56q8vepgx9fwlrjsvan29l"],"pagination":{"next_key":null,"total":"0"}}
testcore1rec0q89ufhj49hy0z799fz5mnhpx3getcndd56q8vepgx9fwlrjsvan29l
  • Deploy and instantiate the maker contract.

The last contract we are going to deploy is the Maker contract. This contract is also very important in the overall functionality of the AMM. It is basically in charge of collecting all the fees from the swaps, swapping them into our AMM token and distribute them to the staking contract and/or governance fee contract. In the case of this tutorial setup, all the fees are going to our staking contract.

RES=$(cored tx wasm store artifacts/astroport_maker.wasm \
    --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS)
CODE_ID_MAKER=$(echo $RES | jq -r '.logs[0].events[-1].attributes[-1].value')
echo $CODE_ID_MAKER

Output example:

149
INIT='{"owner": '\""$OWNER"\"', "astro_token": {"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}, "factory_contract": '\""$CONTRACT_ADDRESS_FACTORY"\"', "staking_contract": '\""$CONTRACT_ADDRESS_STAKING"\"'}'
cored tx wasm instantiate $CODE_ID_MAKER "$INIT" --from wallet --label "staking" -b block -y --no-admin --gas auto --gas-adjustment 1.3 $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
cored q wasm list-contract-by-code $CODE_ID_MAKER --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS
CONTRACT_ADDRESS_MAKER=$(cored q wasm list-contract-by-code $CODE_ID_MAKER --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS | jq -r '.contracts[-1]')
echo $CONTRACT_ADDRESS_MAKER

Output example:

{"contracts":["testcore1s9zwarj2swhlp3wqysep5e67gyem09y3narlc2mx3ntrg885ll7sang6rw"],"pagination":{"next_key":null,"total":"0"}}
testcore1s9zwarj2swhlp3wqysep5e67gyem09y3narlc2mx3ntrg885ll7sang6rw

Now we have all the contracts deployed, instantiated and connected with each other.

Last steps

Even though we deployed and instantiated all the contracts, we still need to adjust the factory contract to include the addresses of the maker and generator contract. We could not do this during instantiation of the factory contract because we did not have this information at that time.

  • Set factory parameters accordingly.
EXEC='{"update_config": {"fee_address": '\""$CONTRACT_ADDRESS_MAKER"\"', "generator_address": '\""$CONTRACT_ADDRESS_GENERATOR"\"'}}'
cored tx wasm execute $CONTRACT_ADDRESS_FACTORY "$EXEC" --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

And now, we finally have our AMM completely set up.

AMM Interaction

Now that all the core AMM contracts are deployed and instantiated, we can start interacting with them. Each contract is used for different operations. Let's do some example basic operations to test the core functionality of our AMM.

  • Create a liquidity pool.

Even though everything is working, we still don't have any pools for users to swap tokens or to provide liquidity, let's create a standard xyk pool using our admin account. This is done through the factory contract.

EXEC='{"create_pair": {"pair_type":{"xyk":{}}, "asset_infos": [{"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}, {"native_token": {"denom": "utestcore"}}]}}'
cored tx wasm execute $CONTRACT_ADDRESS_FACTORY "$EXEC" --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Let's confirm that we created the pair, and get the contract address of the pool.

QUERY='{"pair": {"asset_infos": [{"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}, {"native_token": {"denom": "utestcore"}}]}}'
RES=$(cored query wasm contract-state smart $CONTRACT_ADDRESS_FACTORY "$QUERY" $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS --output json)
CONTRACT_ADDRESS_POOL=$(echo $RES | jq -r '.data.contract_addr')
LIQUIDITY_TOKEN=$(echo $RES | jq -r '.data.liquidity_token')
echo $CONTRACT_ADDRESS_POOL
echo $LIQUIDITY_TOKEN

Output example:

testcore1kk95dde8e5793ztnzve66gqnxj39x7j3736nkxt6xxdevugqwndq2jv3cv
testcore1e27xcswyzjf88d9uc634lh9u5vu8mgl94xue6f54p7g930lkjvfsxvay3c

This created a liquidity pool of 2 tokens. The first one is the AMM token that we created at the start of this tutorial, which is a CW20 implementation (hence the contract_addr field), and the second one is the native testnet token. Also, in this case and as shown in the output above, the address of this liquidity pool contract is testcore1kk95dde8e5793ztnzve66gqnxj39x7j3736nkxt6xxdevugqwndq2jv3cv and the token that will be minted and given to liquidity pool providers is testcore1e27xcswyzjf88d9uc634lh9u5vu8mgl94xue6f54p7g930lkjvfsxvay3c (which will be used later to incentivize the pool through the generator contract).

Now that this liquidity pool is created, we can add the initial liquidity to it.

  • Provide liquidity to the pool.

Since we need both tokens to add liquidity, we will first mint some "MYAMMTOKEN" to our address, since we don't have any yet.

EXEC='{"mint": {"recipient": '\""$OWNER"\"', "amount": "1000000000"}}'
cored tx wasm execute $CONTRACT_ADDRESS_TOKEN "$EXEC" --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Now that we have both tokens, let's add liquidity to the pool we created before. We will first give allowance to the contract so that it can correctly transfer the CW20 tokens from the sender wallet into the contract during the provide liquidity action.

EXEC='{"increase_allowance": {"spender": '\""$CONTRACT_ADDRESS_POOL"\"', "amount": "1000000"}}'
cored tx wasm execute $CONTRACT_ADDRESS_TOKEN "$EXEC" --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Now let's provide liquidity.

EXEC='{"provide_liquidity": {"assets": [{"info":{"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}, "amount": "1000000"}, {"info":{"native_token": {"denom":"utestcore"}}, "amount": "1000000"}]}}'
cored tx wasm execute $CONTRACT_ADDRESS_POOL "$EXEC" --amount 1000000utestcore --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Now we've correctly provided liquidity to the pool. Let's query the pool to check.

QUERY='{"pool":{}}'
cored query wasm contract-state smart $CONTRACT_ADDRESS_POOL "$QUERY" $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Output example:

data:
  assets:
  - amount: "1000000"
    info:
      token:
        contract_addr: testcore19ns9lr7rmqykjrmphlwqg4x452aanelp36kj6hfy2zjhgy70e7ns6h7q4m
  - amount: "1000000"
    info:
      native_token:
        denom: utestcore
  total_share: "1000000"

We can see that we have both assets inside the pool.

  • Swap assets from the pool.

Now that we have assets in the pool, let's perform a swap between them. To do this, we will use the router contract. We will try to swap utestcore into the AMM token.

EXEC='{"execute_swap_operations": {"operations": [{"astro_swap": {"offer_asset_info":{"native_token": {"denom": "utestcore"}}, "ask_asset_info": {"token": {"contract_addr":'\""$CONTRACT_ADDRESS_TOKEN"\"'}}}}], "max_spread": "0.1"}}'
cored tx wasm execute $CONTRACT_ADDRESS_ROUTER "$EXEC" --amount 10utestcore --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Let's query the pool again to see the balance change after the swap.

QUERY='{"pool":{}}'
cored query wasm contract-state smart $CONTRACT_ADDRESS_POOL "$QUERY" $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Output example:

data:
  assets:
  - amount: "999991"
    info:
      token:
        contract_addr: testcore19ns9lr7rmqykjrmphlwqg4x452aanelp36kj6hfy2zjhgy70e7ns6h7q4m
  - amount: "1000010"
    info:
      native_token:
        denom: utestcore
  total_share: "1000000"

As we can see, we've received 9 AMM tokens after putting in 10 utestcore and the balances of the pool are correctly updated.

  • Add our liquidity pool to the incentivized list of pools in the generator.

Right now our pool is fully functional but it's not being incentivized with AMM token rewards through the vesting contract. To do this, we are going to add it to the list of pools in the generator contract. We must incentivize the LP token corresponding to the pool.

EXEC='{"setup_pools": {"pools": [['\""$LIQUIDITY_TOKEN"\"', "1"]]}}'
cored tx wasm execute $CONTRACT_ADDRESS_GENERATOR "$EXEC" --from wallet --gas auto --gas-adjustment 1.3 -y -b block --output json $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

We can now query the generator to see if our pool is in the active pool list.

QUERY='{"config":{}}'
cored query wasm contract-state smart $CONTRACT_ADDRESS_GENERATOR "$QUERY" $COREUM_NODE_ARGS $COREUM_CHAIN_ID_ARGS

Output example:

data:
  active_pools:
  - - testcore1e27xcswyzjf88d9uc634lh9u5vu8mgl94xue6f54p7g930lkjvfsxvay3c
    - "1"
  astro_token:
    token:
      contract_addr: testcore19ns9lr7rmqykjrmphlwqg4x452aanelp36kj6hfy2zjhgy70e7ns6h7q4m
  blocked_tokens_list: []
  checkpoint_generator_limit: null
  factory: testcore1elu53425cx02hh372j5ernkqndjmg524jfvwug6fgee8kte9p0xs937nxq
  generator_controller: null
  guardian: null
  owner: testcore1hpgxerhcnzjqpxpt4qpncrr7sdyzvuekzendeh
  start_block: "400000"
  tokens_per_block: "100"
  total_alloc_point: "1"
  vesting_contract: testcore1w0thqs07f4plnthqxhss0gxqayvsdhdlg6sma5waat5647h5z5zqysr2v5
  voting_escrow: null
  voting_escrow_delegation: null

We can see that the LP token of our newly created pool is in the list of active pools being rewarded with a "1" allocation point. If we wanted to incentivize another pool equally to this pool, we would also give it a "1" allocation point. If we wanted to incentivize it more, we would increase this number. This way we can control how all pools are incentivized.

In this example, the generator will reward with 100 tokens per block, starting from block 400000. Every time a user tries to claim, it will try to take the funds from the vesting contract, so the admin of the AMM is responsible of keeping that vesting contract correctly funded.

As we can also see, the AMM is fully functional, and supports all operations through CLI. In a real case scenario, we might not have an admin account doing all this manually, instead we might have a multisig account or a DAO controlling all AMM admin operations.