diff --git a/codewithus/README.md b/codewithus/README.md new file mode 100644 index 0000000..f79afe1 --- /dev/null +++ b/codewithus/README.md @@ -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 diff --git a/codewithus/demo_1_power.sh b/codewithus/demo_1_power.sh new file mode 100644 index 0000000..0e4dff3 --- /dev/null +++ b/codewithus/demo_1_power.sh @@ -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" diff --git a/codewithus/demo_2_swapper.sh b/codewithus/demo_2_swapper.sh new file mode 100644 index 0000000..e64045f --- /dev/null +++ b/codewithus/demo_2_swapper.sh @@ -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" diff --git a/codewithus/demo_3_augmented.sh b/codewithus/demo_3_augmented.sh new file mode 100644 index 0000000..5b3ee7f --- /dev/null +++ b/codewithus/demo_3_augmented.sh @@ -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" diff --git a/scripts/run_with_data.sh b/scripts/run_with_data.sh index cf7f55b..814ef09 100755 --- a/scripts/run_with_data.sh +++ b/scripts/run_with_data.sh @@ -1,37 +1,33 @@ #!/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 @@ -39,20 +35,10 @@ 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 diff --git a/x/bonds/internal/keeper/batch.go b/x/bonds/internal/keeper/batch.go index fa48603..bdeca8b 100644 --- a/x/bonds/internal/keeper/batch.go +++ b/x/bonds/internal/keeper/batch.go @@ -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, @@ -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,