Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions codewithus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Code with Us Workshop - Nov 03 2020
Make your own Automated Market-Maker, using the new Cosmos SDK Bonds Module

- Discover the new Cosmos-SDK Bonds module, the Automated Market-Maker (AMM) with universal bonding curves. The workshop will be hosted by [Miguel Dingli](https://twitter.com/MiguelDingli), the lead developer of this module, and [Shaun Conway](https://twitter.com/shaunbconway), founder of ixo.
- Learn how to configure your first AMM using a simple bonding curve for algorithmic pricing. Then we will move onto more advanced types such as Uniswap-type token pair swappers and Augmented Bonding Curves.

## Resources

- Repository (_you're already here_): https://github.com/ixoworld/bonds/
- Medium article: https://medium.com/ixo-blog/cosmic-bonding-4f948dd4c2e4
- Risk-Adjusted Bonding Burves: https://github.com/BlockScience/InterchainFoundation/
- Alpha Bonds: https://www.alphabond.org/
- Part of the [Code with Us](https://cosmos.network/series/code-with-us) online workshop series.

## Installation Requirements

- Golang 1.13+
- Make (to run Makefile)
- Bash (for demo scripts)

Note: check out the [main README](../README.md) for instructions on how to quickly run the app.

## Workshop Agenda

- Introduction
- [_Demo 1_](./demo_1_power.sh): Create a Simple Bonding Curve for Algorithmic Pricing
- [_Demo 2_](./demo_2_swapper.sh): Create a Uniswap-Like AMM
- [_Demo 3_](./demo_3_augmented.sh): Create an Augmented Bonding Curve
- Alpha Bonds
70 changes: 70 additions & 0 deletions codewithus/demo_1_power.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash

ALICE=$(bondscli keys show alice --keyring-backend=test -a)
BOB=$(bondscli keys show bob --keyring-backend=test -a)
FEE=$(bondscli keys show fee --keyring-backend=test -a)

# Visual representation of bonding curve:
# https://www.desmos.com/calculator/2ael5dojku

# Create a Power Function bonding curve
bondscli tx bonds create-bond \
--token=mytoken \
--name="My Token" \
--description="My first continuous token" \
--function-type=power_function \
--function-parameters="m:12,n:2,c:100" \
--reserve-tokens=uatom \
--tx-fee-percentage=0 \
--exit-fee-percentage=0 \
--fee-address="$FEE" \
--max-supply=1000000mytoken \
--order-quantity-limits="" \
--sanity-rate="0" \
--sanity-margin-percentage="0" \
--allow-sells \
--signers="$ALICE" \
--batch-blocks=3 \
--from alice --keyring-backend=test --broadcast-mode block -y
# Query the created bond
bondscli q bonds bond mytoken
# We can keep an eye on the batch
watch -n 1 bondscli q bonds batch mytoken

# Query the price of buying 10mytoken
bondscli q bonds buy-price 10mytoken
# Query the token price at supply=10mytoken
bondscli q bonds price 10mytoken

# Buy 10mytoken from alice with max spend of 1000000uatom
bondscli tx bonds buy 10mytoken 1000000uatom --from alice --keyring-backend=test --broadcast-mode block -y
# Wait for order to get processed
sleep 21
# Query alice's account
bondscli q account "$ALICE"

# Query the price of buying 10mytoken
bondscli q bonds buy-price 10mytoken
# Query the token price at supply=20mytoken
bondscli q bonds price 20mytoken

# Buy 10mytoken from bob with max spend of 1000000uatom
bondscli tx bonds buy 10mytoken 1000000uatom --from bob --keyring-backend=test --broadcast-mode block -y
# Wait for order to get processed
sleep 21
# Query bob's account
bondscli q account "$BOB"

# Sell 10mytoken from alice at a profit :]
bondscli tx bonds sell 10mytoken --from alice --keyring-backend=test --broadcast-mode block -y
# Wait for order to get processed
sleep 21
# Query alice's account
bondscli q account "$ALICE"

# Sell 10mytoken from bob at a loss :[
bondscli tx bonds sell 10mytoken --from bob --keyring-backend=test --broadcast-mode block -y
# Wait for order to get processed
sleep 21
# Query bob's account
bondscli q account "$BOB"
75 changes: 75 additions & 0 deletions codewithus/demo_2_swapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash

ALICE=$(bondscli keys show alice --keyring-backend=test -a)
BOB=$(bondscli keys show bob --keyring-backend=test -a)
FEE=$(bondscli keys show fee --keyring-backend=test -a)

# Visual representation of liquidity pool:
# https://www.desmos.com/calculator/plmzg2hboo

# Create liquidity pool
bondscli tx bonds create-bond \
--token=atombtcpool \
--name="ATOM-BTC Pool" \
--description="An ATOM-BTC Liquidity Pool" \
--function-type=swapper_function \
--function-parameters="" \
--reserve-tokens=uatom,ubtc \
--tx-fee-percentage=0.5 \
--exit-fee-percentage=0.1 \
--fee-address="$FEE" \
--max-supply=1000000atombtcpool \
--order-quantity-limits="30000000000uatom,100000000ubtc" \
--sanity-rate="3000" \
--sanity-margin-percentage="10" \
--allow-sells \
--signers="$ALICE" \
--batch-blocks=1 \
--from alice --keyring-backend=test --broadcast-mode block -y
# Query the created bond
bondscli q bonds bond atombtcpool

# Alice adds liquidity (+10atombtcpool -3000ATOM -1BTC)
bondscli tx bonds buy 10atombtcpool 3000000000uatom,1000000ubtc --from alice --keyring-backend=test --broadcast-mode block -y
# Query alice's account
bondscli q account "$ALICE"

# Bob adds liquidity (+100atombtcpool with max prices 310,000ATOM and 110BTC)
bondscli tx bonds buy 1000atombtcpool 310000000000uatom,110000000ubtc --from bob --keyring-backend=test --broadcast-mode block -y
# Query bob's account
bondscli q account "$BOB"

# Query the swap returns from 3000ATOM to BTC (expected to be ~1BTC before fees)
bondscli q bonds swap-return atombtcpool 3000000000uatom ubtc
# Query the swap returns from 1BTC to ATOM (expected to be ~3000ATOM before fees)
bondscli q bonds swap-return atombtcpool 1000000ubtc uatom

# Alice swaps 3000ATOM to BTC at the current rate
bondscli tx bonds swap atombtcpool 3000000000 uatom ubtc --from alice --keyring-backend=test --broadcast-mode block -y
# Query alice's account
bondscli q account "$ALICE"

# Bob swaps 1BTC to ATOM at the current rate
bondscli tx bonds swap atombtcpool 1000000 ubtc uatom --from bob --keyring-backend=test --broadcast-mode block -y
# Query bob's account
bondscli q account "$BOB"

# Alice tries to swap above the order limit
bondscli tx bonds swap atombtcpool 30000000001 uatom ubtc --from alice --keyring-backend=test --broadcast-mode block -y
# Query alice's account [no changes]
bondscli q account "$ALICE"

# Bob tries to swap but violates sanity rates (tx successful but order will fail)
bondscli tx bonds swap atombtcpool 100000000 ubtc uatom --from bob --keyring-backend=test --broadcast-mode block -y
# Query bob's account [no changes]
bondscli q account "$BOB"

# Alice removes liquidity (-10atombtcpool +uatom +ubtc)
bondscli tx bonds sell 10atombtcpool --from alice --keyring-backend=test --broadcast-mode block -y
# Query alice's account
bondscli q account "$ALICE"

# Bob removes liquidity (-1000atombtcpool +uatom +ubtc)
bondscli tx bonds sell 1000atombtcpool --from bob --keyring-backend=test --broadcast-mode block -y
# Query bob's account
bondscli q account "$BOB"
90 changes: 90 additions & 0 deletions codewithus/demo_3_augmented.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env bash

ALICE=$(bondscli keys show alice --keyring-backend=test -a) # organiser
FEE=$(bondscli keys show fee --keyring-backend=test -a) # funding pool

bondscli keys add p1 --keyring-backend=test
bondscli keys add p2 --keyring-backend=test
bondscli keys add p3 --keyring-backend=test

P1=$(bondscli keys show p1 --keyring-backend=test -a) # participant 1 (new account)
P2=$(bondscli keys show p2 --keyring-backend=test -a) # participant 2 (new account)
P3=$(bondscli keys show p3 --keyring-backend=test -a) # participant 3 (new account)

# Creator-specified values:
# d0 := 1000000 // initial raise (reserve [uatom])
# p0 := 1 // initial price (reserve per token [uatom/ufit])
# theta := 0 // initial allocation (percentage)
# kappa := 3.0 // degrees of polynomial (i.e. x^2, x^4, x^6)

# Calculated values:
# R0 = 1000000 // initial reserve (calculated by (1-theta)*d0)
# S0 = 1000000 // initial supply (equal to R0 since p0=1)
# V0 = 1000000000000 // invariant which relates supply and reserve

# Create an Augmented Bonding Curve
bondscli tx bonds create-bond \
--token=ufit \
--name="FIT Initiative" \
--description="An incentivised fitness initiative" \
--function-type=augmented_function \
--function-parameters="d0:1000000,p0:1,theta:0,kappa:3.0" \
--reserve-tokens=uatom \
--tx-fee-percentage=0 \
--exit-fee-percentage=0 \
--fee-address="$FEE" \
--max-supply=20000000ufit \
--order-quantity-limits="" \
--sanity-rate="0" \
--sanity-margin-percentage="0" \
--allow-sells \
--signers="$ALICE" \
--batch-blocks=1 \
--outcome-payment="300000000uatom" \
--from alice --keyring-backend=test --broadcast-mode block -y
# Query the created bond
bondscli q bonds bond ufit

# DAY 1 :: P1, P2, P3 all submit a valid claim, so organiser sends 1ATOM each
bondscli tx send "$ALICE" "$P1" 1000000uatom --from alice --keyring-backend=test --broadcast-mode block -y
bondscli tx send "$ALICE" "$P2" 1000000uatom --from alice --keyring-backend=test --broadcast-mode block -y
bondscli tx send "$ALICE" "$P3" 1000000uatom --from alice --keyring-backend=test --broadcast-mode block -y

# Each account now has 1ATOM
bondscli q account "$P1"
bondscli q account "$P2"
bondscli q account "$P3"

# P1 buys 1ATOM worth of FIT (=1FIT) [note: 1ATOM=1FIT because p0=1]
bondscli tx bonds buy 1000000ufit 1000000uatom --from p1 --broadcast-mode block -y
# P2 buys 1ATOM worth of FIT (=0.26FIT) [note: 1ATOM=0.26FIT because we are now in OPEN phase]
bondscli tx bonds buy 259921ufit 1000000uatom --from p2 --broadcast-mode block -y
# P3 keeps the ATOM and does not buy FIT

# Bond is now in OPEN phase
bondscli q bonds bond ufit

# Note that P1 and P2 are both able to sell (and re-buy) their FIT tokens during the OPEN phase

# A secondary market of FIT tokens (e.g. FIT<->USD liquidity pool) might be set up as well!

# Assume some days pass, participants exercise, more ATOM is exchanged, and project is coming to an end

# Organiser deems the project a success and makes the outcome payment of 300ATOM
# Note: amount not specified here since it was written into the bond at creation
bondscli tx bonds make-outcome-payment ufit --from alice --broadcast-mode block -y

# Bond is now in SETTLE phase (no buying/selling allowed)
bondscli q bonds bond ufit

# P1 withdraws their share
bondscli tx bonds withdraw-share ufit --from p1 --keyring-backend=test --broadcast-mode block -y
# P2 withdraws their share
bondscli tx bonds withdraw-share ufit --from p2 --keyring-backend=test --broadcast-mode block -y

# P1 balance is equal to that of P2 (each gets a proportional share of the outcome payment)
bondscli q account "$P1"
bondscli q account "$P2"

# Of course P3 still only has 1ATOM
bondscli q account "$P3"
68 changes: 27 additions & 41 deletions scripts/run_with_data.sh
Original file line number Diff line number Diff line change
@@ -1,58 +1,44 @@
#!/usr/bin/env bash

PASSWORD="12345678"
GAS_PRICES="0.025stake"

bondsd init local --chain-id bondschain-1

yes $PASSWORD | bondscli keys delete miguel --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete francesco --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete shaun --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete fee --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete fee2 --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete fee3 --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete fee4 --keyring-backend=test --force
yes $PASSWORD | bondscli keys delete fee5 --keyring-backend=test --force

yes $PASSWORD | bondscli keys add miguel --keyring-backend=test
yes $PASSWORD | bondscli keys add francesco --keyring-backend=test
yes $PASSWORD | bondscli keys add shaun --keyring-backend=test
yes $PASSWORD | bondscli keys add fee --keyring-backend=test
yes $PASSWORD | bondscli keys add fee2 --keyring-backend=test
yes $PASSWORD | bondscli keys add fee3 --keyring-backend=test
yes $PASSWORD | bondscli keys add fee4 --keyring-backend=test
yes $PASSWORD | bondscli keys add fee5 --keyring-backend=test

# Note: important to add 'miguel' as a genesis-account since this is the chain's validator
yes $PASSWORD | bondsd add-genesis-account $(bondscli keys show miguel --keyring-backend=test -a) 200000000stake,1000000res,1000000rez
yes $PASSWORD | bondsd add-genesis-account $(bondscli keys show francesco --keyring-backend=test -a) 100000000stake,1000000res,1000000rez
yes $PASSWORD | bondsd add-genesis-account $(bondscli keys show shaun --keyring-backend=test -a) 100000000stake,1000000res,1000000rez

# Set min-gas-prices
FROM="minimum-gas-prices = \"\""
TO="minimum-gas-prices = \"0.025stake\""
sed -i "s/$FROM/$TO/" "$HOME"/.bondsd/config/app.toml
bondscli keys delete node --keyring-backend=test --force
bondscli keys delete alice --keyring-backend=test --force
bondscli keys delete bob --keyring-backend=test --force
bondscli keys delete charlie --keyring-backend=test --force
bondscli keys delete fee --keyring-backend=test --force

bondscli keys add node --keyring-backend=test
bondscli keys add alice --keyring-backend=test
bondscli keys add bob --keyring-backend=test
bondscli keys add charlie --keyring-backend=test
bondscli keys add fee --keyring-backend=test

# Note: important to add 'node' as a genesis-account since this is the validator
bondsd add-genesis-account $(bondscli keys show node --keyring-backend=test -a) 1000000000000uatom,1000000000000ubtc
bondsd add-genesis-account $(bondscli keys show alice --keyring-backend=test -a) 1000000000000uatom,1000000000000ubtc
bondsd add-genesis-account $(bondscli keys show bob --keyring-backend=test -a) 1000000000000uatom,1000000000000ubtc
bondsd add-genesis-account $(bondscli keys show charlie --keyring-backend=test -a) 1000000000000uatom,1000000000000ubtc

# Set staking token (both bond_denom and mint_denom)
STAKING_TOKEN="uatom"
FROM="\"bond_denom\": \"stake\""
TO="\"bond_denom\": \"$STAKING_TOKEN\""
sed -i "s/$FROM/$TO/" "$HOME"/.bondsd/config/genesis.json
FROM="\"mint_denom\": \"stake\""
TO="\"mint_denom\": \"$STAKING_TOKEN\""
sed -i "s/$FROM/$TO/" "$HOME"/.bondsd/config/genesis.json

bondscli config chain-id bondschain-1
bondscli config output json
bondscli config indent true
bondscli config trust-node true
bondscli config keyring-backend test

yes $PASSWORD | bondsd gentx --name miguel --keyring-backend=test
bondsd gentx --name node --amount 1000000uatom --keyring-backend=test

bondsd collect-gentxs
bondsd validate-genesis

# Uncomment the below to broadcast node RPC endpoint
#FROM="laddr = \"tcp:\/\/127.0.0.1:26657\""
#TO="laddr = \"tcp:\/\/0.0.0.0:26657\""
#sed -i "s/$FROM/$TO/" "$HOME"/.bondsd/config/config.toml

# Uncomment the below to broadcast REST endpoint
# Do not forget to comment the bottom lines !!
# bondsd start --pruning "everything" &
# bondscli rest-server --chain-id bondschain-1 --laddr="tcp://0.0.0.0:1317" --trust-node && fg

bondsd start --pruning "everything" &
bondscli rest-server --chain-id bondschain-1 --trust-node && fg
4 changes: 2 additions & 2 deletions x/bonds/internal/keeper/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ func (k Keeper) PerformSwapOrders(ctx sdk.Context, token string) {
batch.Swaps[i].CancelReason = err.Error()

logger.Info(fmt.Sprintf("cancelled swap order for %s to %s from %s", so.Amount.String(), so.ToToken, so.Address.String()))
logger.Debug(fmt.Sprintf("cancellation reason: %s", err.Error()))
logger.Info(fmt.Sprintf("cancellation reason: %s", err.Error())) // set to Info for visibility

ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeOrderCancel,
Expand Down Expand Up @@ -560,7 +560,7 @@ func (k Keeper) CancelUnfulfillableBuys(ctx sdk.Context, token string) (cancelle
cancelledOrders += 1

logger.Info(fmt.Sprintf("cancelled buy order for %s from %s", bo.Amount.String(), bo.Address.String()))
logger.Debug(fmt.Sprintf("cancellation reason: %s", err.Error()))
logger.Info(fmt.Sprintf("cancellation reason: %s", err.Error())) // set to Info for visibility

ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeOrderCancel,
Expand Down