From e11b298c28201b1740da7b76038050d8a83841b7 Mon Sep 17 00:00:00 2001 From: Ruaridh Date: Thu, 23 Jan 2020 19:09:36 +0000 Subject: [PATCH] Add CDP Spec (#328) * add overview and basic structure * add state and params * add basic messages * add state transitions * add begin block state transitions * add missing titles * add concepts * add events * update state and concepts * update for liquidator changes * update events * mention module accounts * update begin block * update params * update page numbering * add fee descriptions * add broken link linter * add broken link linter to CI * move link check to end of CI * update typo Co-Authored-By: Kevin Davis * address review comments * Update x/cdp/spec/06_params.md Co-Authored-By: Kevin Davis * Update x/cdp/spec/README.md Co-Authored-By: Kevin Davis * Update x/cdp/spec/README.md Co-Authored-By: Kevin Davis Co-authored-by: Kevin Davis --- .circleci/config.yml | 12 +++- Makefile | 9 +++ go.mod | 1 + go.sum | 29 +++++++++ x/auction/spec/04_events.md | 6 +- x/auction/spec/README.md | 2 +- x/cdp/spec/01_concepts.md | 62 +++++++++++++++++++ x/cdp/spec/02_state.md | 67 ++++++++++++++++++++ x/cdp/spec/03_messages.md | 116 +++++++++++++++++++++++++++++++++++ x/cdp/spec/04_begin_block.md | 34 ++++++++++ x/cdp/spec/05_events.md | 59 ++++++++++++++++++ x/cdp/spec/06_params.md | 31 ++++++++++ x/cdp/spec/README.md | 19 ++++++ 13 files changed, 442 insertions(+), 5 deletions(-) create mode 100644 x/cdp/spec/01_concepts.md create mode 100644 x/cdp/spec/02_state.md create mode 100644 x/cdp/spec/03_messages.md create mode 100644 x/cdp/spec/04_begin_block.md create mode 100644 x/cdp/spec/05_events.md create mode 100644 x/cdp/spec/06_params.md create mode 100644 x/cdp/spec/README.md diff --git a/.circleci/config.yml b/.circleci/config.yml index bb93ea28..c727d1a7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -96,6 +96,13 @@ jobs: target: start-remote-sims description: "Test multi-seed simulation (long)" + broken-link-check: + executor: golang + steps: + - make: + target: link-check + description: "Check url links are not broken" + workflows: version: 2 @@ -116,4 +123,7 @@ workflows: # These filters ensure that the long sim only runs during release filters: branches: - only: "master" \ No newline at end of file + only: "master" + - broken-link-check: + requires: + - setup-dependencies \ No newline at end of file diff --git a/Makefile b/Makefile index 2dfbf5f8..4cbed021 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,15 @@ go.sum: go.mod clean: rm -rf build/ +######################################## +### Linting + +# Check url links in the repo are not broken. +# This tool checks local markdown links as well. +# Set to exclude riot links as they trigger false positives +link-check: + @go run github.com/raviqqe/liche -r . --exclude ^https://riot.im/app + ######################################## ### Testing diff --git a/go.mod b/go.mod index ca6b8e18..ffba0067 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1 github.com/gorilla/mux v1.7.3 + github.com/raviqqe/liche v0.0.0-20191208214012-e144e0808a75 // indirect github.com/spf13/cobra v0.0.5 github.com/spf13/viper v1.4.0 github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index b8895b5c..cb578ad0 100644 --- a/go.sum +++ b/go.sum @@ -59,6 +59,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -70,6 +72,8 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -141,6 +145,11 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.8.5 h1:2ucYeik+NtUTg+IAiNQtoFC5ZGs5mIVidI7Ome0Br3Y= +github.com/klauspost/compress v1.8.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -157,6 +166,9 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= @@ -200,6 +212,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= +github.com/raviqqe/liche v0.0.0-20191208214012-e144e0808a75 h1:o0pGzJnfjk0E+CZg6jxQrADfk9WYO9fMuLOtSP4owtE= +github.com/raviqqe/liche v0.0.0-20191208214012-e144e0808a75/go.mod h1:/L9q8uCsB8BOWdzLK+6WIwkAlcMfKhFCZY0n8/CLHRY= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -207,7 +221,12 @@ github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -268,6 +287,11 @@ github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.5.0 h1:dhq+O9pmNZFF6qAXpasMO1xSm7dL4qEz2ylfZN8BG9w= +github.com/valyala/fasthttp v1.5.0/go.mod h1:eriCz9OhZjKCGfJ185a/IDgNl0bg9IbzfpcslMZXU1c= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= @@ -298,6 +322,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -311,10 +338,12 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= diff --git a/x/auction/spec/04_events.md b/x/auction/spec/04_events.md index fae55424..39ec4053 100644 --- a/x/auction/spec/04_events.md +++ b/x/auction/spec/04_events.md @@ -5,7 +5,7 @@ The `x/auction` module emits the following events: ## Triggered By Other Modules | Type | Attribute Key | Attribute Value | -| ------------- | ------------- | ------------------- | +|---------------|---------------|---------------------| | auction_start | auction_id | {auction ID} | | auction_start | auction_type | {auction type} | | auction_start | lot_denom | {auction lot denom} | @@ -16,7 +16,7 @@ The `x/auction` module emits the following events: ### MsgPlaceBid | Type | Attribute Key | Attribute Value | -| ----------- | ------------- | ------------------ | +|-------------|---------------|--------------------| | auction_bid | auction_id | {auction ID} | | auction_bid | bidder | {latest bidder} | | auction_bid | bid_amount | {coin amount} | @@ -28,5 +28,5 @@ The `x/auction` module emits the following events: ## EndBlock | Type | Attribute Key | Attribute Value | -| ------------- | ------------- | --------------- | +|---------------|---------------|-----------------| | auction_close | auction_id | {auction ID} | diff --git a/x/auction/spec/README.md b/x/auction/spec/README.md index 32ae71d1..8c2ee2b5 100644 --- a/x/auction/spec/README.md +++ b/x/auction/spec/README.md @@ -6,7 +6,7 @@ 3. **[Messages](03_messages.md)** 4. **[Events](04_events.md)** 5. **[Params](05_params.md)** -6. **[BeginBlock](06_begin_block.md)** +6. **[EndBlock](06_end_block.md)** ## Abstract diff --git a/x/cdp/spec/01_concepts.md b/x/cdp/spec/01_concepts.md new file mode 100644 index 00000000..cde6e9d2 --- /dev/null +++ b/x/cdp/spec/01_concepts.md @@ -0,0 +1,62 @@ +# Concepts + +## Collateralized Debt Positions + +CDPs enable the creation of a stable asset by collateralization with another on chain asset. + +A CDP is scoped to one collateral type. It has one primary owner, and a set of "depositors". The depositors can deposit and withdraw collateral to the CDP. The owner can draw stable assets (creating debt) and repay them to cancel the debt. + +Once created stable assets are free to be transferred between users, but a CDP owner must repay their debt to get their collateral back. + +User interactions with this module: + +- create a new cdp by depositing some type of coin as collateral +- withdraw newly minted stable coin from this CDP (up to a fraction of the value of the collateral) +- repay debt by paying back stable coins (including paying any fees accrued) +- remove collateral and close CDP + +## Liquidation & Stability System + +In the event of a decrease in the price of the collateral, the total value of all collateral in CDPs may drop below the value of all the issued stable assets. This undesirable event is countered through two mechanisms: + +**CDP Liquidations** The ratio of collateral value to debt value in each CDP is monitored. When this drops too low the collateral and debt is automatically seized by the system. The collateral is sold off through an auction to bring in stable asset which is burned against the seized debt. + +**Debt Auctions** In extreme cases where liquidations fail to raise enough to cover the seized debt, another mechanism kicks in: Debt Auctions. System governance tokens are minted and sold through auction to raise enough stable asset to cover the remaining debt. The governors of the system represent the lenders of last resort. + +The system monitors the state of CDPs and debt and triggers these auctions as needed. + +## Internal Debt Tracking + +Users incur debt when they draw new stable assets from their CDP. Within the system this debt is tracked in the form of a "debt coin" stored internally in the module's accounts. Every time a stable coin is created a corresponding debt coin is created. Likewise when debt is repaid stable coin and internal debt coin are burned. + +The cdp module uses two module accounts - one to hold debt coins associated with active CDPs, and another (the "liquidator" account) to hold debt from CDPS that have been seized by the system. + +## Fees + +When a user repays stable asset withdrawn from a CDP, they must also pay a fee. + +This is calculated according to the amount of stable asset withdrawn and the time withdrawn for. Like interest on a loan fees grow at a compounding percentage of original debt. + +Fees create incentives to open or close CDPs and can be changed by governance to help keep the system functioning through changing market conditions. + +A further fee is applied on liquidation of a CDP. Normally when the collateral is sold to cover the debt, any excess not sold is returned to the CDP holder. The liquidation fee reduces the amount of excess collateral returned, representing a cut that the system takes. + +Fees accumulate to the system before being automatically sold at auction for governance token. These are then burned, acting as incentive for safe governance of the system. + +## Governance + +The cdp module's behavior is controlled through several parameters which are updated through a governance mechanism. These parameters are listed in [Parameters](06_params.md). + +Governance is important for actions such as: + +- enabling CDPs to be created with new collateral assets +- changing fee rates to incentivize behavior +- increasing the debt ceiling to allow more stable asset to be created + +## Dependency: supply + +The CDP module relies on a supply keeper to move assets between its module accounts and user accounts. + +## Dependency: pricefeed + +The CDP module needs to know the current price of collateral assets in order to determine if CDPs are under collateralized. This is provided by a "pricefeed" module that returns a price for a given collateral in units (usually US Dollars) which are the target for the stable asset. diff --git a/x/cdp/spec/02_state.md b/x/cdp/spec/02_state.md new file mode 100644 index 00000000..65f66250 --- /dev/null +++ b/x/cdp/spec/02_state.md @@ -0,0 +1,67 @@ +# State + +For detail on the state tracked by the cdp module see the types package. In particular [keys.go](../types/keys.go) describes how state is stored in the key-value store. + +## Module Accounts + +The cdp module account controls two module accounts: + +**CDP Account:** Stores the deposited cdp collateral, and the debt coins for the debt in all the cdps. + +**Liquidator Account:** Stores debt coins that have been seized by the system, and any stable asset that has been raised through auctions. + +## CDP + +A CDP is a struct representing a debt position owned by one address. It has one collateral type and records the debt that has been drawn and how much fees should be repaid. + +Only an owner is authorized to draw or repay debt, but anyone can deposit collateral to a CDP. Deposits are scoped per address and are recorded separately in `Deposit` types. Depositors are free to withdraw their collateral provided it does not put the CDP below the liquidation ratio. + +The CDP's collateral always equal to the total of the deposits. + +```go +type CDP struct { + ID uint64 + Owner sdk.AccAddress + Collateral sdk.Coins + Principal sdk.Coins + AccumulatedFees sdk.Coins + FeesUpdated time.Time +} +``` + +CDPs are stored with a couple of database indexes for faster lookup: + +- by collateral ratio - to look up cdps that are close to the liquidation ratio +- by owner index - to look up cdps that an address is the owner of + +## Deposit + +A Deposit is a struct recording collateral added to a CDP by one address. The address only has authorization to change their deposited amount (provided it does not put the CDP below the liquidation ratio). + +```go +type Deposit struct { + CdpID uint64 + Depositor sdk.AccAddress + Amount sdk.Coins +} +``` + +## Params + +Module parameters controlled by governance. See [Parameters](06_params.md) for details. + +## NextCDPID + +A global counter used to create unique CDP ids. + +## DebtDenom + +The name of the internal debt coin. Its value can be configured at genesis. + +## Total Principle + +Sum of all non seized debt plus accumulated fees. This is used to calculate the new debt created every block due to the fee interest rate. + +## Previous Block Time + +A record of the last block time used to calculate fees. diff --git a/x/cdp/spec/03_messages.md b/x/cdp/spec/03_messages.md new file mode 100644 index 00000000..95304323 --- /dev/null +++ b/x/cdp/spec/03_messages.md @@ -0,0 +1,116 @@ +# Messages + +Users can submit various messages to the cdp module which trigger state changes detailed below. + +## CreateCDP + +CreateCDP sets up and stores a new CDP, adding collateral from the sender, and drawing `Principle` debt. + +```go +type MsgCreateCDP struct { + Sender sdk.AccAddress + Collateral sdk.Coins + Principal sdk.Coins +} +``` + +State changes: + +- a new CDP is created, `Sender` becomes CDP owner +- collateral taken from `Sender` and sent to cdp module account, new `Deposit` created +- `Principal` stable coins are minted and sent to `Sender` +- equal amount of internal debt coins created and stored in cdp module account + +## Deposit + +Deposit adds collateral to a CDP in the form of a deposit. Collateral is taken from `Depositor`. + +```go +type MsgDeposit struct { + Owner sdk.AccAddress + Depositor sdk.AccAddress + Collateral sdk.Coins +} +``` + +State Changes: + +- `Collateral` taken from depositor and sent to cdp module account +- the depositor's `Deposit` struct is updated or a new one created +- cdp fees are updated (see below) + +## Withdraw + +Withdraw removes collateral from a CDP, provided it would not put the CDP under the liquidation ratio. Collateral is removed from one deposit only. + +```go +type MsgWithdraw struct { + Owner sdk.AccAddress + Depositor sdk.AccAddress + Collateral sdk.Coins +} +``` + +State Changes: + +- `Collateral` coins are sent from the cdp module account to `Depositor` +- `Collateral` amount of coins subtracted from the `Deposit` struct +- cdp fees are updated (see below) + +## DrawDebt + +DrawDebt creates debt in a CDP, minting new stable asset which is sent to the sender. + +```go +type MsgDrawDebt struct { + Sender sdk.AccAddress + CdpDenom string + Principal sdk.Coins +} +``` + +State Changes: + +- mint `Principal` coins and send them to `Sender`, updating the CDP's `Principal` field +- mint equal amount of internal debt coins and store in the module account +- increment total principal for principal denom +- cdp fees are updated (see below) + +## RepayDebt + +RepayDebt removes some debt from a CDP and burns the corresponding amount of stable asset from the sender. If all debt is repaid, the collateral is returned to depositors and the cdp is removed from the store + +```go +type MsgRepayDebt struct { + Sender sdk.AccAddress + CdpDenom string + Payment sdk.Coins +} +``` + +State Changes: + +- burn `Payment` coins taken from `Sender`, updating the CDP by reducing `Principal` field by `Paymment` +- burn an equal amount of internal debt coins +- decrement total principal for payment denom +- cdp fees are updated (see below) +- if fees and principal are zero, return collateral to depositors: + - For each deposit, send coins from the cdp module account to the depositor, and delete the deposit struct from store. + +## Fees + +When CDPs are updated by the above messages the fees accumulated since the last update are calculated and added on. + +``` +feesAccumulated = (outstandingDebt * (feeRate^periods)) - outstandingDebt +``` + +where: + +- `outstandingDebt` is the CDP's `Principal` plus `AccumulatedFees` +- `periods` is the number of seconds since last fee update +- `feeRate` is the per second debt interest rate + +## Database Indexes + +When CDPs are update by the above messages the database indexes are also updated. \ No newline at end of file diff --git a/x/cdp/spec/04_begin_block.md b/x/cdp/spec/04_begin_block.md new file mode 100644 index 00000000..e8257c0c --- /dev/null +++ b/x/cdp/spec/04_begin_block.md @@ -0,0 +1,34 @@ +# Begin Blocker + +At the start of every block the BeginBlocker of the cdp module: + +- updates total CDP fees +- liquidates CDPs under the collateral ratio +- nets out system debt and, if necessary, starts auctions to re-balance it +- records the last block time + +## Update Fees + +- The total fees accumulated since the last block across all CDPs are calculated. +- An equal amount of debt coins are minted and sent to the system's CDP module account. +- An equal amount of stable asset coins are minted and sent to the system's liquidator module account + +## Liquidate CDP + +- Get every cdp that is under the liquidation ratio for its collateral type. +- For each cdp: + - Calculate and update fees since last update. + - Remove all collateral and internal debt coins from cdp and deposits and delete it. Send the coins to the liquidator module account. + - Start auctions of a fixed size from this collateral (with any remainder in a smaller sized auction), sending collateral and debt coins to the auction module account. + - Decrement total principal. + +## Net Out System Debt, Re-Balance + +- Burn the maximum possible equal amount of debt and stable asset from the liquidator module account. +- If there is enough debt remaining for an auction, start one. +- If there is enough surplus stable asset remaining for an auction, start one. +- Otherwise do nothing, leave debt/surplus to accumulate over subsequent blocks. + +## Update Previous Block Time + +The current block time is recorded. diff --git a/x/cdp/spec/05_events.md b/x/cdp/spec/05_events.md new file mode 100644 index 00000000..693e91c5 --- /dev/null +++ b/x/cdp/spec/05_events.md @@ -0,0 +1,59 @@ +# Events + +The cdp module emits the following events: + +## Handlers + +### MsgCreateCDP + +| Type | Attribute Key | Attribute Value | +|-------------|---------------|------------------| +| message | module | cdp | +| message | sender | {sender address} | +| create_cdp | cdp_id | {cdp id} | +| cdp_deposit | cdp_id | {cdp id} | +| cdp_deposit | amount | {deposit amount} | +| cdp_draw | cdp_id | {cdp id} | +| cdp_draw | amount | {draw amount} | + +### MsgWithdraw + +| Type | Attribute Key | Attribute Value | +|---------|---------------|------------------| +| message | module | cdp | +| message | sender | {sender address} | + +### MsgDeposit + +| Type | Attribute Key | Attribute Value | +|-------------|---------------|------------------| +| message | module | cdp | +| message | sender | {sender address} | +| cdp_deposit | cdp_id | {cdp id} | +| cdp_deposit | amount | {deposit amount} | + +### MsgDrawDebt + +| Type | Attribute Key | Attribute Value | +|----------|---------------|------------------| +| message | module | cdp | +| message | sender | {sender address} | +| cdp_draw | cdp_id | {cdp id} | +| cdp_draw | amount | {draw amount} | + +### MsgRepayDebt + +| Type | Attribute Key | Attribute Value | +|---------|---------------|------------------| +| message | module | cdp | +| message | sender | {sender address} | + +## BeginBlock + +| Type | Attribute Key | Attribute Value | +|-------------------------|---------------|---------------------| +| cdp_liquidation | module | cdp | +| cdp_liquidation | cdp_id | {cdp id} | +| cdp_liquidation | depositor | {depositor address} | +| cdp_begin_blocker_error | module | cdp | +| cdp_begin_blocker_error | error_message | {error} | diff --git a/x/cdp/spec/06_params.md b/x/cdp/spec/06_params.md new file mode 100644 index 00000000..fbde95d7 --- /dev/null +++ b/x/cdp/spec/06_params.md @@ -0,0 +1,31 @@ +# Parameters + +The cdp module contains the following parameters: + +| Key | Type | Example | Description | +|------------------|-------------------------|------------------------------------|------------------------------------------------------------------| +| CollateralParams | array (CollateralParam) | [{see below}] | array of params for each enabled collateral type | +| DebtParams | array (DebtParam) | [{see below}] | array of params for each enabled pegged asset | +| GlobalDebtLimit | array (coin) | [{"denom":"usdx","amount":"1000"}] | maximum pegged assets that can be minted across the whole system | +| CircuitBreaker | bool | false | flag to disable user interactions with the system | + +Each CollateralParam has the following parameters: + +| Key | Type | Example | Description | +|------------------|---------------|---------------------------------------------|----------------------------------------------------------------------------------------------------------------| +| Denom | string | "pbnb" | collateral coin denom | +| LiquidationRatio | string (dec) | "1.500000000000000000" | the ratio under which a cdp with this collateral type will be liquidated | +| DebtLimit | array (coin) | [{"denom":"pbnb","amount":"1000000000000"}] | maximum pegged asset that can be minted backed by this collateral type | +| StabilityFee | string (dec) | "1.000000001547126" | per second fee | +| Prefix | number (byte) | 34 | identifier used in store keys - **must** be unique across collateral types | +| MarketID | string | "BNB/USD" | price feed identifier for this collateral type | +| ConversionFactor | string (int) | "6" | 10^_ multiplier to go from external amount (say BTC1.50) to internal representation of that amount (150000000) | + +Each DebtParam has the following parameters: + +| Key | Type | Example | Description | +|------------------|--------------|------------|------------------------------------------------------------------------------------------------------------| +| Denom | string | "usdx" | pegged asset coin denom | +| ReferenceAsset | string | "USD" | asset this asset is pegged to, informational purposes only | +| ConversionFactor | string (int) | "6" | 10^_ multiplier to go from external amount (say $1.50) to internal representation of that amount (1500000) | +| DebtFloor | string (int) | "10000000" | minimum amount of debt that a CDP can contain | diff --git a/x/cdp/spec/README.md b/x/cdp/spec/README.md new file mode 100644 index 00000000..99385048 --- /dev/null +++ b/x/cdp/spec/README.md @@ -0,0 +1,19 @@ + +# `cdp` + +## Table of Contents + +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[Messages](03_messages.md)** +4. **[BeginBlock](04_begin_block.md)** +5. **[Events](05_events.md)** +6. **[Parameters](06_params.md)** + +## Overview + +The `x/cdp` module stores and manages Collateralized Debt Positions (or CDPs). + +A CDP enables the creation of a stable asset pegged to an external price (usually US Dollar) by collateralization with another asset. Collateral is locked in a CDP and new stable asset can be minted up to some fraction of the value of the collateral. To unlock the collateral, the debt must be repaid by returning some stable asset to the CDP at which point it will be burned and the collateral unlocked. + +Pegged assets remain fully collateralized by the value locked in CDPs. In the event of price changes, this collateral can be seized and sold off by the system to reclaim and reduce the supply of stable assets.