docs: migrate alexgo docs content
12
developers/.gitbook.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
root: ./
|
||||
# All other options that specify paths will be relative to this root folder.
|
||||
|
||||
structure:
|
||||
readme: README.md
|
||||
summary: SUMMARY.md
|
||||
|
||||
redirects:
|
||||
developers/testnet: developers/networks/testnet.md
|
||||
developers/smart-contracts: developers/networks/mainnet.md
|
||||
developers/smart-contracts/token-list: developers/networks/mainnet.md
|
||||
developers/smart-contracts/amm-pool-mapping: developers/protocol-contracts/README.md
|
||||
BIN
developers/.gitbook/assets/0floor.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
developers/.gitbook/assets/2021-09-18-15.28.55.jpg
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
developers/.gitbook/assets/2021-09-18-15.29.09.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
developers/.gitbook/assets/2021-09-18-15.29.15.jpg
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
developers/.gitbook/assets/2021-09-18-15.29.20.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
developers/.gitbook/assets/2021-09-18-15.29.23.jpg
Normal file
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 387 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 247 KiB |
|
After Width: | Height: | Size: 456 KiB |
|
After Width: | Height: | Size: 456 KiB |
|
After Width: | Height: | Size: 715 KiB |
|
After Width: | Height: | Size: 737 KiB |
|
After Width: | Height: | Size: 631 KiB |
|
After Width: | Height: | Size: 631 KiB |
BIN
developers/.gitbook/assets/calldelta-2.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
developers/.gitbook/assets/calldeltaspot-2.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
developers/.gitbook/assets/cecjing.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
developers/.gitbook/assets/cectable2 (1).png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
developers/.gitbook/assets/cectable2.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
developers/.gitbook/assets/cectable3.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
505
developers/.gitbook/assets/erase.yaml
Normal file
@@ -0,0 +1,505 @@
|
||||
---
|
||||
openapi: 3.0.0
|
||||
paths:
|
||||
"/v1/allswaps":
|
||||
get:
|
||||
operationId: PoolController_getAllSwaps
|
||||
summary: Returns all existing swaps with status
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning all existing swaps
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/pool_stats/{pool_token}":
|
||||
get:
|
||||
operationId: PoolController_getPriceHistory
|
||||
summary: Returns pool stats
|
||||
parameters:
|
||||
- name: pool_token
|
||||
required: true
|
||||
in: path
|
||||
description: pool token of swap pool eg. fwp-alex-wslm
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning pool stats
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/pool_volume/{pool_token}":
|
||||
get:
|
||||
operationId: PoolController_getPoolVolumeHistory
|
||||
summary: Returns all 24 hour pool volumes in time series
|
||||
parameters:
|
||||
- name: pool_token
|
||||
required: true
|
||||
in: path
|
||||
description: pool token of swap pool eg. fwp-alex-wslm
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning volumes
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/volume_24h/{token}":
|
||||
get:
|
||||
operationId: PoolController_getVolume24HRHistory
|
||||
summary: Returns daily volumes of token in time series
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
description: name of token eg. age000-governance-token
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning volumes
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/volume_7d/{token}":
|
||||
get:
|
||||
operationId: PoolController_getVolume7DHistory
|
||||
summary: Returns weekly volumes of token in time series
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
description: name of token eg. age000-governance-token
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning volumes
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/pool_liquidity/{pool_token}":
|
||||
get:
|
||||
operationId: PoolController_getPoolLiquidityHistory
|
||||
summary: Returns liquidity in time series
|
||||
parameters:
|
||||
- name: pool_token
|
||||
required: true
|
||||
in: path
|
||||
description: pool token of swap pool eg. fwp-alex-wslm
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning liquidity
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/liquidity/{token}":
|
||||
get:
|
||||
operationId: PoolController_getLiquidityHistory
|
||||
summary: Returns liquidity of token in time series
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
description: name of token eg. age000-governance-token
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning liquidity
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/fee/{pool_token}":
|
||||
get:
|
||||
operationId: PoolController_getFeeHistory
|
||||
summary: Returns pool fee in time series
|
||||
parameters:
|
||||
- name: pool_token
|
||||
required: true
|
||||
in: path
|
||||
description: pool token of swap pool eg. fwp-alex-wslm
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning fee
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- pool
|
||||
"/v1/stats/tvl":
|
||||
get:
|
||||
operationId: StatsController_getTVL
|
||||
summary: Returns total TVL(total value locked) value of ALEX platform
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning TVL
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- stats
|
||||
"/v1/stats/tvl/{token}":
|
||||
get:
|
||||
operationId: StatsController_getTokenTVL
|
||||
summary: Returns token TVL(total value locked) in time series
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning liquidity
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- stats
|
||||
"/v1/stats/total_supply/{token}":
|
||||
get:
|
||||
operationId: StatsController_getTotalSupply
|
||||
summary: Returns total supply of queried token eg. age000-governance-token
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning total supply
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- stats
|
||||
"/v1/price/{token}":
|
||||
get:
|
||||
operationId: PriceController_getPrice
|
||||
summary: Returns price of token
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
description: name of token eg. age000-governance-token
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning price
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- price
|
||||
"/v1/pool_token_price/{pool_token}":
|
||||
get:
|
||||
operationId: PriceController_getPoolTokenPrice
|
||||
summary: Returns pool token price value of ALEX platform
|
||||
parameters:
|
||||
- name: pool_token
|
||||
required: true
|
||||
in: path
|
||||
description: pool token of swap pool eg. fwp-alex-wslm
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning Pool token price
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- price
|
||||
"/v1/pool_token_stats":
|
||||
get:
|
||||
operationId: PriceController_getAllPoolTokenPrice
|
||||
summary: Returns pool token price value of ALEX platform
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning all existing pool token stats
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- price
|
||||
"/v1/price_history/{token}":
|
||||
get:
|
||||
operationId: PriceController_getPriceHistory
|
||||
summary: Returns price history of token
|
||||
parameters:
|
||||
- name: token
|
||||
required: true
|
||||
in: path
|
||||
description: name of token eg. age000-governance-token
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: offset
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies the offset of data to be returned, default value is
|
||||
0
|
||||
schema: {}
|
||||
- name: limit
|
||||
required: false
|
||||
in: query
|
||||
description: Specifies number of data to be returned, default value is 10
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning price history
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- price
|
||||
"/v1/pairs":
|
||||
get:
|
||||
operationId: DexController_getAllPairs
|
||||
summary: Returns all existing pairs
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning all existing pairs
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- dex
|
||||
"/v1/tickers":
|
||||
get:
|
||||
operationId: DexController_getAllTickers
|
||||
summary: Returns all markets statistics for the last 24 hours
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning all markets statistics for the last 24
|
||||
hours
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- dex
|
||||
"/v1/historical_swaps/{ticker}":
|
||||
get:
|
||||
operationId: DexController_getHistoricalTrades
|
||||
summary: Returns all existing historical trades
|
||||
parameters:
|
||||
- name: ticker
|
||||
required: true
|
||||
in: path
|
||||
description: A ticker with delimiter between different cryptoassets eg. ALEX_WSLM
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: limit
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies number of recent block heights to be returned, default
|
||||
value is 1000
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Succesfully returning all historical trades of certain ticker
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- dex
|
||||
"/v1/orderbook/{ticker_id}":
|
||||
get:
|
||||
operationId: DexController_getOrderBookDepth
|
||||
summary: Returns orderbook information
|
||||
parameters:
|
||||
- name: ticker_id
|
||||
required: true
|
||||
in: path
|
||||
description: A ticker with delimiter between different cryptoassets eg. ALEX_WSLM
|
||||
schema:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: integer
|
||||
- name: depth
|
||||
required: true
|
||||
in: query
|
||||
description: Specifies value of depth on either side of bid/ask
|
||||
schema: {}
|
||||
responses:
|
||||
'200':
|
||||
description: Return orderbook information of queried ticker
|
||||
'403':
|
||||
description: Forbidden
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- dex
|
||||
info:
|
||||
title: Alex REST API
|
||||
description: Alex Open API service
|
||||
version: '1.0'
|
||||
contact:
|
||||
name: ALEX DEV Team
|
||||
url: https://app.alexgo.io
|
||||
email: sidney@alexgo.io
|
||||
tags:
|
||||
- name: ALEX REST API
|
||||
description: ALEX Open API for public usage
|
||||
servers: []
|
||||
components:
|
||||
securitySchemes:
|
||||
bearer:
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
type: http
|
||||
schemas: {}
|
||||
BIN
developers/.gitbook/assets/image (1) (1) (1).png
Normal file
|
After Width: | Height: | Size: 447 KiB |
BIN
developers/.gitbook/assets/image (1) (1).png
Normal file
|
After Width: | Height: | Size: 974 KiB |
BIN
developers/.gitbook/assets/image (1).png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
developers/.gitbook/assets/image (2).png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
developers/.gitbook/assets/image (3).png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
developers/.gitbook/assets/image (4).png
Normal file
|
After Width: | Height: | Size: 563 KiB |
BIN
developers/.gitbook/assets/image (5).png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
developers/.gitbook/assets/image (6).png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
developers/.gitbook/assets/image (7).png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
developers/.gitbook/assets/image (8).png
Normal file
|
After Width: | Height: | Size: 489 KiB |
BIN
developers/.gitbook/assets/image.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
developers/.gitbook/assets/lending-user-flow.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
56
developers/CONTRIBUTING.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Contributing
|
||||
|
||||
We follow a simple model to make contributing as straightforward as possible. These guidelines allow us to streamline the development process and achieve greater transparency.
|
||||
|
||||
## Proposing changes
|
||||
|
||||
The `main` branch is protected and cannot be committed to directly. It will always contain the latest version of the project that is considered to be stable. Development happens on the `dev` branch. In order to propose a change to the project, we have the following process:
|
||||
|
||||
1. Fork the repository if you do not have write access.
|
||||
2. Create a branch from `dev`, using the following naming convention:
|
||||
1. `feat/feature-name` when introducing a new feature.
|
||||
2. `fix/fix-name` when fixing an existing issue.
|
||||
3. `chore/chore-dec` for miscellaneous changes.
|
||||
3. Stick to the project coding style. ([See below](#coding-style).)
|
||||
4. Add your commits to the branch following Conventional Commits ([See below](#conventional-commits).)
|
||||
5. Open a Pull Request targeting the `dev` branch and tag the right code owners for review. ([See below](#code-owners).)
|
||||
6. Merge the PR into `dev` if you have write access or request a merge from a code owner after reviews and checks have passed.
|
||||
|
||||
Note that any new code must be covered by unit tests. Only PRs with checks successfully are eligible to be merged. The code owners reserve the right to accept or reject PRs.
|
||||
|
||||
Any contributions that are accepted become part of the code base under the same [license](LICENSE) that covers the project.
|
||||
|
||||
## Opening issues
|
||||
|
||||
You can open an issue via GitHub's issue tracker. You may tag one or more code owners for visibility if you think it fits the issue.
|
||||
|
||||
## Coding style
|
||||
|
||||
- Tabs instead of spaces.
|
||||
- Closing brackets generally go on a new line.
|
||||
|
||||
## Conventional Commits
|
||||
|
||||
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard for commit messages. The pattern for such a commit message is as follows:
|
||||
```
|
||||
type(scope?): description
|
||||
```
|
||||
|
||||
Where `type` is one of:
|
||||
|
||||
- `feat`: commits that add a feature.
|
||||
- `fix`: commits that fix an issue.
|
||||
- `refactor`: commits that (re)write code but do not change behaviour.
|
||||
- `chore`: miscellaneous commits or housekeeping.
|
||||
- Or one of the other types described by the standard.
|
||||
|
||||
The `scope` portion is optional and valid options depend on the project.
|
||||
|
||||
Example Conventional Commit message:
|
||||
```
|
||||
fix(yield-token): unwrap memo and print if not none
|
||||
```
|
||||
|
||||
## Code owners
|
||||
|
||||
All repositories should contain a `CODEOWNERS` file that automatically requests the right code owner(s) for review when a new PR is submitted. If it does not happen, or if you think someone else should be included, you can request a review manually.
|
||||
21
developers/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 alexgo-io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
17
developers/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
description: From the Co-Founders
|
||||
---
|
||||
|
||||
# 😀 What is ALEX?
|
||||
|
||||
The DeFi landscape is teeming with possibilities, and at the heart of it all, Bitcoin DeFi is set to take center stage. In the coming years, we expect a surge in growth revolving around Ordinals, BRC20 tokens, Bitcoin L2 in particular Stacks.
|
||||
|
||||
A quick retrospect shows how Ordinals have brilliantly showcased the potential of the Bitcoin blockchain. This revolutionary platform has turned the table, illustrating that Bitcoin’s ledger is more than just a settlement layer. Yet, to build a truly meaningful DeFi ecosystem on Bitcoin, transactions are only one piece of the puzzle. We need a competent smart contract and computing layer to complete the picture. That’s where Stacks steps in. The domino effect triggered by Ordinals has kindled an era where we expect Bitcoin’s Layer 1 (L1) asset issuance to skyrocket. Coupled with Stacks’ prowess in handling DeFi and other economic activities, we see a flourishing ecosystem set for the years ahead. 
|
||||
|
||||
At ALEX, we’re not mere spectators. We’re an integral part of this vibrant, multi-year growth story. Our aim? To deliver a top-notch DeFi platform that caters to the next-gen Bitcoin users, innovators, and the broader ecosystem.
|
||||
|
||||
So, in essence, ALEX is a concentrated bet on this view of Bitcoin Finance. 
|
||||
|
||||
Presently, a good number of BRC-20s may appear to be meme coins, but we foresee a significant shift. We are witnessing more established projects considering BRC20 issuance. Moreover, numerous other projects we are in discussion with are considering issuing BRC20 tokens to augment their existing tokenomics and tap into a new audience. Some may argue that Bitcoin began its journey as a “meme” coin, with its initial purpose being to buy pizza amongst friends. However, the essential query is whether the technology enabling the creation of such meme coins can transcend that purpose. We are confident that BRC20 and Ordinals hold a greater potential than just being meme coins. 
|
||||
|
||||
Our vision at ALEX is to dissolve the barrier between Bitcoin L1 and L2 to create a seamless Bitcoin DeFi experience. The relationship between Bitcoin and Stacks is fundamentally different from that of Ethereum and e.g. Arbitrum. In the Bitcoin-Stacks pair, L2 equips L1 with smart contract capabilities, while in the Ethereum-Arbitrum duo, both L1 and L2 possess their independent smart contract functionalities. Therefore, a true Bitcoin DeFi experience isn’t about users having to choose between L1 and L2. Instead, it’s about Bitcoin asset holders experiencing DeFi on L1 with L2 running smart contracts unobtrusively in the background. ALEX is not simply adapting to the emerging Bitcoin DeFi landscape — we’re actively shaping it. We’re steadfast in our belief that our efforts will continue to herald an exciting new epoch for Bitcoin DeFi, introducing the benefits of decentralized trading to an even wider audience. And by doing so, we’re facilitating the next generation of Bitcoin users to flourish within this rapidly evolving ecosystem.
|
||||
54
developers/SUMMARY.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Table of contents
|
||||
|
||||
* [😀 What is ALEX?](README.md)
|
||||
|
||||
## 📈 Automated Market Making
|
||||
|
||||
* [Our Design](automated-market-making/platform-architecture-that-supports-ecosystem-development.md)
|
||||
* [Our Design](automated-market-making/trading-pool.md)
|
||||
* [Collateral Rebalancing Pool](automated-market-making/collateral-rebalancing-pool.md)
|
||||
* [Yield Token Pool](automated-market-making/automated-market-making-designed-for-lending-protocols.md)
|
||||
* [Vault](automated-market-making/vault.md)
|
||||
|
||||
## 🧙♀️ Bitcoin Oracle
|
||||
|
||||
* [What is the Bitcoin Oracle](bitcoin-oracle/what-is-the-bitcoin-oracle.md)
|
||||
* ["On Demand" Consensus Data](bitcoin-oracle/on-demand-consensus-data.md)
|
||||
* [Security Audits](bitcoin-oracle/security-audits.md)
|
||||
* [Why Bitcoin Oracle - BRC20](bitcoin-oracle/what-is-the-bitcoin-oracle-1.md)
|
||||
|
||||
## 🩸 XLink
|
||||
|
||||
* [XLink](https://docs.xlink.network)
|
||||
|
||||
## 🚅 Orderbook
|
||||
|
||||
* [What is the Orderbook?](orderbook/what-is-orderbook.md)
|
||||
* [Understanding the Orderbook](orderbook/understanding-the-orderbook.md)
|
||||
* [Using the Orderbook](orderbook/using-the-orderbook.md)
|
||||
|
||||
## 🚀 Launchpad
|
||||
|
||||
* [What is the Launchpad](launchpad/what-is-the-launchpad.md)
|
||||
* [Using the Launchpad](launchpad/using-the-launchpad.md)
|
||||
|
||||
## 📚 Whitepaper
|
||||
|
||||
* [Automated Market Making of Trading Pool](whitepaper/automated-market-making-of-alex/README.md)
|
||||
* [Automated Market Making of Yield Token Pool](whitepaper/automated-market-making-of-alex/automated-market-making-of-alex.md)
|
||||
* [Automated Market Making of Collateral Rebalancing Pool](whitepaper/automated-market-making-of-collateral-rebalancing-pool.md)
|
||||
* [Dive Into Collateral Rebalancing Pool!](whitepaper/dive-into-collateral-rebalancing-pool.md)
|
||||
|
||||
## 🎮 Developers
|
||||
|
||||
* [Networks](developers/networks/README.md)
|
||||
* [Mainnet](developers/networks/mainnet.md)
|
||||
* [Testnet](developers/networks/testnet.md)
|
||||
* [Protocol Contracts](developers/protocol-contracts/README.md)
|
||||
* [amm-pool-v2-01.clar](developers/protocol-contracts/amm-pool-v2-01.clar.md)
|
||||
* [amm-registry-v2-01.clar](developers/protocol-contracts/amm-registry-v2-01.clar.md)
|
||||
* [amm-vault-v2-01.clar](developers/protocol-contracts/amm-vault-v2-01.clar.md)
|
||||
* [farming-campaign-v2-02.clar](developers/protocol-contracts/farming-campaign-v2-02.clar.md)
|
||||
* [amm-pool-v3.clar](developers/protocol-contracts/amm-pool-v3.clar.md)
|
||||
* [self-listing-helper-v3a.clar](developers/protocol-contracts/self-listing-helper-v3a.clar.md)
|
||||
* [REST API](developers/api-references.md)
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Yield Token Pool
|
||||
|
||||
Please refer to our [white paper](https://docs.alexgo.io/whitepaper/automated-market-making-of-alex) for a more rigorous treatment on the subject.
|
||||
|
||||
## Lending and Borrowing Process
|
||||
|
||||
ALEX's core product is essentially a zero coupon bond in conventional finance. A key benefit is reduced uncertainty about a loan's interest rate, resulting in better financial planning. Specifically, prior to entering a loan contract, borrowers and lenders secure the loan's interest rate and tenor on ALEX.
|
||||
|
||||
Here is a concrete example. Rachel has 100 USD. She wants to increase her 100 USD. She chooses to lend her assets out. She's ok with lending out her 100 USD for a fixed term of three months. She goes to ALEX's interface. There, Rachel can see that "three month ayUSD" is currently priced at 0.9 vs USD. Put simply, 1 ayUSD gets her 0.9 USD. She takes her 100 USD and exchanges it for ayUSD. Given the current exchange rate, she gets about 110 ayUSD. Now she waits. Three months pass. Now, Rachel can exchange her 110 ayUSD for USD again. The rate is 1 ayUSD to 1 USD. So Rachel gets 110 USD. That's a gain of 10 USD over 3 months. Pretty nice!
|
||||
|
||||
Here is the general story. Borrowers and lenders enter a loan contract. Specifically, they swap a forward contract based token called "ayToken" with "Token". "Token" is the underlying asset. For example, they swap ayUSD with USD. More generally, the lender lends out "Tokens" and obtains "ayToken" in return. The price of "Token" is lower than its par value. The contract starts when a lender deposits "Token" in an ALEX pool. Then, upon expiration, the lender redeems the underlying asset, "Token", at par value. Because the lender lent out their "Token" at discounted price some time ago, and now redeems "Token" for par value, there is a profit. Pretty nice!
|
||||
|
||||
In mathematical terms, the interest rate r is calculated as $$p_{t}=\frac{1}{e^{rt}}$$, where $$p_{t}$$ is the spot price of ayToken and the interest rate is assumed to compound. The formula utilises one of the most fundamental principles in asset pricing: an asset's present value is the asset's discounted future value. Thus, in our simplified example, $$t$$= 1 and $$r=\log\frac{1}{0.9}\approx10\%$$.
|
||||
|
||||
## Automated Market Making (AMM) Protocol
|
||||
|
||||
When designing the AMM protocol, ALEX believes the following:
|
||||
|
||||
1. AMMs are mathematically neat and reflect economic demand and supply. For example, price should increase when demand is high or supply is low;
|
||||
2. AMMs are a type of mean, which remains constant during trading activities. This approach is also adopted by popular platforms such as _Uniswap,_ which employ algorithmic means; and
|
||||
3. AMMs can be interpreted through the lens of modern finance theory. Doing so enables ALEX to grow and draw comparisons with conventional finance.
|
||||
|
||||
After extensive research, our beliefs led us to an AMM first proposed by _YieldSpace_. While we appreciate the mathematical beauty of their derivation, we adapt it in several ways with _ALEX_. For example, we replace a simple interest rate with a compounding interest rate. This change is in line with standard uses in financial pricing and modelling since Black and Scholes. We also develop a new capital efficiency scheme, as explained below.
|
||||
|
||||
In mathematical terms, our AMM can be expressed as:
|
||||
|
||||
$$
|
||||
x^{1-t}+y^{1-t}=L
|
||||
$$
|
||||
|
||||
where $$x$$, $$y$$, $$t$$ and $$L$$ are, respectively, the balance of "Token", balance of "ayToken", time to maturity and a constant term when $$t$$ is fixed. The interest rate $$r$$ is defined as $$r=\log\left(\frac{y}{x}\right)$$, i.e. the natural logarithm of the ratio of balance between "ayToken" and "Token", while the price of "ayToken" with respect to "Token" is $$\left(\frac{y}{x}\right)^{t}$$.
|
||||
|
||||
Our design depicts an AMM in the of a form of a generalised mean. It makes economic sense because the shape of the curve is decreasing and convex. It incorporates time to maturity $$t$$, which is explicitly built-in to derive ayToken's spot price. We refer readers to our [white paper](https://docs.alexgo.io/whitepaper/automated-market-making-of-alex) for detail.
|
||||
|
||||
## Liquidity Providers (LP) and Capital Efficiency
|
||||
|
||||
LPs deposit both ayToken and Token in a pool to facilitate trading activities. LPs are typically ready to market-make on all possible scenarios of interest rate movements ranging from $$-\infty$$ to $$+\infty$$. However, part of the interest rates curve or movements will never be considered by market participants. On example is the part where the interest rate is negative. Although negative rates can be introduced in the fiat world by central bankers as monetary policy tool, yield farmers in the crypto world are still longing everything to be positive. In ALEX, positive rate refers to spot price of ayToken not exceeding 1 and ayToken reserve is larger than Token.
|
||||
|
||||
Inspired by _Uniswap v3_, ALEX employs virtual tokens - part of the assets that will never be touched, hence is not required to be held by LP.
|
||||
|
||||

|
||||
|
||||
Figure 1 illustrates an example of adopting virtual tokens in the event of positive interest rate. The blue line is the standard AMM. The blue dot marks an equal balance of Token and ayToken of $$y_{v}$$, meaning there is no, or a 0%, interest rate. $$y_{v}$$ is the boundary amount, as any amount lower than it will never be touched by LP to avoid negative rate, which is represented by blue dashed line. Thus, $$y_{v}$$ is virtual token reserve. Effectively, LP is market-making on the red line, which shifts the blue line lower by $$y_{v}$$. When ayToken is depleted as shown by red dashed line, trading activities are suspended.
|
||||
|
||||
A numerical example provided in Table 1 shows capital efficiency with respect to various interest rate, assuming $$t$$= 0.5 and $$L$$= 20 for illustration's sake. When the current interest rate$$r$$= 10%, LPs are required to deposit 95 token and 105 ayToken according to standard AMM. However, if the interest rate is floored at 0%, LP only needs to contribute 5 ayToken, as the rest 100 ayToken would be virtual. This is a decent saving more than 90%.
|
||||
|
||||

|
||||
|
||||
## Yield Curve and Yield Farming
|
||||
|
||||
By expressing the interest rate as $$p_{t}=\frac{1}{e^{rt}}$$, i.e. $$r=-\frac{1}{t}\log p_{t}$$, we can obtain a series of interest rates from trading pool prices with respect to various maturities, based on which we are able to build a yield curve. The Yield curve is the benchmark tool for modelling risk-free rates in conventional finance. The shape of the curve dictates expectations about future interest rate path, which helps market participants understand market behaviours and trends. Currently we might be able to build a Bitcoin yield curve from Bitcoin futures listed on the Chicago Mercantile Exchange (CME). However, not only is the exchange heavily regulated, its trading volume is skewed to the very short dated front end contracts lasting several months only. ALEX aims to offer future contracts up to 1y when the platform goes live. Should markets mature, ALEX may extend to longer tenors.
|
||||
|
||||
Yield farmers can benefit from understanding the yield curve by purchasing ayToken whose tenor corresponds to high interest rates and selling ayToken whose tenor associates with low interest rates. This is a typical “carry" strategy.
|
||||
|
||||
Last but not least, based on the development of the yield curve and solid design work of our AMM, ALEX will be able to provide more products. Specifically, ALEX will be able to offer derivatives, including options and structured products, building on and extending a large amount of literatures and applications in conventional finance.
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Collateral Rebalancing Pool
|
||||
|
||||
Please refer to our [white paper](../whitepaper/automated-market-making-of-collateral-rebalancing-pool.md) for a more rigorous treatment on the subject.
|
||||
|
||||
Collateral Rebalancing Pool ("CRP") uses [Weighted Equation](https://docs.alexgo.io/protocol/platform-architecture-that-supports-ecosystem-development) and dynamically rebalances between Token and Collateral.
|
||||
|
||||
CRP dynamically rebalances collateral to ensure the ayToken minted (i.e. the loan) remain solvent especially in an adverse market environment (i.e. the value of the loan does not exceed the value of collateral). This dynamic rebalancing, together with a careful choice of the key parameters (including LTV and volatilty assumption) allows ALEX to eliminate the needs for liquidation. Any residual gap risk (which CRP cannot address entirely) is addressed through maintaining a strong reserve fund.
|
||||
|
||||
For example, ayBTC / USD pool (i.e. borrow BTC against USD) will implement a dynamic hedging strategy against BTC upside (i.e. sell USD and buy BTC as BTC spot goes up, and vice versa). The resulting rebalancing between USD and BTC will be then executed by arbitrageurs participating in the pool pricing curve. See some illustration [here](https://docs.google.com/spreadsheets/d/1nSg6L30iedpk\_rLhq3E7Zv8ct3Myb\_D8oWmgJzwtwtw/edit?usp=sharing). The borrower effectively is an LP (and receives ayBTC as the Pool Token) and the USD collateral provided will be automatically converted into a basket of USD and BTC.
|
||||
|
||||
The main benefit of such collateral rebalancing is that we can be (much) more aggressive in LTV and remove liquidation entirely (with appropriate LTV and reserve fund). This also allows aggregation of all ayToken into a single pool (rather than separate pool for each borrower).
|
||||
|
||||
The main drawback is that the collateral received at the time of repayment will not be same in USD value as the original value (due to rebalancing).
|
||||
|
||||
When a Borrower mints ayToken by providing appropriate Collateral, the Collateral is converted into a basket of Collateral and Token, with the weights determined by CRP. CRP determines the weights based on the prevailing LTV and uses the following formula:
|
||||
|
||||
$$
|
||||
\begin{split} &w_{Token}=N\left(d_{1}\right)\\ &w_{Collateral}=\left(1-w_{Token}\right)\\ &d_{1}= \frac{1}{\sigma\sqrt{t}}\left[\ln\left(\frac{LTV_{t}}{LTV_{0}}\right) + t\times\left(APY_{Token}-APY_{Collateral} + \frac{\sigma^2}{2}\right)\right] \end{split}
|
||||
$$
|
||||
|
||||
Some readers may note the similarity of the above formula to the [Black & Scholes delta](https://en.wikipedia.org/wiki/Black%E2%80%93Scholes\_model), because it is. CRP essentially implements a delta replicating strategy of a call option on Token / Collateral, buying more Token when LTV moves higher and vice versa.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Our Design
|
||||
|
||||
ALEX allows for implementation of arbitrary trading strategies and borrows its design from [Balancer V2](https://docs.balancer.fi).
|
||||
|
||||
**Equation** abstracts rebalancing and market making logic, while **Pool** encapsulates the value of a strategy. Pool abstraction allows aggregation of the assets of all ALEX pools into a single **vault**, bringing many advantages over traditional DEX architecture.
|
||||
|
||||
## Equation
|
||||
|
||||
Equation triggers Pool rebalancing. This allows creation of any arbitrary rebalancing strategies to be deployed as a pool.
|
||||
|
||||
### Generalised Mean Equation
|
||||
|
||||
Generalised Mean Equation is an invariant function associated with generalised mean that underpins the [non-lending Trading Pools](trading-pool.md) at ALEX. With a suitable parameterisation, Generalised Mean Equation supports both risky pairs (i.e. $$x y=L$$), stable pairs (i.e. $$x +y=L$$) and any linear combination in-between (i.e. Curve)
|
||||
|
||||
### Weighted Equation
|
||||
|
||||
Weighted Equation is the most basic Equation of all and is a fork of [Balancer](https://balancer.fi/whitepaper.pdf), which generalised the constant product AMM popularised by Uniswap. We implement the following formula:
|
||||
|
||||
$$
|
||||
V=\prod_{i}B_{i}^{w_{i}}
|
||||
$$
|
||||
|
||||
Where $$V$$is a constant, $$B_{i}$$ is the balance of token i and $$w_{i}$$ is the weight of token i in the pool.
|
||||
|
||||
As the price of each token changes, arbitrageurs rebalance the pool by making trades. This maintains the desired weighting of the value held by each token whilst collecting trading fees from the traders. [Collateral Rebalancing Pool](collateral-rebalancing-pool.md) implements the Weighted Equation.
|
||||
|
||||
### Yield Token Equation
|
||||
|
||||
Yield Token Equation drives [Yield Token Pool](automated-market-making-designed-for-lending-protocols.md). It follows [Yield Space](https://yield.is/YieldSpace.pdf) and is designed specifically to facilitate efficient trading between ayToken and Token. Our main contribution is to extend the model to allow for capital efficiency from liquidity provision perspective (inspired by [Uniswap V3](https://uniswap.org/whitepaper-v3.pdf)).
|
||||
|
||||
For example, if a pool is configured to trade between 0% and 10% APY, the capital efficiency can improve to 40x compared to when the yield can trade between $$-\infty$$ and $$+\infty$$.
|
||||
|
||||
## Pool
|
||||
|
||||
Pools handle the logic of dynamic trading strategies, whose token rebalancing are then handled by Vault. Rebalancing logic is driven by Equation. Pool issues Pool Token to liquidity providers. The number of Pool Tokens are determined based on a liquidity provider's relative contribution to the Pool. Pool Tokens thus represent proportional ownership of that Pool, or assets in that Pool.
|
||||
|
||||
### Trading Pool
|
||||
|
||||
Trading Pool implements Generalised Mean Equation and, with a suitable parameterisation, supports both risky pairs (i.e. $$x y=L$$), stable pairs (i.e. $$x +y=L$$) and any linear combination in-between (i.e. Curve).
|
||||
|
||||
### Collateral Rebalancing Pool
|
||||
|
||||
Collateral Rebalancing Pool ("CRP") uses Weighted Equation and dynamically rebalances between Token and Collateral. CRP dynamically rebalances collateral to ensure the ayToken minted (i.e. the loan) remains solvent especially in an adverse market environment (i.e. the value of the loan does not exceed the value of collateral).
|
||||
|
||||
### Yield Token Pool
|
||||
|
||||
Yield Token Pool ("YTP") uses Yield Token Equation and is designed specifically to facilitate efficient trading between ayToken and Token.
|
||||
|
||||
## Vault
|
||||
|
||||
Vault holds and manages the assets of all ALEX pools. The separation of pool and vault has many benefits including, among others, cheaper transaction costs for users and quicker learning curve for developers when building custom pools on ALEX.
|
||||
155
developers/automated-market-making/trading-pool.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# Our Design
|
||||
|
||||
## Introduction
|
||||
|
||||
In this section you will find an overview of the ALEX "Trading Pool" and its automated market making (AMM) protocol.
|
||||
|
||||
At ALEX, we build DeFi primitives targeting developers looking to build ecosystem on Bitcoin. As such, we focus on trading of crypto assets with Bitcoin as the settlement layer. At the core of this focus is the AMM protocol, which allows users to exchange one crypto asset for another in a trustless manner.
|
||||
|
||||
Trading Pool implements Generalized Mean Equation and, with a suitable parameterisation, supports both risky pairs (i.e. $$x y=L$$), stable pairs (i.e. $$x +y=L$$) and any linear combination in-between (i.e. Curve).
|
||||
|
||||
Trading Pool is parameterised with a single parameter $$t$$. $$t$$ can be between 0 and 1, with $$t=1$$ being equivalent of constant product formula (i.e. Uniswap V2) and $$t=0$$ being equivalent of constant sum formula (i.e. mStable). $$0<t <1$$ then gives a Curve-like formula.
|
||||
|
||||
Regarding its implementation, the Trading Pool protocol consists of a set of smart contracts built on the Stacks blockchain that facilitate trading operations within the ALEX DeFi ecosystem. Below, there are listed the main features of the pool.
|
||||
|
||||
{% hint style="info" %}
|
||||
For more of the theory and fundaments behind the Alex AMM protocol refer to the [ALEX AMM Whitepaper](../whitepaper/automated-market-making-of-alex/). If you are looking for technical details and implementation design please refer to the [Developers Protocol Contracts section](../developers/protocol-contracts/#alex-dao-amm-trading-pool).
|
||||
{% endhint %}
|
||||
|
||||
{% hint style="danger" %}
|
||||
**Caution on fixed notation**: Please note we use 8-digit fixed notation to represent decimals. If you interact directly with any of our contracts, you must provide all numbers in the correct format. For example, 1 should be passed as 10,000,000 (= 1e8), i.e. 1.00000000.
|
||||
{% endhint %}
|
||||
|
||||
## Pool management
|
||||
|
||||
### Pool creation
|
||||
|
||||
A pair can be registered (i.e. a pool can be created) by calling `create-pool` function indicating the traits of the two tokens (`token-x` and `token-y`), the factor $$t$$, the governance address (`pool-owner`) and the initial liquidity.
|
||||
|
||||
Trading Pool is permission-less in that anyone can register a pair with initial liquidity, so long as the two tokens are pre-approved (this is to prevent introducing malicious tokens to the platform).
|
||||
|
||||
### Pool governance
|
||||
|
||||
Certain privileged functions are available to `pool-owner` to govern the pool. The `pool-owner` address is set at the time of a pool creation. ALEX DAO, as part of its governance, has the power to update and replace the `pool-owner` address. Therefore, you can view this as ALEX DAO delegating the governance of each pool to its respective `pool-owner`.
|
||||
|
||||
[Refer to the comprehensive list of pool-governed setters](../developers/protocol-contracts/amm-pool-v2-01.clar.md#setters).
|
||||
|
||||
## Pool liquidity operations
|
||||
|
||||
Users can participate by adding (injecting liquidity with function `add-to-position`) or reducing (withdrawing with function `reduce-position`) assets positions in a specific pool that deals with a pair of tokens. When users add assets, they receive pool tokens (a.k.a. LP Tokens), which represent their share of the pool and potential earnings. When withdrawing assets, users return pool tokens.
|
||||
|
||||
### Adding liquidity
|
||||
|
||||
When adding liquidity to a pool, you need to specify the amount of token-x and have the option of specifying the maximum amount of token-y you are willing to pair with token-x (i.e. slippage control). If adding liquidity requires more token-y than the maximum you specified, then the call will fail. You must also have at least the amount of token-x and the maximum amount of token-y in your wallet - otherwise the call will fail.
|
||||
|
||||
Once the liquidity is added, the pool will mint a pool token as a proof of proportional ownership of the pool liquidity. The number of the pool token being minted is proportional to the amount of liquidity you added compared to the existing liquidity at the pool.
|
||||
|
||||
The pool token is transferable and may be used at other protocols (for example, as a collateral).
|
||||
|
||||
### Removing liquidity
|
||||
|
||||
When removing liquidity from a pool, you need to specify the percentage of your pool tokens that you want to liquidate, i.e. between 0 and 1.
|
||||
|
||||
The percentage will be converted to the number of pool tokens to be burnt and the corresponding amount of token-x and token-y will be sent to you.
|
||||
|
||||
## Trading
|
||||
|
||||
When a pool for a specific token pair is funded, it allows users to exchange those tokens, with a fee for each swap. Users can swap one token with another by calling `swap-x-for-y` or `swap-y-for-x`. As the names imply, `swap-x-for-y` swaps token-x into token-y and `swap-y-for-x` swaps token-y into token-x.
|
||||
|
||||
Users can specify the slippage limit (the minimum amount of the desired target token they expect to receive: `min-dy` and `min-dx`, respectively), so that the call fails if the swapped amount does not meet your target.
|
||||
|
||||
### Swap helper and routing
|
||||
|
||||
It may not be reasonable to expect developers or users to remember the correct order of token pairs. Therefore, we provide `swap-helper` function that helps choose between `swap-x-for-y` and `swap-y-for-x` and swaps `token-x` into `token-y` without users having to know the correct order.
|
||||
|
||||
Sometimes, a direct swap isn't possible. In such cases, the system employs intermediate tokens to complete the exchange. For example, swapping Token-A to Token-C might require an intermediate swap through Token-B. This process is known as a multi-hop or multi-step swap. It is intended for scenarios where a direct pool for Token-A/Token-C does not exist, but there are pools for Token-A/Token-B and Token-B/Token-C. To facilitate multi-hop swaps, we provide three helper routing functions: `swap-helper-a`, `swap-helper-b`, and `swap-helper-c`. These functions support multi-hop swaps involving two, three, and four pools, respectively.
|
||||
|
||||
## Helper functions
|
||||
|
||||
In addition to the swap helpers and routing functions, we provide a few helpful functions.
|
||||
|
||||
### Oracle
|
||||
|
||||
Trading Pool provides two types of on-chain oracles - instant and resilient. Their implementations are similar to Uniswap V2.
|
||||
|
||||
Instant oracle (`get-oracle-instant`) gives you the latest pool-implied price (i.e. most up-to-date), but is subject to a higher manipulation risk. Instant oracle may be suitable for, for example, arbitrage or liquidation.
|
||||
|
||||
Resilient oracle (`get-oracle-resilient`) on the other hand gives you a trade-weighted price that is therefore more resilient to potential manipulation but is less up to date. Resilient oracle may be more suitable for, for example, benchmarking to lending and borrowing.
|
||||
|
||||
### Liquidity provision
|
||||
|
||||
In certain cases, prior information is necessary to perform operations effectively. For example, to determine the slippage limit, you need to know the specific amounts of token-x and token-y required to mint a certain number of pool tokens. Additionally, it can be useful to know how many pool tokens can be minted or burnt if a specific amount of token-x and token-y are provided. The relevant helper functions for these operations are: `get-position-given-mint`, `get-position-given-burn` and `get-token-given-position`.
|
||||
|
||||
## Glossary
|
||||
|
||||
### Base Token
|
||||
|
||||
The base token is the cryptocurrency token that a user currently possesses and submits during a swap transaction.
|
||||
|
||||
### Dx
|
||||
|
||||
The amount of the token-x involved in liquidity and trading operations.
|
||||
|
||||
### Dy
|
||||
|
||||
The amount of the token-y involved in liquidity and trading operations.
|
||||
|
||||
### Factor
|
||||
|
||||
The factor is a multiplier (scaling factor) defined within a token pair pool, playing a critical role in determining the value of `dy` (amount of target token) given `dx` (amount of base token) and the pool balances of each token. Together with the token principals, the factor constitutes the pool identifier that is utilized to retrieve the pool details.
|
||||
|
||||
### Fee
|
||||
|
||||
The cost associated with performing a swap or other operations within the platform. It is deducted from each transaction on the "in" leg (i.e., token-x for `swap-x-for-y` and token-y for `swap-y-for-x`). The fee to be calculated is set at the [pool creation](trading-pool.md#pool-creation) and may be updated through the governance. Part of the fee may be [rebated](trading-pool.md#fee-rebate) to liquidity providers as a reward.
|
||||
|
||||
### Fee Rate
|
||||
|
||||
The percentage of the transaction amount that is taken as a fee during a swap or other operations.
|
||||
|
||||
### Fee Rebate
|
||||
|
||||
The portion of the swap fee that is reinvested into the relevant pool's liquidity, causing the pool's invariant to increase slightly after each transaction. This mechanism is similar to that of Uniswap V2.
|
||||
|
||||
### In given out
|
||||
|
||||
If you want to know the amount of token-x you may need to provide to get a target amount of token-y (or vice versa), you can use `get-x-in-given-y-out` and `get-y-in-give-x-out`, respectively.
|
||||
|
||||
### In given price
|
||||
|
||||
If you are an arbitrageur, you may want to know the amount of token-x or token-y you need to provide to rebalance the pool-implied price to a target. In such a case, you can use `get-x-given-price` or `get-y-given-price`.
|
||||
|
||||
### Liquidity Positions
|
||||
|
||||
When a user provides liquidity to a pool, they are said to be adding liquidity positions (using the `add-to-position` function). The reverse operation occurs when users withdraw their assets, thus reducing their positions (using the `reduce-position` function). Both operations involve the minting and burning of LP Tokens, respectively, to represent the user's share of the pool.
|
||||
|
||||
### Maximum Dy (`max-dy`)
|
||||
|
||||
In the context of an add positions transaction, this amount specifies the maximum quantity of token-y that the user is willing to deposit. If the required amount exceeds this specified limit, the transaction will be reverted with the error `ERR-EXCEEDS-MAX-SLIPPAGE`.
|
||||
|
||||
### Minimum Dy (`min-dy`)
|
||||
|
||||
In the context of a swap transaction, this amount defines the minimum quantity of the target token that the user expects to receive. If the resulting amount falls below this specified threshold, the transaction will be reverted with the error `ERR-EXCEEDS-MAX-SLIPPAGE`.
|
||||
|
||||
### Out given in
|
||||
|
||||
Sometimes you may want to know the expected amount of token-y if you were to swap certain amount of token-x. Or you may want to know the expected amount of token-x for some token-y. Two read-only functions - `get-y-given-x` and `get-x-given-y` will do that for you.
|
||||
|
||||
### Pool token / LP Token
|
||||
|
||||
Pool token, also known as "LP Token" (Liquidity Provider Token); issued to users who contribute assets to a liquidity pool, representing their share of the pool and potential earnings. The token contract is `token-amm-pool-v2-01` and it implements [SIP013](https://github.com/stacksgov/sips/pull/42). Each pool is mapped to a unique id (`pool-id`) with associated liquidity mapped to the balance under that id (`token-id`).
|
||||
|
||||
### Ratio
|
||||
|
||||
The ratio represents the relationship between the amounts of a token pair involved in pool operations. Each pool has two predefined values, `max-in-ratio` and `max-out-ratio`, which set the maximum amounts that can be involved in swap operations.
|
||||
|
||||
### Slippage
|
||||
|
||||
In the Automated Market Maker (AMM) Pool contract, slippage refers to the difference between the calculated amount of the target token and the configured maximum or minimum limit during a transaction. If no limit is set, the default limits are `u340282366920938463463374607431768211455` (the maximum value for `uint` type in Clarity language: `2**128 - 1`) for the maximum and `u0` for the minimum. These limits are enforced within the pool contract and are validated using the custom error `ERR-EXCEEDS-MAX-SLIPPAGE`.
|
||||
|
||||
### Swap Transaction
|
||||
|
||||
A swap transaction refers to a type of operation whereby a user exchanges a given quantity of one cryptocurrency token for another. Within the context of the ALEX Trading Pool, swap transactions are executed using predefined token pairs existing within a pre-established liquidity pool.
|
||||
|
||||
### Target Token
|
||||
|
||||
Also known as the "quoted" token, the target token is the cryptocurrency token that a user will receive as a result of a swap transaction.
|
||||
19
developers/automated-market-making/vault.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Vault
|
||||
|
||||
Vault holds and manages the assets of all ALEX pools. The separation of pool and vault has many benefits including, among others, cheaper transaction costs for users and quicker learning curve for developers when building custom pools on ALEX.
|
||||
|
||||
{% hint style="info" %}
|
||||
If you are looking for technical details and implementation design please refer to the [Developers Protocol Contracts section](../developers/protocol-contracts/#vault-amm-vault-v2-01.clar).
|
||||
{% endhint %}
|
||||
|
||||
### Flash Loan
|
||||
|
||||
Aggregating the assets of all ALEX pools into a single vault allows for the offering of Flash Loan, [popularized by AAVE](https://aave.com/flash-loans/).
|
||||
|
||||
Flash Loans are uncollateralized loans that must be repaid (plus interest) in the same transaction as it is borrowed. Since everything done with the loan must be completed in a single transaction, there are codified guarantees that make it impossible for borrowers to run away with the tokens.
|
||||
|
||||
Flash Loan allows arbitrageurs to take advantages of any price discrepancies in two or more pools without the needs for holding any input tokens.
|
||||
551
developers/bitcoin-oracle/on-demand-consensus-data.md
Normal file
@@ -0,0 +1,551 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# "On Demand" Consensus Data
|
||||
|
||||
## End consumer of consensus data dictates how it is validated and verified
|
||||
|
||||
Bitcoin Oracle produces the consensus data based on the computation from the off-chain engines, but the validation and verification of such consensus data can be implemented by the end consumer as they see fit.
|
||||
|
||||
For example, wallet integrating Bitcoin Oracle may implement a client-side verification of the consensus data, instead of relying on an on-chain validation.
|
||||
|
||||
A website that wants to display users' BRC20 balances, but do not need to verify the consensus data, may simply use the data without verification.
|
||||
|
||||
A BRC20 trading dapp on an EVM-compatible Bitcoin L2 may implement their own smart contract written in Solidity to validate the consensus data, before initiating other smart contract interactions.
|
||||
|
||||
## So how can one fetch the consensus data from Bitcoin Oracle?
|
||||
|
||||
### Summary data
|
||||
|
||||
If you need only the summary data, without its associated consensus data, you can use the following endpoints at [https://api.alexgo.io](https://api.alexgo.io/).
|
||||
|
||||
{% swagger src="https://api.alexlab.co/swagger-ui-yaml" path="/v1/brc20/user-balance" method="get" %}
|
||||
[https://api.alexlab.co/swagger-ui-yaml](https://api.alexlab.co/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/brc20/bitcoin-tx-indexed" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
#### Examples
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="User balance" %}
|
||||
{% code overflow="wrap" %}
|
||||
```sh
|
||||
curl --location 'https://api.alexgo.io/v1/brc20/user-balance?tick=ORMM&user=bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq' \
|
||||
--header 'Accept: application/json'
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
**Response**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```json
|
||||
{
|
||||
"balance": "962959356579080000000000",
|
||||
"up-to-block": "825995"
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="Bitcoin tx indexed" %}
|
||||
{% code overflow="wrap" %}
|
||||
```sh
|
||||
curl --location 'https://api.alexgo.io/v1/brc20/bitcoin-tx-indexed?bitcoin-tx-id=9778d139d55f3dca60e4d45942cf6c0ab97e23fd24771696b9ecdfba52303b01&offset=0&output=0' \
|
||||
--header 'Accept: application/json'
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
**Response**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```json
|
||||
{
|
||||
"from": "bc1p42g525vmjry4k66pq39a03375esmmdkqhk76ty9yed6elxtcj9ds9pm7dt",
|
||||
"to": "bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq",
|
||||
"tick": "ORMM",
|
||||
"amt": "3700000000000000000000000"
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
### Full consensus data
|
||||
|
||||
If you need the full consensus data, you can use the following endpoint at [https://api.bitcoin-oracle.network](https://api.bitcoin-oracle.network/).
|
||||
|
||||
The endpoint performs a match against an array where each item represents a distinct condition. If multiple query parameters are specified, such as `from` and `height`, the returned transactions must satisfy **all** the given conditions. 
|
||||
|
||||
The endpoint supports query conditions for addresses in two formats: Bech32 and PKScript.
|
||||
|
||||
{% swagger src="https://api.bitcoin-oracle.network/swagger-ui-yaml" path="/v1/brc20" method="post" %}
|
||||
[https://api.bitcoin-oracle.network/swagger-ui-yaml](https://api.bitcoin-oracle.network/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
#### How to validate the consensus data
|
||||
|
||||
With the consensus data, you can 
|
||||
|
||||
1. determine if a minimum threshold you require was reached among data providers
|
||||
2. (for Stacks smart contracts) determine whether or not the relevant Bitcoin transaction was indeed mined
|
||||
|
||||
#### Validation of off-chain computation
|
||||
|
||||
`order_hash` is the sha256 hash of the following tuple:
|
||||
|
||||
```json
|
||||
{
|
||||
bitcoin-tx: (buff 8192),
|
||||
output: uint,
|
||||
offset: uint,
|
||||
tick: (string-utf8 4),
|
||||
amt: uint,
|
||||
from: (buff 128),
|
||||
to: (buff 128),
|
||||
from-bal: uint,
|
||||
to-bal: uint,
|
||||
decimals: uint
|
||||
}
|
||||
```
|
||||
|
||||
Each data provider then creates and signs a sha256 hash of a concatenation of 
|
||||
|
||||
1. Structured data prefix: `0x534950303138`
|
||||
2. Message domain: `0x6d11cd301d11961e7cfeabd61e3f4da17f42f3d627362c8878aa9cbb5c532be2`
|
||||
3. `order_hash`
|
||||
|
||||
The addition of the structured data prefix and the message domain mitigates the message replay risk.
|
||||
|
||||
The signatures and public keys of the data providers, who validated the event, are available under `signatures` and `signer_pubkeys`, respectively, together with `signer_types` indicating which implementation or type each signer uses (for example, for BRC20, there are three types - `bis`, `hiro` and `uinsat`).
|
||||
|
||||
End consumer of this consensus data can then use these data to verify that each signer validated this particular BRC20 transfer.
|
||||
|
||||
#### Verification of Bitcoin transaction (Stacks only)
|
||||
|
||||
The consensus data provides additional information to allow smart contracts on Stacks to verify that the relevant Bitcoin transaction is indeed mined, which enhances the security and lessens its dependence on the off-chain data provider.
|
||||
|
||||
For more information, please refer to [https://explorer.hiro.so/txid/SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.clarity-bitcoin-v1-06?chain=mainnet](https://explorer.hiro.so/txid/SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.clarity-bitcoin-v1-06?chain=mainnet).
|
||||
|
||||
#### Examples
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="Historical transfer by Bitcoin {tx_id}" %}
|
||||
{% code overflow="wrap" %}
|
||||
```sh
|
||||
curl --location --request POST 'https://api.bitcoin-oracle.network/v1/brc20' \
|
||||
--header 'x-service-type: INDEXER' \
|
||||
--header 'x-version: 0.0.1' \
|
||||
--data-raw '{
|
||||
"type": "tx_id",
|
||||
"tx_id":"9778d139d55f3dca60e4d45942cf6c0ab97e23fd24771696b9ecdfba52303b01",
|
||||
"output": 0,
|
||||
"offset": 0
|
||||
}'
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
**Response**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"tx_hash": "020000000001022f119e4f00a1ea91771cd8dfc8e459cf98b7aac138aef6f4ff9394f53ab28faf0000000000fdffffff3f90f44767460ec0a742fe5320238cd05d8fbd3d292768ea5d5b38b29c7744760100000000fdffffff0322020000000000002251207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba1297318998e0902000000000016001412c625feb11e662805f4923b289a15d6be803ed70000000000000000386a360c0000000204646573740100000000000000000000000000000000047573657205166f4c0cb79258561dddf49ad4b91479324935b0dd01403a09be942697dc269ae4766a2a885911fd477306cd3d5dfad03cad5377d887a7b59c0bf78734df40cd6d44940a20f5f02896911a43231e81b7ee864311cd8cd202473044022035237c80120014629af1b1f1db73f6ed74e748a5afd398e05ce35a81e56130f902204ef75df72cce7fc124ce4696cb8155b5dfad16950eea1c7de0eedc761ffa7ff00121025ce5bd977e990a1e653519333c35fa2d7531a1b5cc6737e2057165ff148aca5b00000000",
|
||||
"order_hash": "337d20f2431441591a46f8c65569e5e8bea98c70e0d6fa243ed19c4b40c3f9b7",
|
||||
"amt": "3700000000000000000000000",
|
||||
"bitcoin_tx": "00000020e7f505d8d9098cca86d39b4889f4ae4d2514929e16b0030000000000000000008d1d3bbee8ca41c87cea86e0d1eef44789a34051b3b48c68c4f358d488e75de8948e9f6569d80317921bb034",
|
||||
"decimals": "18",
|
||||
"from": {
|
||||
"pkscript": "5120aa9145519b90c95b6b41044bd7c63ea661bdb6c0bdbda590a4cb759f9978915b",
|
||||
"address": "bc1p42g525vmjry4k66pq39a03375esmmdkqhk76ty9yed6elxtcj9ds9pm7dt"
|
||||
},
|
||||
"from_bal": "0",
|
||||
"offset": "0",
|
||||
"output": "0",
|
||||
"tick": "ORMM",
|
||||
"to": {
|
||||
"pkscript": "51207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba129731899",
|
||||
"address": "bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
},
|
||||
"to_bal": "612741501250300100000000000",
|
||||
"tx_id": "9778d139d55f3dca60e4d45942cf6c0ab97e23fd24771696b9ecdfba52303b01",
|
||||
"proof_hashes": [
|
||||
"0048801e960dbf63c4602968259b23efc84d01b56f765c748d02b7387fda083c",
|
||||
"c2ad185f79ab5e04def0b4ae8a1b971f03d738501c999be7b04d453f115d0c99",
|
||||
"dde8ca635a80f4978049d95e53621f85b81a109e739c8a17e3a87589baff3378",
|
||||
"3f0a3723a1141af85387d1180c5d25fd5c0ba1de9d140d46b608511659d146e1",
|
||||
"02c2fe271149f95e3b2ce44441158c0e6459df5a75297df6d3e4733d78ee5577",
|
||||
"223866a29166b32436d84381dea03193a1fddcabe93d5752a05d42539c754641",
|
||||
"b58fd40d5861a7a1407315f2d91e328442fa25f4a9f2dc7a937aff2e05fb0c24",
|
||||
"f2d8b750b230ea7a05ab8c8f9c607410bfa8c85b1066128be835cd7f3fe3e787",
|
||||
"190320c66700b5bf8decea0a29491b5c3a0f53692823107dbe01b99af615c263",
|
||||
"fa3e58599aa6573f3702bf0d53bd306f57713a642b696142131b6e009257d600",
|
||||
"ecf791c893b78c40c2aad6125aea4ee5dd39d92a4ecbd421a9b38c90433dd3d3",
|
||||
"2c202c28b430c7b7b726b006c55a661af87fdcb349ded3becc5d563baa39cf8a"
|
||||
],
|
||||
"tx_index": "2049",
|
||||
"tree_depth": "12",
|
||||
"height": "825254",
|
||||
"signers": [
|
||||
"SP1B0DHZV858RCBC8WG1YN5W9R491MJK88QPPC217",
|
||||
"SP35D14R1JB3KHE4D55MMN646GFZJ198B7FMBG5PD",
|
||||
"SP3ZCGVGSQWT6TJAXZRXHCYA6SWGNSNGKHSYA1F2Q"
|
||||
],
|
||||
"signer_pubkeys": [
|
||||
"02883d08893252a59cf25aafffe1417bf74a7526621665a4bc0060e4aa95405891",
|
||||
"0255966348dacd748595af0439e0a1cc947b2e3dc090acd8f90c32c30c3099b0a0",
|
||||
"03c1a83abd5a199cb502818a110e2d55f67aae0e894f776c189b9f73556f8402a9"
|
||||
],
|
||||
"signer_types": [
|
||||
"bis",
|
||||
"hiro",
|
||||
"unisat"
|
||||
],
|
||||
"signatures": [
|
||||
"0fc66c9a7fe85ce78740fcc07f60ac47d5a05c469b2ca5f1ee16f5cc4b6eda1e41367bd67b03e7fbc6e4ba883c6fad1551373bd786f59afefbed268d08e59fd500",
|
||||
"cd63d0ffae136ca1ffe1681ec4b062ada335b002b96b2a6153cea0a1f3ed94f14b601202ac2c8ecb229168c1264d0fad3475307df5a493ad98b9fae431f5138401",
|
||||
"f7045fca2269e91d632f4a259eb47cc9f3ebb17dd64f7b8f4dfc8aa2ecfb2e716bfcce5f3c8ec6be0987c6f620d8c4205cd8d0c9728ee73c8892768ffca211c101"
|
||||
],
|
||||
"created_at": 1704970783160,
|
||||
"updated_at": 1704970783160
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="Historical transfer of {tick} from {from} to {to}" %}
|
||||
{% code overflow="wrap" %}
|
||||
```sh
|
||||
curl --location --request POST 'https://api.bitcoin-oracle.network/v1/brc20' \
|
||||
--header 'x-service-type: INDEXER' \
|
||||
--header 'x-version: 0.0.1' \
|
||||
--data-raw '{
|
||||
"from": [
|
||||
"bc1p42g525vmjry4k66pq39a03375esmmdkqhk76ty9yed6elxtcj9ds9pm7dt"
|
||||
],
|
||||
"to": [
|
||||
"bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
],
|
||||
"tick": [
|
||||
"ORMM"
|
||||
],
|
||||
"limit": 10
|
||||
}'
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
**Response**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"tx_hash": "020000000001022f119e4f00a1ea91771cd8dfc8e459cf98b7aac138aef6f4ff9394f53ab28faf0000000000fdffffff3f90f44767460ec0a742fe5320238cd05d8fbd3d292768ea5d5b38b29c7744760100000000fdffffff0322020000000000002251207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba1297318998e0902000000000016001412c625feb11e662805f4923b289a15d6be803ed70000000000000000386a360c0000000204646573740100000000000000000000000000000000047573657205166f4c0cb79258561dddf49ad4b91479324935b0dd01403a09be942697dc269ae4766a2a885911fd477306cd3d5dfad03cad5377d887a7b59c0bf78734df40cd6d44940a20f5f02896911a43231e81b7ee864311cd8cd202473044022035237c80120014629af1b1f1db73f6ed74e748a5afd398e05ce35a81e56130f902204ef75df72cce7fc124ce4696cb8155b5dfad16950eea1c7de0eedc761ffa7ff00121025ce5bd977e990a1e653519333c35fa2d7531a1b5cc6737e2057165ff148aca5b00000000",
|
||||
"order_hash": "337d20f2431441591a46f8c65569e5e8bea98c70e0d6fa243ed19c4b40c3f9b7",
|
||||
"amt": "3700000000000000000000000",
|
||||
"bitcoin_tx": "00000020e7f505d8d9098cca86d39b4889f4ae4d2514929e16b0030000000000000000008d1d3bbee8ca41c87cea86e0d1eef44789a34051b3b48c68c4f358d488e75de8948e9f6569d80317921bb034",
|
||||
"decimals": "18",
|
||||
"from": {
|
||||
"pkscript": "5120aa9145519b90c95b6b41044bd7c63ea661bdb6c0bdbda590a4cb759f9978915b",
|
||||
"address": "bc1p42g525vmjry4k66pq39a03375esmmdkqhk76ty9yed6elxtcj9ds9pm7dt"
|
||||
},
|
||||
"from_bal": "0",
|
||||
"offset": "0",
|
||||
"output": "0",
|
||||
"tick": "ORMM",
|
||||
"to": {
|
||||
"pkscript": "51207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba129731899",
|
||||
"address": "bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
},
|
||||
"to_bal": "612741501250300100000000000",
|
||||
"tx_id": "9778d139d55f3dca60e4d45942cf6c0ab97e23fd24771696b9ecdfba52303b01",
|
||||
"proof_hashes": [
|
||||
"0048801e960dbf63c4602968259b23efc84d01b56f765c748d02b7387fda083c",
|
||||
"c2ad185f79ab5e04def0b4ae8a1b971f03d738501c999be7b04d453f115d0c99",
|
||||
"dde8ca635a80f4978049d95e53621f85b81a109e739c8a17e3a87589baff3378",
|
||||
"3f0a3723a1141af85387d1180c5d25fd5c0ba1de9d140d46b608511659d146e1",
|
||||
"02c2fe271149f95e3b2ce44441158c0e6459df5a75297df6d3e4733d78ee5577",
|
||||
"223866a29166b32436d84381dea03193a1fddcabe93d5752a05d42539c754641",
|
||||
"b58fd40d5861a7a1407315f2d91e328442fa25f4a9f2dc7a937aff2e05fb0c24",
|
||||
"f2d8b750b230ea7a05ab8c8f9c607410bfa8c85b1066128be835cd7f3fe3e787",
|
||||
"190320c66700b5bf8decea0a29491b5c3a0f53692823107dbe01b99af615c263",
|
||||
"fa3e58599aa6573f3702bf0d53bd306f57713a642b696142131b6e009257d600",
|
||||
"ecf791c893b78c40c2aad6125aea4ee5dd39d92a4ecbd421a9b38c90433dd3d3",
|
||||
"2c202c28b430c7b7b726b006c55a661af87fdcb349ded3becc5d563baa39cf8a"
|
||||
],
|
||||
"tx_index": "2049",
|
||||
"tree_depth": "12",
|
||||
"height": "825254",
|
||||
"signers": [
|
||||
"SP1B0DHZV858RCBC8WG1YN5W9R491MJK88QPPC217",
|
||||
"SP35D14R1JB3KHE4D55MMN646GFZJ198B7FMBG5PD",
|
||||
"SP3ZCGVGSQWT6TJAXZRXHCYA6SWGNSNGKHSYA1F2Q"
|
||||
],
|
||||
"signer_pubkeys": [
|
||||
"02883d08893252a59cf25aafffe1417bf74a7526621665a4bc0060e4aa95405891",
|
||||
"0255966348dacd748595af0439e0a1cc947b2e3dc090acd8f90c32c30c3099b0a0",
|
||||
"03c1a83abd5a199cb502818a110e2d55f67aae0e894f776c189b9f73556f8402a9"
|
||||
],
|
||||
"signer_types": [
|
||||
"bis",
|
||||
"hiro",
|
||||
"unisat"
|
||||
],
|
||||
"signatures": [
|
||||
"0fc66c9a7fe85ce78740fcc07f60ac47d5a05c469b2ca5f1ee16f5cc4b6eda1e41367bd67b03e7fbc6e4ba883c6fad1551373bd786f59afefbed268d08e59fd500",
|
||||
"cd63d0ffae136ca1ffe1681ec4b062ada335b002b96b2a6153cea0a1f3ed94f14b601202ac2c8ecb229168c1264d0fad3475307df5a493ad98b9fae431f5138401",
|
||||
"f7045fca2269e91d632f4a259eb47cc9f3ebb17dd64f7b8f4dfc8aa2ecfb2e716bfcce5f3c8ec6be0987c6f620d8c4205cd8d0c9728ee73c8892768ffca211c101"
|
||||
],
|
||||
"created_at": 1704970783160,
|
||||
"updated_at": 1704970783160
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="Batch historical transfer (multiple {tick}, {from} and/or {to})" %}
|
||||
{% code overflow="wrap" %}
|
||||
```sh
|
||||
curl --location --request POST 'https://api.bitcoin-oracle.network/v1/brc20' \
|
||||
--header 'x-service-type: INDEXER' \
|
||||
--header 'x-version: 0.0.1' \
|
||||
--data-raw '{
|
||||
"from": [
|
||||
"bc1p42g525vmjry4k66pq39a03375esmmdkqhk76ty9yed6elxtcj9ds9pm7dt",
|
||||
"bc1pgpxqrl8gcykc970kkczswaau4ur4rcjat9y0pvmagkfhhjddzscq6mdpf4"
|
||||
],
|
||||
"to": [
|
||||
"bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
],
|
||||
"tick": [
|
||||
"ORMM",
|
||||
"OXBT"
|
||||
],
|
||||
"limit": 100
|
||||
}'
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
**Response**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"tx_hash": "020000000001022f119e4f00a1ea91771cd8dfc8e459cf98b7aac138aef6f4ff9394f53ab28faf0000000000fdffffff3f90f44767460ec0a742fe5320238cd05d8fbd3d292768ea5d5b38b29c7744760100000000fdffffff0322020000000000002251207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba1297318998e0902000000000016001412c625feb11e662805f4923b289a15d6be803ed70000000000000000386a360c0000000204646573740100000000000000000000000000000000047573657205166f4c0cb79258561dddf49ad4b91479324935b0dd01403a09be942697dc269ae4766a2a885911fd477306cd3d5dfad03cad5377d887a7b59c0bf78734df40cd6d44940a20f5f02896911a43231e81b7ee864311cd8cd202473044022035237c80120014629af1b1f1db73f6ed74e748a5afd398e05ce35a81e56130f902204ef75df72cce7fc124ce4696cb8155b5dfad16950eea1c7de0eedc761ffa7ff00121025ce5bd977e990a1e653519333c35fa2d7531a1b5cc6737e2057165ff148aca5b00000000",
|
||||
"order_hash": "337d20f2431441591a46f8c65569e5e8bea98c70e0d6fa243ed19c4b40c3f9b7",
|
||||
"amt": "3700000000000000000000000",
|
||||
"bitcoin_tx": "00000020e7f505d8d9098cca86d39b4889f4ae4d2514929e16b0030000000000000000008d1d3bbee8ca41c87cea86e0d1eef44789a34051b3b48c68c4f358d488e75de8948e9f6569d80317921bb034",
|
||||
"decimals": "18",
|
||||
"from": {
|
||||
"pkscript": "5120aa9145519b90c95b6b41044bd7c63ea661bdb6c0bdbda590a4cb759f9978915b",
|
||||
"address": "bc1p42g525vmjry4k66pq39a03375esmmdkqhk76ty9yed6elxtcj9ds9pm7dt"
|
||||
},
|
||||
"from_bal": "0",
|
||||
"offset": "0",
|
||||
"output": "0",
|
||||
"tick": "ORMM",
|
||||
"to": {
|
||||
"pkscript": "51207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba129731899",
|
||||
"address": "bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
},
|
||||
"to_bal": "612741501250300100000000000",
|
||||
"tx_id": "9778d139d55f3dca60e4d45942cf6c0ab97e23fd24771696b9ecdfba52303b01",
|
||||
"proof_hashes": [
|
||||
"0048801e960dbf63c4602968259b23efc84d01b56f765c748d02b7387fda083c",
|
||||
"c2ad185f79ab5e04def0b4ae8a1b971f03d738501c999be7b04d453f115d0c99",
|
||||
"dde8ca635a80f4978049d95e53621f85b81a109e739c8a17e3a87589baff3378",
|
||||
"3f0a3723a1141af85387d1180c5d25fd5c0ba1de9d140d46b608511659d146e1",
|
||||
"02c2fe271149f95e3b2ce44441158c0e6459df5a75297df6d3e4733d78ee5577",
|
||||
"223866a29166b32436d84381dea03193a1fddcabe93d5752a05d42539c754641",
|
||||
"b58fd40d5861a7a1407315f2d91e328442fa25f4a9f2dc7a937aff2e05fb0c24",
|
||||
"f2d8b750b230ea7a05ab8c8f9c607410bfa8c85b1066128be835cd7f3fe3e787",
|
||||
"190320c66700b5bf8decea0a29491b5c3a0f53692823107dbe01b99af615c263",
|
||||
"fa3e58599aa6573f3702bf0d53bd306f57713a642b696142131b6e009257d600",
|
||||
"ecf791c893b78c40c2aad6125aea4ee5dd39d92a4ecbd421a9b38c90433dd3d3",
|
||||
"2c202c28b430c7b7b726b006c55a661af87fdcb349ded3becc5d563baa39cf8a"
|
||||
],
|
||||
"tx_index": "2049",
|
||||
"tree_depth": "12",
|
||||
"height": "825254",
|
||||
"signers": [
|
||||
"SP1B0DHZV858RCBC8WG1YN5W9R491MJK88QPPC217",
|
||||
"SP35D14R1JB3KHE4D55MMN646GFZJ198B7FMBG5PD",
|
||||
"SP3ZCGVGSQWT6TJAXZRXHCYA6SWGNSNGKHSYA1F2Q"
|
||||
],
|
||||
"signer_pubkeys": [
|
||||
"02883d08893252a59cf25aafffe1417bf74a7526621665a4bc0060e4aa95405891",
|
||||
"0255966348dacd748595af0439e0a1cc947b2e3dc090acd8f90c32c30c3099b0a0",
|
||||
"03c1a83abd5a199cb502818a110e2d55f67aae0e894f776c189b9f73556f8402a9"
|
||||
],
|
||||
"signer_types": [
|
||||
"bis",
|
||||
"hiro",
|
||||
"unisat"
|
||||
],
|
||||
"signatures": [
|
||||
"0fc66c9a7fe85ce78740fcc07f60ac47d5a05c469b2ca5f1ee16f5cc4b6eda1e41367bd67b03e7fbc6e4ba883c6fad1551373bd786f59afefbed268d08e59fd500",
|
||||
"cd63d0ffae136ca1ffe1681ec4b062ada335b002b96b2a6153cea0a1f3ed94f14b601202ac2c8ecb229168c1264d0fad3475307df5a493ad98b9fae431f5138401",
|
||||
"f7045fca2269e91d632f4a259eb47cc9f3ebb17dd64f7b8f4dfc8aa2ecfb2e716bfcce5f3c8ec6be0987c6f620d8c4205cd8d0c9728ee73c8892768ffca211c101"
|
||||
],
|
||||
"created_at": 1704970783160,
|
||||
"updated_at": 1704970783160
|
||||
},
|
||||
{
|
||||
"tx_hash": "020000000001023c99d5e25fac74e9d73d48f524e4a4772fcff9b6515d4383a5b4de1f93734f590000000000fdffffffb5c50d3e99ad5cab208c154047ae24290de2895ff68b19e8237f19ed707d02a30100000017160014df456fbaa7c5f34de88cc94494c14f0d6e83f0b2fdffffff0322020000000000002251207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba1297318999b873b000000000017a9147677a8e87a0b9fdaffcf2837bbfddd82adc7bcbd870000000000000000386a360c0000000204646573740100000000000000000000000000000000047573657205164e928c9b9f2884e66ebc9cffa24146da5c4c35450140f7b6b87eea8059209ec74c7418a59050bd0bd56cdded5cde1e684646628d9b8864803b32d6f5eec08c65887ae065f58687484ca5aad9eb5fcfdbabfa092afced02483045022100c2ea597e0b0948812dccb4cf7ab9700bf6d335d85665dce9d1d1cc729bfeaf1302205f8071e8d6c3ad136cc9543c65ff7ebc927b13955b8b462ffeb71f7eac28c1f2012102877a31bb403b5f261df23397709629e6cc2aa4b33a5d915263dd1b776f4d9d4800000000",
|
||||
"order_hash": "4576d334224e0e693377d120253ff2bcb80659b523d5e4ba9d240110cf82cd84",
|
||||
"amt": "24500000000000000000000",
|
||||
"bitcoin_tx": "0000ff3f498d61c4022daa78511e5813c26548790374795d314e030000000000000000006bf1aaef26015cdfbaab2dbfc90559d16b3323bc2faa8741457cbe9668fd145c025e9f6569d803172c5b5c1a",
|
||||
"decimals": "18",
|
||||
"from": {
|
||||
"pkscript": "5120404c01fce8c12d82f9f6b6050777bcaf0751e25d5948f0b37d45937bc9ad1430",
|
||||
"address": "bc1pgpxqrl8gcykc970kkczswaau4ur4rcjat9y0pvmagkfhhjddzscq6mdpf4"
|
||||
},
|
||||
"from_bal": "0",
|
||||
"offset": "0",
|
||||
"output": "0",
|
||||
"tick": "OXBT",
|
||||
"to": {
|
||||
"pkscript": "51207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba129731899",
|
||||
"address": "bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
},
|
||||
"to_bal": "39776330400000000000000",
|
||||
"tx_id": "08fc19fd8f6d9d51b749ab749681b73cc4f509017e93ba2e8a2057067fbe03af",
|
||||
"proof_hashes": [
|
||||
"b05924a5ebc27daf9e4c098c87cfd221be41eae11e6f1f7f7077fc8cdab920a1",
|
||||
"bd2c2e28b685e32b87df545df150fbb365ffc6f4c0212e5e91825ffc68ee3b7b",
|
||||
"cd90c2c8253afe98f9b4b508fe5de98183455dc3c2b038800b6d79392d7ff631",
|
||||
"35ccbc548dadd37c52a3e2dc5b3e3368b42138eee021b15116c4d28a738b3783",
|
||||
"3849fc4ef7251102c0455ab8f93d515f07a169bc59c5bc73adcbbbfb9bf6a4f3",
|
||||
"886d7f840b46fce7deadfe9ab284f01de2ef0aaa02d203bba79988b297aca71e",
|
||||
"b6819566d285ee1425b5228a22b8ec17866adfc997cc49fdefafd48164d9b2fe",
|
||||
"91b68bd8fcf5cf071caf70f9eb0baedd4e64fe10340bcd270292c42cf90263e1",
|
||||
"77a107cc14035c6213eb24edba266619d9d5556469702400e151b06342078a77",
|
||||
"a6caab6504b9b5211b84e09d86f000d9a76cbbd1c102c7ac1ca16910ea12ba84",
|
||||
"dc78465cee2705e0e7df2ab1552b0e397d38b73d7e72748bc15b9bcd79943dc7",
|
||||
"348aa2ad2007818206ad5ba02ace1105ff2aac38d651b987f310afad20644fb6"
|
||||
],
|
||||
"tx_index": "930",
|
||||
"tree_depth": "12",
|
||||
"height": "825229",
|
||||
"signers": [
|
||||
"SP1B0DHZV858RCBC8WG1YN5W9R491MJK88QPPC217",
|
||||
"SP3ZCGVGSQWT6TJAXZRXHCYA6SWGNSNGKHSYA1F2Q"
|
||||
],
|
||||
"signer_types": [
|
||||
"bis",
|
||||
"unisat"
|
||||
],
|
||||
"signatures": [
|
||||
"ef56767f067488b242ba87ccee3c7d4a5e8697d05589d83846ff1bf6ae69d7414703059780e04b1fa5a9cab64d80680a287f9c1d5abab71bc7970785e45d960300",
|
||||
"d0341a786a5a7417eded3afca695ac720cf755b59506a6db8ad8a3b553e1b16324707f774cc63a9d8c6da6a3c2c7a1843da1727108ed6bd5106f86791d73750e01"
|
||||
],
|
||||
"created_at": 1704970835029,
|
||||
"updated_at": 1704970835029
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="Latest balance of {tick} by {from_or_to}" %}
|
||||
{% code overflow="wrap" %}
|
||||
```sh
|
||||
curl --location --request POST 'https://api.bitcoin-oracle.network/v1/brc20' \
|
||||
--header 'x-service-type: INDEXER' \
|
||||
--header 'x-version: 0.0.1' \
|
||||
--data-raw '{
|
||||
"from_or_to": [
|
||||
"bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
],
|
||||
"tick": [
|
||||
"ORMM"
|
||||
],
|
||||
"limit": 1
|
||||
}'
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
**Response**
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"tx_hash": "0200000000010269f33e6de0c8d0fa2ad24fb7ab31e62981085c67773072cfebb30ba7e06152230000000000fdffffff14dc94d279bd19377015616ae8a0d7af7debfd4af66a49c4fc84fd1fb7d8d8350100000000fdffffff0322020000000000002251207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba129731899de28080000000000225120b87be26d45435dcf999a5614f87153ba9f12b3ad7d6f7eb89c7096ba55d94a550000000000000000386a360c00000002046465737401000000000000000000000000000000000475736572051676a3e7ab979a2926cac65cf383758c964fd42fad01402130d7dd3c3261b8ffa39397d124b4575e79fae8301fc6240811ed731db4ca3ea1fc92489e0caab3ca70ad4e249cdb3581c39d7cefda14130cd774871c02a6d701408efe9991f8fcc75cf1bcb4b2f905604716abf7f4c6b794a8224955f29dd68fa2952c0b7ac6c2559686241c32b9eaddcaefe146d0ee4e8dea5d1439e0790213b700000000",
|
||||
"order_hash": "7ed54d9d2390f2c03ebc479c7b85edf4fcba580f1172073c9102e02b8724a99f",
|
||||
"amt": "2696850000000000000000000",
|
||||
"bitcoin_tx": "00000024759a2a96f6d4c7b6169e0ec425ce216d6d06ef9e67cb030000000000000000007481d64f1c2113dedb79d8d27b9b3ae829a951aab141428042ec67c5a381bb1accb8a56569d8031718108c2f",
|
||||
"decimals": "18",
|
||||
"from": {
|
||||
"pkscript": "5120b87be26d45435dcf999a5614f87153ba9f12b3ad7d6f7eb89c7096ba55d94a55",
|
||||
"address": "bc1phpa7ym29gdwulxv62c20su2nh2039vad04hhawyuwztt54weff2suawxly"
|
||||
},
|
||||
"from_bal": "0",
|
||||
"offset": "0",
|
||||
"output": "0",
|
||||
"tick": "ORMM",
|
||||
"to": {
|
||||
"pkscript": "51207e875ae46c9f2d28d8d302cfa8c045bfc94df9277dbdf2d7a1fcdba129731899",
|
||||
"address": "bc1p06r44ervnukj3kxnqt863sz9hly5m7f80k7l94aplnd6z2tnrzvstdkzsq"
|
||||
},
|
||||
"to_bal": "613048439850300100000000000",
|
||||
"tx_id": "508358f6ddda009c3384b06485d0ab574673cf099a95e8a842d513d6e0ca9988",
|
||||
"proof_hashes": [
|
||||
"78d43aeafbf896c9c08ca81dd0123cee8fe6920ec3704ebe4bb1ab379ddc3237",
|
||||
"65beee3a9d7539ee0d4bf18ab60e37e0ac4eb8b56eb6a2a6179093d04cbd8bfa",
|
||||
"b64a594738212c1a174612558fc88dd25a0e916373c8e516874cc8aa6c7a0ac5",
|
||||
"8fa03e9cce09e81847792f1db0a99cad6a24c17879f84186cbd754959f90a6e2",
|
||||
"ab41c3f5c9126df65c4a485db493ecf1c7ed6b621469a3bb26143191e47933db",
|
||||
"ee5b3305dcdd34d89e87e051e200e8eae6808f0b2002f8ea177578f62983ec76",
|
||||
"a6985409cddec722494d07b4a6b699a9095e9ba6fe3b5c902c33bc6213043573",
|
||||
"58da9a56a684ac8b76fe1659a0f06bebae67ef17b17352c7cfa3735cf217fc04",
|
||||
"dfe3fa38798e03ec6304fd40045345ed99fecb90f6aab0e887cc44691c600ab3",
|
||||
"92249cc6082a2cf61718bd52d9f8506ad9bef28d426524455e7ffc1155e99e0d",
|
||||
"297e44492b16e57842e2691fbd9c8a1c73677102c81b368b8c10cb538215e686",
|
||||
"1d98b08c6ff58476fa9c08d56436a09242ff9c300429f5549303cc89559ee7aa"
|
||||
],
|
||||
"tx_index": "2275",
|
||||
"tree_depth": "12",
|
||||
"height": "825936",
|
||||
"signers": [
|
||||
"SP1B0DHZV858RCBC8WG1YN5W9R491MJK88QPPC217",
|
||||
"SP3ZCGVGSQWT6TJAXZRXHCYA6SWGNSNGKHSYA1F2Q"
|
||||
],
|
||||
"signer_pubkeys": [
|
||||
"02883d08893252a59cf25aafffe1417bf74a7526621665a4bc0060e4aa95405891",
|
||||
"03c1a83abd5a199cb502818a110e2d55f67aae0e894f776c189b9f73556f8402a9"
|
||||
],
|
||||
"signer_types": [
|
||||
"bis",
|
||||
"unisat"
|
||||
],
|
||||
"signatures": [
|
||||
"c6a17ad9c249f896dc3a9cc46b77c25d05516811dec70b7768e306a8a79e073932148075c2eb887248534ccfde74da2ac5186f01a847ca00195e35ec2745b98a00",
|
||||
"745f23a5993799c6309820b2c2163dbbc5e3f1f8722c643fa58ef016a7d6240540182e5e61320955109b56dec0fd8f51edf25a34686c860ed8d722807c18804601"
|
||||
],
|
||||
"created_at": 1705359837844,
|
||||
"updated_at": 1705359837844
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
|
||||
|
||||
11
developers/bitcoin-oracle/security-audits.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Security Audits
|
||||
|
||||
Bitcoin Oracle is audited by CoinFabrik.
|
||||
|
||||
* [https://cdn.alexlab.co/pdf/ALEX\_Audit\_202310\_Bitcoin\_Oracle\_and\_Bridge.pdf](https://cdn.alexlab.co/pdf/ALEX\_Audit\_202310\_Bitcoin\_Oracle\_and\_Bridge.pdf)
|
||||
|
||||
The smart contracts are also subject to our [bug bounty](https://immunefi.com/bounty/alex/) programme on Immunefi.
|
||||
39
developers/bitcoin-oracle/what-is-the-bitcoin-oracle-1.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Why Bitcoin Oracle - BRC20
|
||||
|
||||
## Bitcoin does not understand you
|
||||
|
||||
The DeFi landscape is teeming with possibilities, and at the heart of it all, Bitcoin DeFi is set to take center stage. In the coming years, we expect a surge in growth revolving around Ordinals, BRC20 tokens, Bitcoin L2 in particular Stacks.
|
||||
|
||||
A quick retrospect shows how Ordinals have brilliantly showcased the potential of the Bitcoin blockchain. This revolutionary platform has turned the table, illustrating that Bitcoin’s ledger is more than just a settlement layer.
|
||||
|
||||
The unique character of BRC20 tokens, built on a fundamentally non-fungible blockchain, sparks intrigue among many. Even though Bitcoin’s blockchain doesn’t enforce the token standard rules, and the token operation is often slow and inefficient, the allure of Bitcoin being more than just a payment system is irresistible.
|
||||
|
||||
In order to enforce the token standard rules, a number of "off-chain" indexers has, therefore, been developed and are in use to address these constraints. However, the risk of tampering with a centralized off-chain indexer cannot be ignored, and many in the field, including us, consider the establishment of an on-chain, tamper-proof, and censorship-resistant indexer to be pivotal for wider BRC20 adoption.
|
||||
|
||||
To that end, we’re collaborating with pioneers like Domo, the creator of the BRC20 standard, and the major off-chain indexers like \[BIS], OKX, Hiro and UniSat to construct an "indexer of indexers." This concept capitalizes on Stacks’ unique attributes as Bitcoin’s L2, leading the charge for decentralized consensus on BRC20 indexing.
|
||||
|
||||
## Temper-proof, censorshop-resistant, indexing
|
||||
|
||||
Bitcoin Oracle aims to provide a temper-proof, censorship-resistant, indexing of events of meta-protocols like BRC20, with Bitcoin chain as its ultimate source of truth, removing the needs to rely on a single, centralised, off-chain, indexer.
|
||||
|
||||
<figure><img src="../../.gitbook/assets/Screenshot 2023-09-30 at 10.52.53 PM.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
|
||||
|
||||
## Founded on the partnership
|
||||
|
||||
Bitcoin Oracle does not implement an on-chain version of "indexing engine" itself, which, while theoretically possible, is computationally very expensive, but rather runs a federated model that relies on a consortium of off-chain indexers to validate and submit the latest meta-protocol transactions to the on-chain smart contract written by ALEX, which keeps the validators in check by (1) implementing a consensus mechanism and (2) independently verifying that the purported Bitcoin tx is indeed mined (which only Bitcoin L2, like Stacks, can do).
|
||||
|
||||
The consensus is reached when a minimum threshold (i.e. "_m-of-n_") of pre-approved validators agree to a particular event.
|
||||
|
||||
## Combining the best of off-chain and on-chain
|
||||
|
||||
This combination of off-chain computation and on-chain verification allows the Bitcoin Oracle to scale without compromising its security as the governance around a particular meta-protocol evolves.
|
||||
|
||||
For example, the structure means disagreements over the state are easily resolved so long as they concern within the existing rules of the meta-protocol concerned, because Bitcoin network acts as the universal source of truth and all indexers do are indexing that truth according to the rules.
|
||||
|
||||
Disagreements stemming from those that are outside the current rules require update of the rules, but does not require an upgrade of the on-chain indexer, vastly simplifying the process.
|
||||
56
developers/bitcoin-oracle/what-is-the-bitcoin-oracle.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# What is the Bitcoin Oracle
|
||||
|
||||
## Cross-chain messaging and consensus layer for all and any off-chain computation engines
|
||||
|
||||
Bitcoin Oracle is a cross-chain messaging and consensus layer for all and any off-chain computation engines that builds on Bitcoin.
|
||||
|
||||
Bitcoin Oracle provides infrastructure that 
|
||||
|
||||
* allows two or more off-chain computation engines on Bitcoin to exchange messages, and
|
||||
* provides the consensus model to validate such cross-chain messages.
|
||||
|
||||
The consensus is deemed to have reached when a minimum threshold (i.e. "_m-of-n_") of the relevant community agree to a particular event.
|
||||
|
||||
End consumers can then verify the consensus before making a decision or taking an action with respect to that particular event, thus enhancing the security assumptions.
|
||||
|
||||
For example, Bitcoin Oracle secures [Xlink](what-is-the-bitcoin-oracle.md#example-xlink). When Xlink identifies a particular cross-chain transfer to process, it pulls the relevant consensus data from Bitcoin Oracle, verify them using its smart contract before processing them on the relevant destination chain.
|
||||
|
||||
## Flexible threshold-based consensus model
|
||||
|
||||
Using the "on-demand" consensus data, dapps and other end consumers of such data can reach the consensus based on a minimum threshold (i.e. "_m-of-n_") of the relevant community agree to a particular event.
|
||||
|
||||
Bitcoin Oracle provides a consensus model framework that allows the end consumer to customise their consensus model by optimising across the trust and the security budget.
|
||||
|
||||
Each end consumer may specify a number of required (i.e. trusted) and optional (i.e. non-trusted) validators as its consensus model.
|
||||
|
||||
For example, for each event to validate, the end consumer may specify that the required validators must agree and a certain threshold (say 51%) of all validators (including required and optional) must agree.
|
||||
|
||||
A fast derivation of consensus is achieved through [Threshold Sampling](what-is-the-bitcoin-oracle.md#threshold-sampling) among nodes.
|
||||
|
||||
Some may choose to have only required validators, in which case, effectively, a federated concensus model is run. In this case, a trust element is introduced to eliminate the security budget constraint. 
|
||||
|
||||
Some others may choose to have only optional validators, but with staking/slashing mechanism. In this case, the security budget enabled by the staking/slashing mechanism means the consensus model can be run trustlessly.
|
||||
|
||||
### Threshold Sampling
|
||||
|
||||
Threshold sampling allows Bitcoin Oracle to derive consensus from the network of nodes without having to download all the consensus data from its data layer. Bitcoin Oracle engages in several rounds of random sampling for subset of the network and, with each successful round, consensus confidence grows. When Bitcoin Oracle achieves a set confidence threshold, an event is deemed to have reached consensus, subject to validation by all trusted nodes.
|
||||
|
||||
## Example - XLink
|
||||
|
||||
[XLink](https://app.xlink.network) is a key component of any projects building on Bitcoin that abstracts the difference between L1 and L2 from the user experience, i.e. providing the "native-like” Bitcoin DeFi experience on L1, whereby users can use native BTC or L1 assets issued on Bitcoin to interact with L2 smart contracts.
|
||||
|
||||
XLink is bi-directional or “two-way” bridge, meaning you can freely transfer assets between Bitcoin and its L2s and vice versa.
|
||||
|
||||
XLink incorporates a mixture of required and optional validators to secure its infrastructure, where the consensus (100% threshold) of the required validators must be met to validate the consensus (51% threshold) reached by all the validators. 
|
||||
|
||||
<figure><img src="../.gitbook/assets/image (8).png" alt=""><figcaption><p>Bitcoin Oracle secures XLink</p></figcaption></figure>
|
||||
|
||||
This model brings the following benefits:
|
||||
|
||||
* It lowers the barrier to entry to join the validator network, encouraging more members of its community to participate in securing the XLink infrastructure.
|
||||
* Security budget is replaced with a set of trusted validators, which essentially acts as the secondary check against the consensus derived from the network.
|
||||
* Larger part of the incentives can be allocated to encouraging the community to join and actively participate in securing the network.
|
||||
* Smaller part of the incentives needs to be alloacted to the "insurance" fund.
|
||||
* 51% threshold and the lower barrier to entry to join the network means it is expensive for the required validators to take over the validator network.
|
||||
* Likewise, malicious actors cannot take over the validator network even if they own all optional validators (which is very unlikely) unless they also take over every required validator.
|
||||
|
||||
204
developers/developers/amm-pool-mapping.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# AMM Pool Mapping
|
||||
|
||||
Below table maps the pool listed on [https://app.alexlab.co/pool](https://app.alexlab.co/pool) to smart contracts with the relevant parameters
|
||||
|
||||
## Pool Types
|
||||
|
||||
We have three smart contracts in production that provide AMM.
|
||||
|
||||
### Trading Pool
|
||||
|
||||
[Trading Pool](../trading-lending-and-borrowing/trading-pool.md) is the latest AMM smart contract that developers should use whenever possible.
|
||||
|
||||
Trading Pool implements Generalised Mean Equation and, with a suitable parameterisation, supports both risky pairs (i.e. $$x y=L$$), stable pairs (i.e. $$x +y=L$$) and any linear combination in-between (i.e. Curve).
|
||||
|
||||
Trading Pool is parameterised with a single parameter $$t$$. $$t$$ can be between 0 and 1, with $$t=1$$ being equivalent of constant product formula (i.e. Uniswap V2) and $$t=0$$ being equivalent of constant sum formula (i.e. mStable). $$0<t <1$$ then gives a Curve-like formula.
|
||||
|
||||
#### Contract address
|
||||
|
||||
`SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.amm-swap-pool-v1-1`
|
||||
|
||||
### Fixed Weight Pool
|
||||
|
||||
Fixed Weight Pool is based on Balancer and allows to create AMM pools with custom (i.e. non equal-weight), fixed-weight, pools.
|
||||
|
||||
Fixed Weight Pool has been deprecated since the introduction of [Trading Pool](amm-pool-mapping.md#trading-pool).
|
||||
|
||||
#### Contract address
|
||||
|
||||
`SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.fixed-weight-pool-v1-01`
|
||||
|
||||
### Simple Weight Pool
|
||||
|
||||
Simple Weight Pool supports the constant product formula (i.e. $$x y=L$$).
|
||||
|
||||
Simple Weight Pool has been deprecated since the introduction of [Trading Pool](amm-pool-mapping.md#trading-pool).
|
||||
|
||||
#### Contract address
|
||||
|
||||
`SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.simple-weight-pool-alex`
|
||||
|
||||
## AMM Pools
|
||||
|
||||
### STX-xBTC-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wbtc`
|
||||
* `factor`: 1e8
|
||||
|
||||
### STX-sUSDT-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-susdt`
|
||||
* `factor`: 1e8
|
||||
|
||||
### STX-ALEX-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `factor`: 1e8
|
||||
|
||||
### ALEX-ATALEXV2-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.auto-alex-v2`
|
||||
* `factor`: 1e8
|
||||
|
||||
### ALEX-DIKO-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wdiko`
|
||||
* `factor`: 1e8
|
||||
|
||||
### STX-VIBES-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wvibes`
|
||||
* `factor`: 1e8
|
||||
|
||||
### STX-ALEX-50-50
|
||||
|
||||
**Smart Contract**: [Fixed Weight Pool](amm-pool-mapping.md#fixed-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `weight-x`: 0.5e8
|
||||
* `weight-y`: 0.5e8
|
||||
|
||||
### STX-xBTC-50-50
|
||||
|
||||
**Smart Contract**: [Fixed Weight Pool](amm-pool-mapping.md#fixed-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wbtc`
|
||||
* `weight-x`: 0.5e8
|
||||
* `weight-y`: 0.5e8
|
||||
|
||||
### STX-xUSD-50-50
|
||||
|
||||
**Smart Contract**: [Fixed Weight Pool](amm-pool-mapping.md#fixed-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wxusd`
|
||||
* `weight-x`: 0.5e8
|
||||
* `weight-y`: 0.5e8
|
||||
|
||||
### xUSD-USDA-0.005
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wxusd`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wusda`
|
||||
* `factor`: 0.005e8
|
||||
|
||||
### ALEX-USDA-50-50
|
||||
|
||||
**Smart Contract**: [Simple Weight Pool](amm-pool-mapping.md#simple-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wusda`
|
||||
|
||||
### STX-CORGI-1
|
||||
|
||||
**Smart Contract**: [Trading Pool](amm-pool-mapping.md#trading-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wcorgi`
|
||||
* `factor`: 1e8
|
||||
|
||||
### STX-MIA-50-50
|
||||
|
||||
**Smart Contract**: [Fixed Weight Pool](amm-pool-mapping.md#fixed-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wmia`
|
||||
* `weight-x`: 0.5e8
|
||||
* `weight-y`: 0.5e8
|
||||
|
||||
### STX-NYCC-50-50
|
||||
|
||||
**Smart Contract**: [Fixed Weight Pool](amm-pool-mapping.md#fixed-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wnycc`
|
||||
* `weight-x`: 0.5e8
|
||||
* `weight-y`: 0.5e8
|
||||
|
||||
### ALEX-BANABA-50-50
|
||||
|
||||
**Smart Contract**: [Simple Weight Pool](amm-pool-mapping.md#simple-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wban`
|
||||
|
||||
### ALEX-SLIME-50-50
|
||||
|
||||
**Smart Contract**: [Simple Weight Pool](amm-pool-mapping.md#simple-weight-pool)
|
||||
|
||||
#### Parameters
|
||||
|
||||
* `token-x`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token`
|
||||
* `token-y`: `SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wslm`
|
||||
|
||||
123
developers/developers/api-references.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# REST API
|
||||
|
||||
Front-end developers may use our REST API ([https://api.alexgo.io](https://api.alexgo.io)) to access the latest market data on ALEX.
|
||||
|
||||
## Pool
|
||||
|
||||
---
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/allswaps" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/pool_stats/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/pool_volume/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/volume_24h/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/volume_7d/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/pool_liquidity/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/liquidity/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/fee/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
## Stats
|
||||
|
||||
---
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/stats/tvl" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/stats/tvl/{token}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/stats/total_supply/{token}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
## Price
|
||||
|
||||
---
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/price/{token}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/pool_token_price/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/pool_token_stats" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/price_history/{token}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
## DEX
|
||||
|
||||
---
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/pairs" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/tickers" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/ticker/{ticker_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/orderbook/{ticker}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/historical_swaps/{pool_token_id}" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
## Coin-gecko
|
||||
|
||||
---
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v2/coin-gecko/pairs" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v2/coin-gecko/tickers" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
## Public
|
||||
|
||||
---
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/public/pairs" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://api.alexgo.io/swagger-ui-yaml" path="/v1/public/amm-pool-stats" method="get" %}
|
||||
[https://api.alexgo.io/swagger-ui-yaml](https://api.alexgo.io/swagger-ui-yaml)
|
||||
{% endswagger %}
|
||||
6
developers/developers/networks/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
description: Stacks networks environments and deployed addresses
|
||||
---
|
||||
|
||||
* [Mainnet](mainnet.md)
|
||||
* [Testnet](testnet.md)
|
||||
19
developers/developers/networks/mainnet.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Smart Contracts
|
||||
|
||||
## Deployed Protocol Contracts
|
||||
|
||||
<table><thead><tr><th width="167">Contract</th><th>Address</th></tr></thead><tbody><tr><td>DAO</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.executor-dao</code></td></tr><tr><td>Vault</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-vault</code></td></tr><tr><td>Reserve Pool</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-reserve-pool</code></td></tr><tr><td>Launchpad</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-launchpad-v1-1</code></td></tr><tr><td>Lottery</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-lottery</code></td></tr><tr><td>Trading Pool</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.amm-swap-pool-v1-1</code></td></tr><tr><td>Fixed Weight Pool<td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.fixed-weight-pool-v1-01</code></td></tr><tr><td>Simple Weight Pool</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.simple-weight-pool-alex</code></td></tr><tr><td>Swap Router</td><td>(to route between Fixed Weight Pool and Simple Weight Pool)<br><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.swap-helper-v1-03</code></td></tr><tr><td>Swap Bridge </td><td>(to route between Trading Pool and Fixed Weight Pool / Simple Weight Pool)<br><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.swap-helper-bridged</code></td></tr><tr><td>ALEX Token</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token</code></td></tr><tr><td>autoALEX Token</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.auto-alex</code></td></tr><tr><td>Bridge Endpoint</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.bridge-endpoint-v1-01</code></td></tr><tr><td>sUSDT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-susdt</code></td></tr></tbody></table>
|
||||
|
||||
## Token List
|
||||
|
||||
Where applicable, ALEX uses "wrapped" token to ensure certain functionalities (mainly the support for the fixed notation) are added to the native, 3rd-party, tokens.
|
||||
|
||||
These "wrapped" tokens do not hold any native tokens, but are "pass-throughs". They call the relevant functions of the native tokens (e.g. `transfer`) to complete the user requests, but ensure these are done in a consistent manner across all tokens handled by ALEX.
|
||||
|
||||
<table><thead><tr><th width="154">Token</th><th>Address</th></tr></thead><tbody><tr><td>STX</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2</code></td></tr><tr><td>ALEX</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-alex</code></td></tr><tr><td>xBTC</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wxbtc</code></td></tr><tr><td>sUSDT</td><td><code>SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-susdt</code></td></tr><tr><td>xUSD</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wxusd</code></td></tr><tr><td>autoALEX</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.auto-alex-v3</code></td></tr><tr><td>USDA</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wusda</code></td></tr><tr><td>DIKO</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wdiko</code></td></tr><tr><td>MIA</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wmia</code></td></tr><tr><td>NYC</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wnyc</code></td></tr><tr><td>BANANA</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wban</code></td></tr><tr><td>SLIME</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wslm</code></td></tr><tr><td>WELSH</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wcorgi</code></td></tr><tr><td>VIBES</td><td><code>SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wvibes</code></td></tr></tbody></table>
|
||||
|
||||
### BRC20 Tokens
|
||||
|
||||
BRC20 tokens on ALEX represent those BRC20 tokens that are pegged in from Bitcoin.
|
||||
|
||||
<table><thead><tr><th width="161">Token</th><th>Address</th></tr></thead><tbody><tr><td>$B20</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-db20</code></td></tr><tr><td>MAXI</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-maxi</code></td></tr><tr><td>SHNT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-shnt</code></td></tr><tr><td>PIZA</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-piza</code></td></tr><tr><td>LONG</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-long</code></td></tr><tr><td>INSC</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-insc</code></td></tr><tr><td>MAJO</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-majo</code></td></tr><tr><td>DEXM</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-dexm</code></td></tr><tr><td>ATMT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-aiptp</code></td></tr><tr><td>CVLT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-cvlt</code></td></tr><tr><td>LBOW</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-lbow</code></td></tr><tr><td>SBTC</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-sbtc</code></td></tr><tr><td>OXBT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-oxbt</code></td></tr><tr><td>₿</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-spacesignb</code></td></tr><tr><td>ORDS</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-ords</code></td></tr><tr><td>NYTO</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-nyto</code></td></tr><tr><td>BENG</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-beng</code></td></tr><tr><td>TRAC</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-trac</code></td></tr><tr><td>SATS</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-sats</code></td></tr><tr><td>TARO</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-taro</code></td></tr><tr><td>10MM</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-10mm</code></td></tr><tr><td>PEPE</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-pepe</code></td></tr><tr><td>VMPX</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-vmpx</code></td></tr><tr><td>@LFG</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-atlfg</code></td></tr><tr><td>ORDI</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-ordi</code></td></tr><tr><td>$BIT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-dbit</code></td></tr><tr><td>MXRC</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-mxrc</code></td></tr><tr><td>IGLI</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-igli</code></td></tr><tr><td>OHMS</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-ohms</code></td></tr><tr><td>JAKE</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-jake</code></td></tr><tr><td>MEME</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-meme</code></td></tr><tr><td>NALS</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-nals</code></td></tr><tr><td>XING</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-xing</code></td></tr><tr><td>BANK</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-bank</code></td></tr><tr><td>PASS</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-pass</code></td></tr><tr><td>WZRD</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-wzrd</code></td></tr><tr><td>MOON</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-moon</code></td></tr><tr><td>DRAC</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-drac</code></td></tr><tr><td>LOVE</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-love</code></td></tr><tr><td>ZBIT</td><td><code>SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.brc20-zbit</code></td></tr></tbody></table>
|
||||
16
developers/developers/networks/testnet.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Testnet
|
||||
|
||||
We use our own testnet whose API node is hosted at [https://stacks-node-api.testnet.alexlab.co/](https://stacks-node-api.testnet.alexlab.co/), with a few useful modifications (such as [puppet mode controller](http://127.0.0.1:5000/s/sPu0USrFZJvbjvTbkBTh/)) to the stock testnet deployment.
|
||||
|
||||
You can explore the state of the testnet at [https://explorer.testnet.alexlab.co/?chain=mainnet](https://explorer.testnet.alexlab.co/?chain=mainnet).
|
||||
|
||||
Developers generally would interact directly with our contracts deployed on the testnet through the API node above, but we also make available [https://app.testnet.alexlab.co/](https://app.testnet.alexlab.co/) for those who would like to interact from a browser.
|
||||
|
||||
Please note the testnet may be reset from time to time for maintenance and other purposes. We try to minimise the frequency of these resets, but it can and does happen, so please do bear that in mind when interacting with our testnet.
|
||||
|
||||
For any questions / follow-ups, please use our Discord channel ([https://discord.gg/alexlab](https://discord.gg/alexlab)).
|
||||
|
||||
## Smart Contracts
|
||||
|
||||
<table><thead><tr><th width="167">Contract</th><th>Address</th></tr></thead><tbody><tr><td>Vault</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.alex-vault</code></td></tr><tr><td>Reserve Pool</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.alex-reserve-pool</code></td></tr><tr><td>Fixed Weight Pool</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.fixed-weight-pool-v1-02</code></td></tr><tr><td>Simple Weight Pool</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.simple-weight-pool-alex</code></td></tr><tr><td>Swap Helper</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.swap-helper-v1-03</code></td></tr><tr><td>ALEX Token</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.age000-governance-token</code></td></tr><tr><td>autoALEX Token</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.auto-alex</code></td></tr><tr><td>STX (wrapped)</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.token-wstx</code></td></tr><tr><td>xBTC</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.token-wbtc</code></td></tr><tr><td>xUSD</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.token-wxusd</code></td></tr><tr><td>USDA</td><td><code>ST29E61D211DD0HB0S0JSKZ05X0DSAJS5G5QSTXDX.token-wusda</code></td></tr></tbody></table>
|
||||
|
||||
94
developers/developers/protocol-contracts/README.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
description: ALEX DAO - Comprehensive Technical Design Overview
|
||||
---
|
||||
|
||||
This document provides a detailed overview of the smart contracts that enable ALEX DeFi operations. We categorize these contracts based on their functionalities, explain their interactions, and describe some common technical aspects.
|
||||
|
||||
## AMM Trading Pool
|
||||
|
||||
This section provides an overview of the ALEX on-chain Trading Pool and its Automated Market Making (AMM) protocol.
|
||||
|
||||

|
||||
|
||||
### Pool: amm-pool-v2-01.clar
|
||||
|
||||
This is the primary contract in ALEX's AMM Trading Pool system. It encompasses several core operations, including pool creation, liquidity operations, LP token management, and token swapping. This contract is complemented by the two auxiliary contracts listed below.
|
||||
|
||||
[Complete technical documentation](./amm-pool-v2-01.clar.md)
|
||||
|
||||
### Registry: amm-registry-v2-01.clar
|
||||
|
||||
This contract functions as a persistence module for all pool-related information needed by the ALEX Automated Market Maker (AMM) Trading Pool system. It also manages a list of blocklisted operators.
|
||||
|
||||
[Complete technical documentation](./amm-registry-v2-01.clar.md)
|
||||
|
||||
## Vault
|
||||
|
||||
The Vault component of the ALEX platform is distinct from the Trading Pool components by design. This separation offers numerous advantages, such as reduced transaction costs for users and a faster learning curve for developers who are creating custom pools on ALEX.
|
||||
|
||||
### Vault: amm-vault-v2-01.clar
|
||||
|
||||
The Vault contract supports the primary contract `amm-pool-v2-01.clar` in position and swap operations by keeping records of the reserves accumulated from fees and securing pool assets. This contract also offers a flash-loan feature for registered tokens, available to approved users.
|
||||
|
||||
[Complete technical documentation](./amm-vault-v2-01.clar.md)
|
||||
|
||||
## Farming Campaign: farming-campaign-v2-02.clar
|
||||
|
||||
This contract manages the ALEX Surge liquidity incentive program, overseeing pool registration, voting, staking, and reward distribution. It determines how $ALEX rewards are allocated based on user votes and supports additional voter incentives.
|
||||
|
||||
[Complete technical documentation](./farming-campaign-v2-02.clar.md)
|
||||
|
||||
## Common features
|
||||
|
||||
### Governance
|
||||
|
||||
The smart contracts discussed in this section include features to control administrative privileges, access, and operational status. It is needed to duplicate some functions for them to be available on each contract.
|
||||
|
||||
#### Admin access control
|
||||
|
||||
Contracts in the ALEX platform may include a feature that checks administrative access through the function `is-dao-or-extension`. This function ensures that the caller (`tx-sender`) is either the DAO executor or an authorized extension.
|
||||
|
||||
#### Operational status
|
||||
|
||||
The `amm-pool-v2-01` and `amm-vault-v2-01` contracts have functionalities to set and query the operational status of the contract. Specifically, these contracts include a `paused` flag. When this flag is set to true, all operations within the contract are halted.
|
||||
|
||||
#### Blocklisted operators
|
||||
|
||||
The `amm-registry-v2-01` contract features the ability to update (on admin operator request) and query a list of blacklisted addresses that are prohibited from operating within the trading pool. The `amm-pool-v2-01` contract delegates the task of this verification to the Registry, which performs a check against the `tx-sender`.
|
||||
|
||||
### Traits
|
||||
|
||||
In Clarity language, a trait defines a public interface to which smart contracts can conform. All Trading Pool contracts in this documentation import traits to ensure interface conformity for various types (such as tokens and flash-loan users) and to conduct their transactions safely. These traits are customized versions of standard traits which are provided by the ALEX platform to serve specific purposes. Below is a list of all the traits utilized by the Trading Pool contracts.
|
||||
|
||||
#### sip-010-trait
|
||||
|
||||
This is a customized version of the Stacks' Standard Trait Definition for Fungible Tokens and is used by contracts in the ALEX platform. The changes in this version include support for 8-digit fixed notation and additional helper functions for `transfer`, `get-balance`, and `get-total-supply`. Mint and burn functions are also included along with their respective helpers.
|
||||
|
||||
[ALEX sip-010 customized implementation](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/traits/trait-sip-010.clar) |
|
||||
[Full sip-010 standard](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md)
|
||||
|
||||
#### semi-fungible-trait
|
||||
|
||||
This is a customized version of the Stacks' Standard Trait Definition for Semi-Fungible Tokens and is used only by the Vault contract.
|
||||
The customizations are similar to those in the customized `sip-010-trait`, with additional fixed notation helpers for the `transfer-memo`, `get-overall-balance`, and `get-overall-supply` functions. Additionally, the `get-token-uri` function is customized to redefine the `response` parameter type to the tuple: `(optional (string-utf8 256)) uint` instead of sip-013's `string-ascii`.
|
||||
|
||||
[ALEX sip-013 customized implementation](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/traits/trait-semi-fungible.clar) |
|
||||
[Full sip-013 standard](https://github.com/stacksgov/sips/blob/main/sips/sip-013/sip-013-semi-fungible-token-standard.md)
|
||||
|
||||
#### flash-loan-user-trait
|
||||
|
||||
This is a custom trait from ALEX designed to support flash-loan operations and is used only by the Vault contract. The trait defines an `execute` function, which is asserted in the Vault's `flash-loan` function signature, allowing the flash-loan user to execute their logic with the loaned amount.
|
||||
|
||||
[ALEX flash-loan customized implementation](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/traits/trait-flash-loan-user.clar)
|
||||
|
||||
### Mathematics helpers
|
||||
|
||||
The Pool and Vault contracts are equipped with helper functions that facilitate various mathematical operations (e.g., amounts, percentages) with the necessary precision. These helpers improve the expressiveness of the contracts' logic. Some of these helper functions utilize mathematical constants defined within each contract. All helper functions are declared as private and, like the governance functions, may be replicated across both contracts using the same equations.
|
||||
|
||||
|Topic|Functions|
|
||||
|--|--|
|
||||
|Precision multipliers and divisors|`mul-down`, `mul-up`, `div-down`, `div-up`|
|
||||
|Rolling summation|`rolling_sum_div`, `rolling_div_sum`|
|
||||
|Accumulate|`accumulate_division`, `accumulate_product`|
|
||||
|Power and exponential|`pow-fixed`, `pow-priv`, `pow-down`, `pow-up`, `exp-fixed`, `exp-pos`|
|
||||
|Logarithmic|`log-fixed`, `ln-fixed`, `ln-priv`|
|
||||
275
developers/developers/protocol-contracts/amm-pool-v2-01.clar.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Pool
|
||||
|
||||
#### Location: [`alex-dao-2/contracts/extensions/amm-pool-v2-01.clar`](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/extensions/amm-pool-v2-01.clar)
|
||||
|
||||
This document provides comprehensive technical documentation for the primary contract in ALEX's AMM Trading Pool system. The contract encompasses several core operations, including pool creation, liquidity operations (adding or removing assets), LP token management (minting and burning tokens that represent a user's share of the pool and potential earnings), and token swapping (facilitating the exchange of tokens within an existing and funded pool while charging a corresponding fee). This contract is complemented by two auxiliary contracts: a REGISTRY contract that handles the persistence of pool information, and a VAULT contract that secures the assets and manages the reserves accumulated from the fees. For detailed information about these auxiliary contracts, please refer to their respective technical documentation: [amm-registry-v2-01.clar](amm-registry-v2-01.clar.md) and [amm-vault-v2-01.clar](amm-vault-v2-01.clar.md).
|
||||
|
||||
## Storage
|
||||
|
||||
### Variables: (data-var)
|
||||
|
||||
* `paused` (bool) This data variable acts as a flag to determine and control the operational status of the contract within the system. When set to 'paused,' it will block all position and swap transactions.
|
||||
|
||||
### Constants
|
||||
|
||||
* `x_a_list_no_deci`
|
||||
* `x_a_list`
|
||||
|
||||
#### Mathematical constants
|
||||
|
||||
These symbolic constants are employed to define and restrict decimal precision and boundary limits in calculations within the system.
|
||||
|
||||
* `ONE_8`
|
||||
* `UNSIGNED_ONE_8`
|
||||
* `MAX_NATURAL_EXPONENT`
|
||||
* `MIN_NATURAL_EXPONENT`
|
||||
* `MILD_EXPONENT_BOUND`
|
||||
* `MAX_POW_RELATIVE_ERROR`
|
||||
|
||||
## Contract calls (interactions)
|
||||
|
||||
* `executor-dao` Calls are made to verify whether a certain contract-caller is designated as an extension.
|
||||
* `amm-registry-v2-01` This contract is called to manage and configure the data and settings of AMM pools. In this document, it is referred to as the 'registry'.
|
||||
* `amm-vault-v2-01` This contract is called to execute token transfers during the reduction of positions and swapping operations. Additionally, calls are made to add fees charged to the reserves.
|
||||
* `token-amm-pool-v2-01` In operations to add or reduce positions, interactions with this contract involve minting and burning of LP (Liquidity Provider) Tokens and retrieving their balance amounts. In this document, it is referred to as the 'LP Token'.
|
||||
* Tokens (`token-x-trait`, `token-y-trait`, `token-z-trait`, etc.) During the process of adding positions and executing swaps, a trait is used to invoke the relevant tokens to perform the necessary transfers involved in the transaction. This trait is a customized version of the Stacks' standard definition for Fungible Tokens (`sip-010`), with support for 8-digit fixed notation.
|
||||
|
||||
## Features
|
||||
|
||||
### POOL features
|
||||
|
||||
1. `create-pool` This function establishes a liquidity pool for a specified token pair (token-x/token-y). It starts by verifying that the `tx-sender` is not blacklisted through the [`is-blocklisted-or-default` function](amm-pool-v2-01.clar.md#governance-features). Following this validation, the function delegates the pool creation task to the registry. The pools are uniquely identified by their `token-x`, `token-y`, and `factor` values. Upon successful creation, the function automatically invokes `add-to-position` function to initialize token positions for the specified pair within the new pool.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(factor uint)
|
||||
(pool-owner principal)
|
||||
(dx uint)
|
||||
(dy uint)
|
||||
```
|
||||
|
||||
2. `add-to-position` The `add-to-position` function adds asset positions to an existing liquidity pool by transferring the respective tokens from the `tx-sender` to the system vault contract. It updates the pool details in the registry contract and mints LP tokens to the sender, representing their share of the pool and potential earnings. This minting operation is tracked using a unique pool identifier (POOL\_ID).\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(factor uint)
|
||||
(dx uint)
|
||||
(max-dy (optional uint))
|
||||
```
|
||||
|
||||
3. `reduce-position` This function performs the inverse operation of `add-to-position` by allowing users to withdraw asset positions from an existing token pair pool. Upon meeting all requirements (such as the operational status of the pool contract, a valid percentage, and sufficient liquidity pool supply), the function transfers the calculated amount from the vault to the sender and burns the corresponding LP tokens. Note that this function cannot be invoked by blacklisted senders.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(factor uint)
|
||||
(percent uint)
|
||||
```
|
||||
|
||||
4. **Swap tokens functions**: The swap tokens functions enable token exchanges between two given tokens within the liquidity pool. For a swap to successfully execute, the pool contract must contain sufficient liquidity for the specified token pair. The basic steps are: a. transferring a specified amount of token-x from the sender to the system vault b. transferring a calculated amount of token-y from the system vault to the sender while considering swap fees and expected minimum amounts c. registering the fee in token-x within the vault d. updating the pool registry's liquidity status\
|
||||
\
|
||||
These steps are mirrored for swaps involving the reverse token pair (token-y/token-x).\
|
||||
\
|
||||
If no direct pool exists for the desired pair, the contract provides helper functions to facilitate multi-hop swaps using intermediate token pools. This process, also known as multi-step swap, allows the exchange via a route like token-x/intermediate-token and intermediate-token/token-y. Note that this feature requires prior knowledge of the intermediary pools to connect the desired pair in the swap.\
|
||||
\
|
||||
The current protocol version supports up to 4-pools-route operations which are implemented in the following functions:
|
||||
|
||||
* `swap-helper` Swaps a given token-x for a required token-y. 1 pool route: token-x/token-y.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(factor uint)
|
||||
(dx uint)
|
||||
(min-dy (optional uint))
|
||||
```
|
||||
|
||||
* `swap-helper-a` Swaps a given token-x for a required token-z. 2 pools route: token-x/token-y - token-y/token-z.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(token-z-trait <ft-trait>)
|
||||
(factor-x uint)
|
||||
(factor-y uint)
|
||||
(dx uint)
|
||||
(min-dz (optional uint))
|
||||
```
|
||||
|
||||
* `swap-helper-b` Swaps a given token-x for a required token-w. 3 pools route: token-x/token-y - token-y/token-z - token-z/token-w.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(token-z-trait <ft-trait>)
|
||||
(token-w-trait <ft-trait>)
|
||||
(factor-x uint)
|
||||
(factor-y uint)
|
||||
(factor-z uint)
|
||||
(dx uint)
|
||||
(min-dw (optional uint))
|
||||
```
|
||||
|
||||
* `swap-helper-c` Swaps a given token-x for a required token-v. 4 pools route: token-x/token-y - token-y/token-z - token-z/token-w - token-w/token-v.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(token-z-trait <ft-trait>)
|
||||
(token-w-trait <ft-trait>)
|
||||
(token-v-trait <ft-trait>)
|
||||
(factor-x uint)
|
||||
(factor-y uint)
|
||||
(factor-z uint)
|
||||
(factor-w uint)
|
||||
(dx uint)
|
||||
(min-dv (optional uint))
|
||||
```
|
||||
|
||||
**Note**: all these helpers use the swap supporting functions `swap-x-for-y` and `swap-y-for-x`.
|
||||
|
||||
### Supporting features
|
||||
|
||||
The following functions are tools to assist the off-chain activities.
|
||||
|
||||
1. Fee helpers (`fee-helper`, `fee-helper-a`, `fee-helper-b`, `fee-helper-c`) These functions retrieve current fees for an existing pool based on the specified tokens and factors.
|
||||
2. Rate helpers (`get-helper`, `get-helper-a`, `get-helper-b`, `get-helper-c`) These functions retrieve exchange rates for a given amount in an existing pool based on the specified tokens and factors.
|
||||
|
||||
**Note**: The above functions, along with their variations, support intermediary routes similar to those in the swapping functions (e.g., token-x/token-y, token-x/token-y-token-y/token-z, etc.).
|
||||
|
||||
### Governance features
|
||||
|
||||
1. `is-dao-or-extension` This standard protocol function checks whether a caller (`tx-sender`) is the DAO executor or an authorized extension, delegating the extensions check to the `executor-dao` contract.\
|
||||
**Input**: None.
|
||||
2. `is-blocklisted-or-default` A read-only feature that verifies if a given address is blacklisted in the registry contract.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(sender principal)
|
||||
```
|
||||
|
||||
3. `is-paused` A read-only function that checks the operational status of the contract.\
|
||||
**Input**: None.
|
||||
4. `pause` A public function, governed through the `is-dao-or-extension`, that can change the contract's operational status.\
|
||||
**Input**:
|
||||
|
||||
```lisp
|
||||
(new-paused bool)
|
||||
```
|
||||
|
||||
### Getter and Setter functions
|
||||
|
||||
All getter and setter functions in the contract handle pool information, delegating their retrieval or update operations to the corresponding functions in the registry contract [amm-registry-v2-01.clar](amm-registry-v2-01.clar.md).
|
||||
|
||||
#### Setters
|
||||
|
||||
The following is the complete list of setter functions for pool configurations. All set configuration functions are restricted to the respective pool owner or ALEX admin operators (see function `is-dao-or-extension`).
|
||||
|
||||
* `set-fee-rate-x` and `set-fee-rate-y`: set the swap fee (% of swap amount) of `token-x` and `token-y`, respectively. Both `fee-rate-x` and `fee-rate-y` are zero by default.
|
||||
|
||||
* `set-start-block` and `set-end-block`: set the block heights before and after, respectively, which the pool is not available. Both `start-block` and `end-block` is set to `u340282366920938463463374607431768211455` by default.
|
||||
|
||||
* `set-threshold-x` and `set-threshold-y`: set the amount of `token-x` and `token-y`, respectively, below which a minimum % slippage is applied. Both `threshold-x` and `threshold-y` are zero by default.
|
||||
|
||||
* `set-max-in-ratio` and `set-max-out-ratio`: set the maximum ratio values used to calculate the highest amount that can be deposited (IN) or exchanged (OUT) within the pool.
|
||||
|
||||
* `set-oracle-enabled`: add or remove the pool from the on-chain price oracle. Oracle is disabled by default.
|
||||
|
||||
* `set-oracle-average`: set the exponential moving average factor for the `oracle-resilient`. Please note this call will reset the existing `oracle-resilient` value. The `oracle-average` is zero by default. We recommend `0.99e8`.
|
||||
|
||||
#### Getters
|
||||
|
||||
**Main getters**
|
||||
|
||||
* `get-invariant` (consumes the preceding registry's `get-switch-threshold`)
|
||||
* `get-max-ratio-limit`
|
||||
* `get-pool-details`
|
||||
* `get-pool-details-by-id`
|
||||
* `get-pool-exists`
|
||||
* `get-switch-threshold`
|
||||
|
||||
**Pool configuration getter functions (query the registry via the aforementioned `get-pool-details` function)**
|
||||
|
||||
* `check-pool-status`
|
||||
* `get-balances`
|
||||
* `get-start-block`
|
||||
* `get-end-block`
|
||||
* `get-fee-rate-x`
|
||||
* `get-fee-rate-y`
|
||||
* `get-fee-rebate`
|
||||
* `get-max-in-ratio`
|
||||
* `get-max-out-ratio`
|
||||
* `get-oracle-average`
|
||||
* `get-oracle-enabled`
|
||||
* `get-oracle-resilient`
|
||||
* `get-oracle-instant`
|
||||
* `get-pool-owner`
|
||||
* `get-price`
|
||||
* `get-threshold-x`
|
||||
* `get-threshold-y`
|
||||
|
||||
**Pool token information getter functions (query the registry via the aforementioned `get-pool-details` function)**
|
||||
|
||||
* `get-x-given-price`
|
||||
* `get-y-given-price`
|
||||
* `get-y-given-x`
|
||||
* `get-x-given-y`
|
||||
* `get-y-in-given-x-out`
|
||||
* `get-x-in-given-y-out`
|
||||
* `get-position-given-mint`
|
||||
* `get-position-given-burn`
|
||||
* `get-token-given-position`
|
||||
|
||||
#### Internal helper functions
|
||||
|
||||
**Token helpers**
|
||||
|
||||
These helper functions facilitate the retrieval of specific token data using another known data as input:
|
||||
|
||||
* `get-x-given-price-internal`
|
||||
* `get-y-given-price-internal`
|
||||
* `get-y-given-x-internal`
|
||||
* `get-x-given-y-internal`
|
||||
* `get-y-in-given-x-out-internal`
|
||||
* `get-x-in-given-y-out-internal`
|
||||
* `get-position-given-burn-internal`
|
||||
* `get-position-given-mint-internal`
|
||||
* `get-price-internal`
|
||||
* `get-token-given-position-internal`
|
||||
|
||||
**Mathematical helpers**
|
||||
|
||||
These helper functions aid in various calculations within the context of
|
||||
the contract, such as amounts, percentages, etc. Some of these functions rely on predefined constants, as specified in [mathematical constants](amm-pool-v2-01.clar.md#mathematical-constants): `accumulate_division`, `accumulate_product`, `div-down`, `div-up`, `exp-fixed`, `exp-pos`, `ln-fixed`, `ln-priv`, `log-fixed`, `mul-down`, `mul-up`, `pow-down`, `pow-fixed`, `pow-priv`, `pow-up`, `rolling_div_sum`, `rolling_sum_div`.
|
||||
|
||||
|
||||
## Errors defined in the contract
|
||||
|
||||
* `ERR-BLOCKLISTED`
|
||||
* `ERR-EXCEEDS-MAX-SLIPPAGE`
|
||||
* `ERR-INVALID-EXPONENT`
|
||||
* `ERR-INVALID-LIQUIDITY`
|
||||
* `ERR-INVALID-POOL`
|
||||
* `ERR-MAX-IN-RATIO`
|
||||
* `ERR-MAX-OUT-RATIO`
|
||||
* `ERR-NO-LIQUIDITY`
|
||||
* `ERR-NOT-AUTHORIZED`
|
||||
* `ERR-ORACLE-AVERAGE-BIGGER-THAN-ONE`
|
||||
* `ERR-ORACLE-NOT-ENABLED`
|
||||
* `ERR-OUT-OF-BOUNDS`
|
||||
* `ERR-PAUSED`
|
||||
* `ERR-PERCENT-GREATER-THAN-ONE`
|
||||
* `ERR-POOL-ALREADY-EXISTS`
|
||||
* `ERR-PRODUCT-OUT-OF-BOUNDS`
|
||||
* `ERR-SWITCH-THRESHOLD-BIGGER-THAN-ONE`
|
||||
* `ERR-X-OUT-OF-BOUNDS`
|
||||
* `ERR-Y-OUT-OF-BOUNDS`
|
||||
309
developers/developers/protocol-contracts/amm-pool-v3.clar.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# amm-pool-v3.clar
|
||||
|
||||
- Location: `./contracts/amm-pool-v3.clar`
|
||||
|
||||
<!-- - [Deployed contract]() -->
|
||||
|
||||
The `amm-pool-v3` contract implements the core logic of DAMM (Discrete Automated Market Maker), a concentrated liquidity protocol designed to maximize capital efficiency by organizing liquidity into discrete price ranges called **bins** or **ticks**.
|
||||
|
||||
Unlike traditional AMMs that spread liquidity across the entire price curve, DAMM allows liquidity providers (LPs) to allocate funds into specific price intervals. Each price bin behaves as an independent constant product pool, with a custom virtual balance system to keep swaps bounded within the configured range.
|
||||
|
||||
This contract supports the full lifecycle of DAMM pools:
|
||||
- **Pool Creation** – DAO-controlled creation of new pools between two fungible tokens, specifying bin size and fee configuration.
|
||||
- **Liquidity Provision** – LPs add liquidity to specific ticks within a pool, receiving fungible LP tokens for each tick.
|
||||
- **Liquidity Management** – LPs can reduce their positions by percentage, claiming back their share of assets and accrued fees from a specific tick.
|
||||
- **Swapping** – Supports swaps of token X for token Y (and vice versa) within a tick.
|
||||
- **Administrative Control** – The ALEX DAO can pause or sunset pools and adjust fee parameters at any time.
|
||||
- **Fee Claiming** – Accumulated fees can be withdrawn by the DAO to a target address.
|
||||
|
||||
## Features
|
||||
|
||||
### Public
|
||||
|
||||
#### `add-to-position`
|
||||
|
||||
This function allows a user to add liquidity to a specific price bin (tick) within a DAMM pool. Unlike traditional AMMs where liquidity is distributed evenly across all prices, here the user targets a defined price range. The `min-price` and `max-price` parameters act as a safety check, even if the user selects a bin, they might not want to enter at just any price inside that range. These bounds let users specify a narrower range of acceptable prices for their deposit. If the actual price (after adding liquidity) falls outside of this min-max window, the transaction will revert to protect the user from entering at an unfavorable rate. The function accepts a max amount of both tokens (`dx`, `dy`) and bounds on the acceptable price range (`min-price`, `max-price`).
|
||||
|
||||
It internally calculates the actual amounts of each token that can be added given the pool's current balances and fee configuration. If the price after the addition falls outside the user-defined bounds, the transaction reverts.
|
||||
|
||||
If this is the first liquidity added to the tick, it sets the virtual balances and initializes the price bin. Otherwise, it uses the existing balances to calculate a fair proportional LP minting.
|
||||
|
||||
This function interacts with the `amm-liquidity-token-v3` contract to mint LP tokens for the position, and with the respective SIP-010 token contracts to transfer the user's tokens into the pool. All funds are held directly by the `amm-pool-v3 contract`, there is no external vault.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|-----------------|--------------|
|
||||
| `token-x-trait` | `<ft-trait>` |
|
||||
| `token-y-trait` | `<ft-trait>` |
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
| `dx` | `uint` |
|
||||
| `dy` | `uint` |
|
||||
| `min-price` | `uint` |
|
||||
| `max-price` | `uint` |
|
||||
|
||||
|
||||
#### `reduce-position`
|
||||
|
||||
This function allows a user to reduce their liquidity position in a specific tick of a DAMM pool by a given percentage. Internally, it calculates the user's LP token balance for the selected bin, burns the requested portion, and sends back the proportional share of token X and token Y to the user.
|
||||
|
||||
The function interacts with the `amm-liquidity-token-v3` contract to burn LP tokens, and with the respective SIP-010 token contracts to transfer assets back to the user. All liquidity is held directly by the `amm-pool-v3` contract, there is no external vault mechanism involved.
|
||||
|
||||
The `percent` parameter represents the portion of the position to withdraw, using fixed-point math with 8 decimal precision. For example:
|
||||
|
||||
- `100_000_000` means 100% (full withdrawal)
|
||||
- `50_000_000` means 50%
|
||||
- `10_000_000` means 10%
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|-----------------|--------------|
|
||||
| `token-x-trait` | `<ft-trait>` |
|
||||
| `token-y-trait` | `<ft-trait>` |
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
| `percent` | `uint` |
|
||||
|
||||
#### `swap-x-for-y-ioc`
|
||||
|
||||
This function allows users to swap a specific amount of token X (`dx`) for token Y in a selected bin (`tick`) of a DAMM pool, using an **Immediate-Or-Cancel (IOC)** strategy. The swap aims to provide the best possible rate for token Y. The effective upper price limit for the swap is the more restrictive of either the user-defined `max-price` or the natural upper price boundary (`price-end`) of the specified tick. If the requested `dx` would push the price beyond this effective cap, only a partial amount (or none) of `dx` will be swapped.
|
||||
|
||||
The function validates the pool's status and token traits, calculates how much of token X can be swapped without breaching the price cap, applies fees and potential rebates, and executes the transfers. If conditions are not met (e.g. price exceeds `max-price` or insufficient liquidity), it returns zero values for all outputs.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------------------|-------------|
|
||||
| `token-x-trait` | `<ft-trait>` |
|
||||
| `token-y-trait` | `<ft-trait>` |
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
| `dx` | `uint` |
|
||||
| `max-price` | `uint` |
|
||||
|
||||
#### `swap-y-for-x-ioc`
|
||||
|
||||
This function is the reverse of `swap-x-for-y-ioc`, the execution logic is similar. The effective lower price limit for the swap is the less restrictive of either the user-defined `min-price` or the natural lower price boundary (`price-start`) of the specified tick. If the requested `dy` would push the price below this effective cap, only a partial amount (or none) will be swapped. If conditions are not met, it returns zero values for all outputs.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|-----------------|--------------|
|
||||
| `token-x-trait` | `<ft-trait>` |
|
||||
| `token-y-trait` | `<ft-trait>` |
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
| `dy` | `uint` |
|
||||
| `min-price` | `uint` |
|
||||
|
||||
### Governance Features
|
||||
|
||||
The following functions are guarded by the `is-dao-or-extension` function. This implies that only the ALEX DAO or an enabled extension can use these features.
|
||||
|
||||
#### `is-dao-or-extension`
|
||||
|
||||
Standard protocol function to check whether the `contract-caller` is an enabled extension within the DAO or the `tx-sender` is the DAO itself. The extension check is delegated to the `executor-dao` contract.
|
||||
|
||||
#### `create-pool`
|
||||
|
||||
Creates a new DAMM pool between two SIP-010 fungible tokens.
|
||||
|
||||
This function configures a pool with a specific `bin-size`, fee rates for each token, and a fee rebate percentage. It performs several validations before pool creation:
|
||||
|
||||
- Ensures that both tokens are different and verifies the `bin-size` is one of the allowed values (`u1`, `u5`, `u10`, `u20`).
|
||||
- Checks that a pool with the same token pair (`token-x`, `token-y`) and `bin-size` does not already exist. It also verifies that a pool with the reversed token pair (`token-y`, `token-x`) and the same `bin-size` is not already registered.
|
||||
- Validates that `fee-rate-x` and `fee-rate-y` are strictly less than 1e8 (`ONE_8`) and that `fee-rebate` does not exceed 100%.
|
||||
|
||||
The pool is stored using a new `pool-id` generated by incrementing `pool-id-nonce`, and it is inserted into both the `pools` map and the `pool-id-by-token` index for lookup by token pair. The pool starts in an active state (not paused or sunset), and the owner is set to the supplied `pool-owner`. Finally, it emits an event with the pool ID, the pool parameters, and the transaction sender.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| -------------- | ------------ |
|
||||
| `token-x-trait`| `<ft-trait>` |
|
||||
| `token-y-trait`| `<ft-trait>` |
|
||||
| `bin-size` | `uint` |
|
||||
| `pool-owner` | `principal` |
|
||||
| `fee-rate-x` | `uint` |
|
||||
| `fee-rate-y` | `uint` |
|
||||
| `fee-rebate` | `uint` |
|
||||
|
||||
#### `update-pool-fee`
|
||||
|
||||
Updates the fee configuration for an existing pool. It sets new values for the swap fee on each token and the rebate returned to liquidity providers. The function also validates that the new fee values for token X and token Y are both less than `ONE_8` (i.e. below 100%). Finally, it emits an event with the pool ID, the updated fees, the fee rebate, and the transaction sender.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ------------ | ------ |
|
||||
| `pool-id` | `uint` |
|
||||
| `fee-rate-x` | `uint` |
|
||||
| `fee-rate-y` | `uint` |
|
||||
| `fee-rebate` | `uint` |
|
||||
|
||||
#### `set-pool-status`
|
||||
|
||||
Updates the operational status of a pool. It can mark a pool as `paused` (temporarily disabling activity) or `sunset` (permanently deactivating the pool), affecting its availability for swaps and actions like adding or removing liquidity. Finally, it emits an event with the pool ID, the deactivation and pause status, and the transaction sender.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ------ |
|
||||
| `pool-id` | `uint` |
|
||||
| `sunset` | `bool` |
|
||||
| `paused` | `bool` |
|
||||
|
||||
#### `claim-fees`
|
||||
|
||||
Allows the DAO to withdraw accumulated swap fees from a specific pool and tick. The function resets the stored fees to zero and transfers the collected amounts of both tokens to the specified address using the corresponding token contracts.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ----------------- | ----------- |
|
||||
| `token-x-trait` | `<ft-trait>` |
|
||||
| `token-y-trait` | `<ft-trait>` |
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
| `fee-to-address` | `principal` |
|
||||
|
||||
### Getters
|
||||
|
||||
#### `get-pool-count`
|
||||
|
||||
#### `get-pool-id`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `key` | `{ token-x: principal, token-y: principal, bin-size: uint }` |
|
||||
|
||||
#### `get-pool`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
#### `get-pool-balances`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
|
||||
#### `get-liquidity-token-id`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `pool-id` | `uint` |
|
||||
| `tick` | `int` |
|
||||
|
||||
#### `parse-liquidity-token-id`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `token-id` | `uint` |
|
||||
|
||||
#### `tick-to-price`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `bin-size` | `uint` |
|
||||
| `tick` | `int` |
|
||||
|
||||
#### `get-price-bounds`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| `bin-size` | `uint` |
|
||||
| `tick` | `int` |
|
||||
|
||||
#### `get-virtual-balances`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
|-------------|------|
|
||||
| `bin-size` | `uint` |
|
||||
| `tick` | `int` |
|
||||
| `balance-x` | `uint` |
|
||||
| `balance-y` | `uint` |
|
||||
|
||||
## Storage
|
||||
|
||||
### `pool-id-nonce`
|
||||
|
||||
| Data | Type |
|
||||
|----------|------|
|
||||
| Variable | `uint` |
|
||||
|
||||
A global counter used to assign unique identifiers to new pools. It is incremented each time a pool is created through the `create-pool` function.
|
||||
|
||||
### `pools`
|
||||
|
||||
| Data | Type |
|
||||
|------|------|
|
||||
| Map | `uint => { token-x: principal, token-y: principal, bin-size: uint, pool-owner: principal, fee-rate-x: uint, fee-rate-y: uint, fee-rebate: uint, sunset: bool, paused: bool }` |
|
||||
|
||||
Stores configuration data for each pool, indexed by `pool-id`. It includes the token pair, bin size, fee parameters, and status flags (`paused` and `sunset`). This map is used to validate pool existence and retrieve parameters during pool creation, swaps, and liquidity operations.
|
||||
|
||||
### `pool-id-by-token`
|
||||
|
||||
| Data | Type |
|
||||
|------|------|
|
||||
| Map | `{ token-x: principal, token-y: principal, bin-size: uint } => uint` |
|
||||
|
||||
Maps a token pair and bin size to its corresponding `pool-id`. This provides a way to retrieve an existing pool’s ID based on its asset configuration.
|
||||
|
||||
### `pool-supply`
|
||||
|
||||
| Data | Type |
|
||||
|------|------|
|
||||
| Map | `{ pool-id: uint, tick: int } => { total-supply: uint, balance-x: uint, balance-y: uint, fee-x: uint, fee-y: uint }` |
|
||||
|
||||
Stores the state of each bin in a pool, indexed by `pool-id` and `tick`. It tracks the total LP token supply, token balances, and accumulated fees for that specific price range within the pool.
|
||||
|
||||
## Contract calls
|
||||
|
||||
- `executor-dao`: called by governance functions (e.g., `create-pool`, `update-pool-fee`) via `is-dao-or-extension` to verify if the `contract-caller` is an authorized extension or if `tx-sender` is the DAO itself.
|
||||
- `amm-liquidity-token-v3`: used to mint and burn LP tokens that represent user positions in specific ticks.
|
||||
- `token-x-trait` / `token-y-trait`: represent the fungible tokens involved in each pool. These trait contracts are used to perform transfers during swaps and liquidity updates.
|
||||
|
||||
## Errors
|
||||
|
||||
| Error Name | Value |
|
||||
| --------------------------------------- | ------------- |
|
||||
| `ERR-NOT-AUTHORIZED` | `(err u1000)` |
|
||||
| `ERR-POOL-PAUSED` | `(err u1001)` |
|
||||
| `ERR-POOL-SUNSET` | `(err u1002)` |
|
||||
| `ERR-POOL-NOT-FOUND` | `(err u1003)` |
|
||||
| `ERR-INVALID-PAIR` | `(err u1004)` |
|
||||
| `ERR-POOL-ALREADY-EXISTS` | `(err u2000)` |
|
||||
| `ERR-INVALID-PRICE` | `(err u2001)` |
|
||||
| `ERR-INVALID-TOKEN-TRAIT` | `(err u2002)` |
|
||||
| `ERR-INVALID-BIN-SIZE` | `(err u2003)` |
|
||||
| `ERR-PERCENT-GREATER-THAN-ONE` | `(err u2004)` |
|
||||
| `ERR-ZERO-PERCENT` | `(err u2005)` |
|
||||
| `ERR-INVALID-AMOUNT` | `(err u2006)` |
|
||||
| `ERR-POSITION-NOT-FOUND` | `(err u2007)` |
|
||||
| `ERR-PERCENT-GREATER-THAN-OR-EQUALS-ONE` | `(err u2008)` |
|
||||
| `ERR-INSUFFICIENT-LIQUIDITY` | `(err u2009)` |
|
||||
| `ERR-STORAGE-FAILURE` | `(err u3001)` |
|
||||
| `ERR-INVALID-LP-STATE` | `(err u3002)` |
|
||||
| `ERR-MAX-POOLS-ALLOWED` | `(err u3003)` |
|
||||
| `ERR-TICK-OUT-OF-RANGE` | `(err u3004)` |
|
||||
@@ -0,0 +1,189 @@
|
||||
# Registry
|
||||
|
||||
#### Location: [`alex-dao-2/contracts/aux/amm-registry-v2-01.clar`](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/aux/amm-registry-v2-01.clar)
|
||||
|
||||
This document provides comprehensive technical details for the registry contract within ALEX's Automated Market Maker (AMM) Trading Pool system. The contract primarily functions as a persistence module for all pool-related information needed by the main contract [amm-pool-v2-01.clar](amm-pool-v2-01.clar.md).
|
||||
|
||||
To achieve this, the contract allows for the creation and updating of pools. Pool creation involves persisting an entry in a datamap, using `token-x`, `token-y`, and `factor` as the key and containing all relevant pool information.
|
||||
|
||||
Additionally, the contract includes configuration getters and setters that support position and swap operations. It is also responsible for managing a list of blocklisted operators.
|
||||
|
||||
## Storage
|
||||
|
||||
### Variables: (datamap)
|
||||
|
||||
* `pools-data-map` (datamap
|
||||
key:
|
||||
{
|
||||
token-x: principal,
|
||||
token-y: principal,
|
||||
factor: uint
|
||||
}
|
||||
value:
|
||||
{
|
||||
pool-id: uint,
|
||||
total-supply: uint,
|
||||
balance-x: uint,
|
||||
balance-y: uint,
|
||||
pool-owner: principal,
|
||||
fee-rate-x: uint,
|
||||
fee-rate-y: uint,
|
||||
fee-rebate: uint,
|
||||
oracle-enabled: bool,
|
||||
oracle-average: uint,
|
||||
oracle-resilient: uint,
|
||||
start-block: uint,
|
||||
end-block: uint,
|
||||
threshold-x: uint,
|
||||
threshold-y: uint,
|
||||
max-in-ratio: uint,
|
||||
max-out-ratio: uint
|
||||
}
|
||||
)
|
||||
A datamap structure that persists complete pool information. The map key consists of the unique pool identifier `{token-x, token-y, factor}`, and the map value contains detailed pool attributes.
|
||||
|
||||
* `pools-id-map` (datamap key: uint value: { token-x: principal, token-y: principal, factor: uint })
|
||||
A datamap structure that facilitates the retrieval of pool details using the pool ID as the key. The stored values include `token-x` and `token-y` principals, and `factor`.
|
||||
|
||||
* `blocklist` (datamap key: principal value: bool)
|
||||
A datamap structure that stores a persisted list of blocklisted addresses for operating within the Alex Trading Pool.
|
||||
|
||||
### Variables: (data-var)
|
||||
|
||||
* `pool-nonce` (uint)
|
||||
A persisted variable used to generate a new pool ID incrementally. The stored value represents the last pool ID that was created.
|
||||
|
||||
* `switch-threshold` (uint)
|
||||
An internal variable used to set a fixed threshold for calculations. It is initialized with `u80000000` and can be retrieved and modified using `get-switch-threshold` and `set-switch-threshold` functions. The value of `switch-threshold` must be less than or equal to the constant `ONE_8`. This value is crucial for the mathematical formulas used within the `amm-pool-v2-01.clar` contract.
|
||||
|
||||
* `max-ratio-limit` (uint)
|
||||
This variable sets the upper limit for the ratio in a token pool. These ratios are evaluated during each pool swap operation to determine the maximum amount that can be deposited or exchanged in the pool. It is initialized with the value of the constant `ONE_8`.
|
||||
|
||||
#### Mathematical constants
|
||||
|
||||
This symbolic constant is employed to define and restrict decimal precision to 8 decimal places.
|
||||
|
||||
* `ONE_8` It is declared as `u100000000`.
|
||||
|
||||
## Contract calls (interactions)
|
||||
|
||||
* `executor-dao` This call is used to verify whether a certain contract caller is designated as an extension.
|
||||
|
||||
## Features
|
||||
|
||||
1. `create-pool` This function establishes a liquidity pool for a specified token pair (token-x/token-y). It begins by verifying that the `tx-sender` is an ALEX admin operator (see the function `is-dao-or-extension`), as it is intended to be used by the main `amm-pool-v2-01.clar` contract in the current model.
|
||||
The primary validation performed by this function ensures that the pool does not already exist; if it does, an error is thrown. This validation considers the factor and both token combinations (token-x/token/y or token-y/token-x) as unique identifiers. When a pool is created, an entry is added to the `pools-data-map` structure, using this unique identifier as the key to keep track of all pool information, including balances, fees, thresholds, and more. Additionally, the function generates an ID for the newly created pool (see `pool-nonce`).
|
||||
All remaining values in the datamap are initialized to zero (`u0`), except for `oracle-enabled`, which is set to `false`. Additionally, `start-block` and `end-block` are initialized with the maximum uint value to ensure the pool remains in a non-operational status until properly initialized. For a complete list of fields, refer to the `pools-data-map`.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(token-y-trait <ft-trait>)
|
||||
(factor uint)
|
||||
(pool-owner principal)
|
||||
```
|
||||
|
||||
2. `update-pool` This function updates a liquidity pool identified by the unique combination of `token-x`, `token-y`, and `factor`. It is a governed function that restricts the `tx-sender` to be an ALEX admin operator (see the function `is-dao-or-extension`).
|
||||
Similar to the aforementioned `create-pool` function, `update-pool` is designed to be used by the main `amm-pool-v2-01.clar` contract. However, in this case, it is used indirectly in position and swap operations.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-x principal)
|
||||
(token-y principal)
|
||||
(factor uint)
|
||||
(pool-data {
|
||||
pool-id: uint,
|
||||
total-supply: uint,
|
||||
balance-x: uint,
|
||||
balance-y: uint,
|
||||
pool-owner: principal,
|
||||
fee-rate-x: uint,
|
||||
fee-rate-y: uint,
|
||||
fee-rebate: uint,
|
||||
oracle-enabled: bool,
|
||||
oracle-average: uint,
|
||||
oracle-resilient: uint,
|
||||
start-block: uint,
|
||||
end-block: uint,
|
||||
threshold-x: uint,
|
||||
threshold-y: uint,
|
||||
max-in-ratio: uint,
|
||||
max-out-ratio: uint }
|
||||
)
|
||||
```
|
||||
|
||||
### Governance features
|
||||
|
||||
1. `is-dao-or-extension` This standard protocol function checks whether a caller (`tx-sender`) is the DAO executor or an authorized extension, delegating the extensions check to the `executor-dao` contract.\
|
||||
**Input**:
|
||||
None.
|
||||
|
||||
2. `is-blocklisted-or-default` A read-only feature that verifies if a given address is blacklisted using the `blocklist` map.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(sender principal)
|
||||
```
|
||||
|
||||
3. `set-blocklist-many` A public function, governed by the `is-dao-or-extension` mechanism, that allows setting or updating the blocklisted status for a list of addresses (up to 1000 addresses).\
|
||||
**Input**:
|
||||
```lisp
|
||||
(list 1000 {
|
||||
sender: principal,
|
||||
blocked: bool
|
||||
})
|
||||
```
|
||||
|
||||
### Getter and Setter functions
|
||||
|
||||
#### Pool administration setters
|
||||
|
||||
* `set-fee-rebate`
|
||||
* `set-pool-owner`
|
||||
* `set-max-ratio-limit`
|
||||
* `set-switch-threshold`
|
||||
|
||||
#### Pool operation setters and getters
|
||||
The following groups of functions support pool usage and configuration features consumed by the main `amm-pool-v2-01.clar` contract.
|
||||
|
||||
#### Setters
|
||||
|
||||
* `set-start-block`
|
||||
* `set-end-block`
|
||||
* `set-fee-rate-x`
|
||||
* `set-fee-rate-y`
|
||||
* `set-max-in-ratio`
|
||||
* `set-max-out-ratio`
|
||||
* `set-oracle-average`
|
||||
* `set-oracle-enabled`
|
||||
* `set-threshold-x`
|
||||
* `set-threshold-y`
|
||||
|
||||
#### Getters
|
||||
|
||||
* `get-pool-details-by-id`
|
||||
* `get-pool-details`
|
||||
* `get-pool-exists`
|
||||
* `get-max-ratio-limit`
|
||||
* `get-switch-threshold`
|
||||
|
||||
#### Internal helper functions
|
||||
|
||||
* `set-blocklist` This is a private function designed to complement the aforementioned governance function `set-blocklist-many`.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(sender principal)
|
||||
(blocked bool)
|
||||
```
|
||||
|
||||
## Errors defined in the contract
|
||||
* `ERR-EXCEEDS-MAX-SLIPPAGE`
|
||||
* `ERR-INVALID-LIQUIDITY`
|
||||
* `ERR-INVALID-POOL`
|
||||
* `ERR-MAX-IN-RATIO`
|
||||
* `ERR-MAX-OUT-RATIO`
|
||||
* `ERR-NO-LIQUIDITY`
|
||||
* `ERR-NOT-AUTHORIZED`
|
||||
* `ERR-ORACLE-AVERAGE-BIGGER-THAN-ONE`
|
||||
* `ERR-ORACLE-NOT-ENABLED`
|
||||
* `ERR-PAUSED`
|
||||
* `ERR-PERCENT-GREATER-THAN-ONE`
|
||||
* `ERR-POOL-ALREADY-EXISTS`
|
||||
* `ERR-SWITCH-THRESHOLD-BIGGER-THAN-ONE`
|
||||
163
developers/developers/protocol-contracts/amm-vault-v2-01.clar.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Vault
|
||||
|
||||
#### Location: [`alex-dao-2/contracts/aux/amm-vault-v2-01.clar`](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/aux/amm-vault-v2-01.clar)
|
||||
|
||||
This document provides comprehensive technical details for the vault contract within ALEX's Automated Market Maker (AMM) Trading Pool system. The vault contract supports the primary contract [amm-pool-v2-01.clar](amm-pool-v2-01.clar.md) in position and swap operations by keeping record of the reserves accumulated from fees and securing pool assets. It ensures asset security through transfer transactions where the vault contract is the recipient of token transfers, thereby holding and safeguarding the assets within the pool.
|
||||
In addition to supporting Trading Pool operations, the vault contract also offers a flash-loan feature for registered tokens, available to approved users.
|
||||
|
||||
## Storage
|
||||
|
||||
### Variables: (data-var)
|
||||
|
||||
* `paused` (bool)
|
||||
This data variable acts as a flag to determine and control the operational status of the contract within the system.
|
||||
|
||||
#### Token variables
|
||||
|
||||
* `approved-tokens` (datamap key: principal value: bool)
|
||||
A datamap structure that lists all the approved tokens for transfer and loan operations.
|
||||
|
||||
* `reserve` (datamap key: principal value: uint)
|
||||
A datamap structure that keeps record of all the reserves in the vault for a specific token.
|
||||
|
||||
#### Flash-loan variables
|
||||
|
||||
* `approved-flash-loan-users` (datamap key: principal value: bool)
|
||||
A datamap structure that lists all the approved users for loan operations.
|
||||
|
||||
* `flash-loan-enabled` (bool)
|
||||
A flag variable indicating the status of the contract's flash-loan feature. Currently, this is only an informative flag.
|
||||
|
||||
* `flash-loan-fee-rate` (uint)
|
||||
This variable defines the fee rate charged for loan operations.
|
||||
|
||||
#### Mathematical constants
|
||||
|
||||
This symbolic constant is employed to define and restrict decimal precision to 8 decimal places.
|
||||
|
||||
* `ONE_8` It is declared as `u100000000`.
|
||||
|
||||
## Contract calls (interactions)
|
||||
|
||||
* `executor-dao` This call is used to verify whether a certain contract caller is designated as an extension.
|
||||
|
||||
* `token-trait` Calls are made to token contracts that comply with the <ft-trait> defined in each token-trait parameter to facilitate token transfers and retrieve balances during transfer and loan operations.
|
||||
|
||||
* `flash-loan-user-trait` Calls are made to token contracts that comply with the <flash-loan-trait> defined in the flash-loan-user-trait variable to execute loans for the approved flash-loan users and tokens.
|
||||
|
||||
## Features
|
||||
|
||||
1. `add-to-reserve` This function increases the existing reserves of a specific token by the given amount. It is governed by the `is-dao-or-extension` check to ensure that the `tx-sender` is an ALEX admin operator. Intended to be invoked by the main `amm-pool-v2-01.clar` contract during swap operations, this function is called following a transfer of the incoming token (token-x) to the vault contract. The `add-to-reserve` function is then executed with the token principal and the specified amount, representing the swap fees charged by the system for the transaction.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-trait principal)
|
||||
(amount uint)
|
||||
```
|
||||
|
||||
2. `remove-from-reserve` This function serves as the reverse operation of `add-to-reserve`, decreasing the specified amount for the given token. An additional check ensures that the amount is less than or equal to the token's current reserve in the vault.
|
||||
Although it is not currently called by any existing module, the function also verifies that the `tx-sender` is an ALEX admin operator via the `is-dao-or-extension` control.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-trait principal)
|
||||
(amount uint)
|
||||
```
|
||||
|
||||
3. `transfer-ft` Like `add-to-reserve`, this function is intended to be called by the `amm-pool-v2-01.clar` contract during swap operations and is governed by the `is-dao-or-extension` check. Controls are in place to ensure that the contract is operational (not paused) and that the given token is approved in the contract's list.
|
||||
If all these conditions are met, the function will execute a transfer of the specified amount from the vault to the designated recipient.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-trait <ft-trait>)
|
||||
(amount uint)
|
||||
(recipient principal)
|
||||
```
|
||||
|
||||
4. `transfer-ft-two` This function serves as a helper for calling the `transfer-ft` function twice with two different tokens and amounts for the same recipient within a single transaction. In the current model, this feature is utilized by the `amm-pool-v2-01.clar` contract during position reduction operations to return assets to the user.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-x-trait <ft-trait>)
|
||||
(dx uint)
|
||||
(token-y-trait <ft-trait>)
|
||||
(dy uint)
|
||||
(recipient principal)
|
||||
```
|
||||
|
||||
5. `transfer-sft` This function is similar to `transfer-ft`, but it is designed for semi-fungible tokens, which operate with a token ID. It includes the same controls as `transfer-ft` regarding the vault's operational status and approved tokens. Although this function is not called by the `amm-pool-v2-01.clar` contract in the current system design, it requires invocation by an ALEX admin operator, as governed by the `is-dao-or-extension` check.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(token-trait <sft-trait>)
|
||||
(token-id uint)
|
||||
(amount uint)
|
||||
(recipient principal)
|
||||
```
|
||||
|
||||
6. `flash-loan` This function is designed to lend the recipient (the `tx-sender`) a specified amount of tokens to execute an embedded function declared in the `flash-loan-trait`. The recipient then transfers back the same amount plus the corresponding fee (refer to `flash-loan-fee-rate`).
|
||||
As with previous features, controls are in place to check the vault's operational status, approve tokens and flash-loan users, and ensure there is sufficient balance to make the transfer.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(flash-loan-user-trait <flash-loan-trait>)
|
||||
(token-trait <ft-trait>)
|
||||
(amount uint)
|
||||
(memo (optional (buff 16)))
|
||||
```
|
||||
|
||||
### Governance features
|
||||
|
||||
1. `is-dao-or-extension` This standard protocol function checks whether a caller (`tx-sender`) is the DAO executor or an authorized extension, delegating the extensions check to the `executor-dao` contract.\
|
||||
**Input**:
|
||||
None.
|
||||
|
||||
2. `is-paused` A read-only function that checks the operational status of the contract.\
|
||||
**Input**:
|
||||
None.
|
||||
|
||||
3. `pause` A public function, governed through the `is-dao-or-extension`, that can change the contract's operational status.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(new-paused bool)
|
||||
```
|
||||
|
||||
### Getter and Setter functions
|
||||
|
||||
#### Vault administration getter
|
||||
* `get-reserve`
|
||||
|
||||
#### Flash-loan operation setters and getters
|
||||
|
||||
**Setters**
|
||||
|
||||
* `set-approved-flash-loan-user`
|
||||
* `set-approved-token`
|
||||
* `set-flash-loan-enabled`
|
||||
* `set-flash-loan-fee-rate`
|
||||
|
||||
**Getters**
|
||||
* `get-flash-loan-enabled`
|
||||
* `get-flash-loan-fee-rate`
|
||||
|
||||
#### Internal helper functions
|
||||
|
||||
* `check-is-approved-flash-loan-user` This is a private function designed to verify whether a flash-loan user is approved in the contract's persisted datamap, `approved-flash-loan-users`.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(flash-loan-user-trait principal)
|
||||
```
|
||||
|
||||
* `check-is-approved-token` This is a private function designed to verify whether a token is approved in the contract's persisted datamap, `approved-tokens`.\
|
||||
**Input**:
|
||||
```lisp
|
||||
(flash-loan-token principal)
|
||||
```
|
||||
|
||||
**Mathematical helpers**
|
||||
|
||||
These helper functions aid in various calculations within the context of the contract.
|
||||
* `mul-down`
|
||||
* `mul-up`
|
||||
|
||||
## Errors defined in the contract
|
||||
|
||||
* `ERR-AMOUNT-EXCEED-RESERVE`
|
||||
* `ERR-INVALID-BALANCE`
|
||||
* `ERR-INVALID-TOKEN`
|
||||
* `ERR-NOT-AUTHORIZED`
|
||||
* `ERR-PAUSED`
|
||||
@@ -0,0 +1,578 @@
|
||||
# farming-campaign-v2-02.clar
|
||||
|
||||
<!--- Location: [`alex-dao-2/contracts/extensions/farming-campaign-v2-02.clar`](https://github.com/alexgo-io/alex-dao-2/blob/main/contracts/extensions/farming-campaign-v2-02.clar)-->
|
||||
- [Deployed contract](https://explorer.hiro.so/txid/SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.farming-campaign-v2-02?chain=mainnet)
|
||||
|
||||
The `farming-campaign-v2-02` contract manages the ALEX Surge liquidity incentive program, where liquidity pools compete to receive $ALEX rewards. Participants influence the reward distribution by voting for pools, while liquidity providers can stake LP tokens to earn additional rewards.
|
||||
Surge is structured in rounds. The process follows these steps:
|
||||
1. **Pool Registration** – Projects must register liquidity pools before the deadline to participate in the Surge round.
|
||||
2. **Voting** – Users vote using ALEX and LiALEX tokens to decide how rewards will be distributed among the registered pools.
|
||||
3. **Staking** – Liquidity providers stake LP tokens, which represent their share of a trading pool’s assets, to earn additional rewards.
|
||||
4. **Reward Distribution** – At the end of the round, $ALEX rewards are distributed among the pools based on the votes received. Within each pool, the rewards are allocated proportionally to liquidity providers based on the amount of LP tokens they staked.
|
||||
|
||||
Additionally, projects can donate voter rewards as extra incentives to attract votes for their pools.
|
||||
|
||||
## Features
|
||||
|
||||
### Public Features
|
||||
|
||||
#### `stake`
|
||||
|
||||
This function allows users to stake LP tokens in a registered liquidity pool within an active Surge campaign. Staking LP tokens makes users eligible to receive a share of the $ALEX rewards allocated to the pool based on the total votes it received.
|
||||
The function verifies that the registration period has ended and the staking period is still active. It then interacts with the `token-amm-pool-v2-01` contract to transfer the specified amount of LP tokens from the sender’s wallet to the contract. After the transfer, it updates the total amount of LP tokens staked in the pool. Once the staking is confirmed, the contract updates the `campaign-stakers` map with the staker’s details and emits a notification event.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
| `campaign-id`| `uint`|
|
||||
|`amount`|`uint`|
|
||||
|
||||
#### `unstake`
|
||||
|
||||
This function allows users to withdraw their staked LP tokens from a liquidity pool in a Surge campaign while claiming any earned $ALEX. Before proceeding, it verifies that the staking period has ended and that the user has not already collected their allocation.
|
||||
The contract determines the user's share based on the $ALEX rewards allocated to the pool, which were determined by the votes it received. The distribution within the pool is then proportional to the amount of LP tokens each user staked. Once determined, it mints and transfers the corresponding amount to the user via the `token-alex` contract. Additionally, it calls `token-amm-pool-v2-01` to return the LP tokens back to the user and updates `campaign-stakers` to mark the process as complete. A notification event logs the transaction.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
| `campaign-id`| `uint`|
|
||||
|
||||
#### `register-for-campaign`
|
||||
|
||||
This function allows a liquidity pool to register to participate in a Surge campaign. Before registering, it ensures that the pool is whitelisted and that the registration deadline has not been reached. Additionally, it checks that the pool has not already been registered.
|
||||
Once validated, the function creates an entry in `campaign-registrations`, initializing reward amounts and total staked values to `0`. It also updates `campaign-registered-pools` to add the new registered pool. A notification event logs the registration.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
| `campaign-id`| `uint`|
|
||||
|
||||
#### `add-reward-for-campaign`
|
||||
|
||||
This function allows a registrant to add voter rewards to a liquidity pool already registered in a Surge round. These rewards incentivize users to vote for the pool.
|
||||
The function first verifies that the pool is registered in the campaign. It ensures that the voting phase is still open and validates that the reward token matches either of the pool’s trading tokens by interacting with the `amm-pool-v2-01`. If these conditions are met, the function transfers the specified reward amount from the registrant to the contract using the provided token contract. It then updates the stored reward balances for the pool in `campaign-registrations` and records the registrant’s contribution in `campaign-registrants`.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
| `campaign-id`| `uint`|
|
||||
|`reward-token-trait`|`<ft-trait>`|
|
||||
|`reward-amount`|`uint`|
|
||||
|
||||
#### `vote-campaign`
|
||||
|
||||
This function allows participants to vote for liquidity pools in a Surge round, determining how $ALEX rewards are distributed. Users allocate their voting power across one or multiple pools.
|
||||
The function verifies that the voting phase is active and retrieves the voter’s available voting power using the `voting-power` function, which calculates the user's voting power based on their $ALEX and $LiALEX holdings. It ensures that the total votes cast does not exceed the voter's limit. Once validated, the function updates the vote counts for each selected pool in `campaign-voter-votes` map, records the total votes cast in `campaign-total-vote` map and applies the vote distribution logic through `update-pool-votes` function.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
| `votes`| `list 1000 { pool-id: uint, votes: uint }`|
|
||||
|`lp-pools`|`list 200 uint`|
|
||||
|
||||
#### `claim-vote-reward`
|
||||
|
||||
This function allows voters to claim rewards from a Surge round if they voted for a liquidity pool that distributed voter rewards. These rewards are additional incentives offered by pool registrants to encourage voting participation.
|
||||
The function first checks that the voting phase has ended and ensures the voter has not previously claimed rewards for the specified pool. It then calculates the voter’s share based on the total votes cast for the pool, using data stored in `campaign-pool-votes-by-voter` and `campaign-pool-votes-for-project-reward` maps, which track individual and total votes for voter rewards distribution. The function verifies that the requested reward tokens match the liquidity pool’s assets by interacting with the `amm-pool-v2-01` contract. If all conditions are met, the function transfers the voter’s share of the rewards and updates `campaign-vote-rewards-claimed` to prevent duplicate claims.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
| `campaign-id`| `uint`|
|
||||
|`reward-token-x-trait`|`<ft-trait>`|
|
||||
|`reward-token-y-trait`|`<ft-trait>`|
|
||||
|
||||
#### `claim-vote-reward-many`
|
||||
|
||||
This function enables batch claiming of voter rewards for multiple liquidity pools and campaigns in a single transaction. It iterates over the provided lists of pool IDs, campaign IDs and reward token contracts, calling the `claim-vote-reward` function for each entry.
|
||||
Since it relies on [`claim-vote-reward`](#claim-vote-reward) function, the same eligibility checks apply.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-ids`|`list 100 uint`|
|
||||
| `campaign-ids`| `list 100 uint`|
|
||||
|`reward-token-x-traits`|`list 100 <ft-trait>`|
|
||||
|`reward-token-y-traits`|`list 100 <ft-trait>`|
|
||||
|
||||
### Privileged Features
|
||||
|
||||
#### `revoke-registration`
|
||||
|
||||
This privileged function allows revoking a pool's registration in a Surge campaign before the registration cut-off date. The action can be performed by the DAO or an authorized extension, or by the pool's registrant if `revoke-enabled` is set to `true`. If revoked, the registrant recovers the voter rewards they contributed.
|
||||
The function ensures that the specified reward tokens match the pool’s trading pair by interacting with `amm-pool-v2-01`. If the conditions are met, it updates the `campaign-registrations` and `campaign-registrants` maps to remove the pool and return the reward tokens to the registrant.
|
||||
|
||||
### Governance Features
|
||||
|
||||
#### `is-dao-or-extension`
|
||||
This standard protocol function checks whether a caller (`tx-sender`) is the DAO executor or an authorized extension, delegating the extensions check to the `executor-dao` contract.
|
||||
|
||||
#### `set-campaign-nonce`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the campaign nonce, which serves as a unique identifier for newly created Surge rounds. This ensures that each campaign has a sequential and distinct ID.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`new-nonce`|`uint`|
|
||||
|
||||
#### `set-revoke-enabled`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that enables or disables the ability to revoke a registered liquidity pool from a campaign before the registration cut-off date. When set to `true`, the registrant of a pool can cancel its participation and recover the reward tokens added during registration. By default, this is set to `false`, meaning that once a pool is registered, it cannot be removed from the campaign.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`enabled`|`bool`|
|
||||
|
||||
#### `whitelist-pools`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the list of liquidity pools eligible to participate in Surge campaigns. Only pools that are whitelisted can be registered in a campaign.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pools`|`(list 1000 uint)`|
|
||||
|
||||
#### `create-campaign`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that initializes a new Surge campaign. This function sets key parameters such as registration, voting, and staking deadlines, as well as the total reward amount allocated for distribution. Each campaign is assigned a unique ID, incremented from the `campaign-nonce` variable.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`registration-cutoff`|`uint`|
|
||||
|`voting-cutoff`|`uint`|
|
||||
|`stake-cutoff`|`uint`|
|
||||
|`stake-end`|`uint`|
|
||||
|`reward-amount`|`uint`|
|
||||
|`snapshot-block`|`uint`|
|
||||
|
||||
#### `transfer-token`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that allows the contract to transfer a specified amount of a fungible token to a recipient.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`token-trait`|`<ft-trait>`|
|
||||
|`amount`|`uint`|
|
||||
|`recipient`|`principal`|
|
||||
|
||||
#### `update-campaign`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the parameters of an existing campaign. This function modifies attributes such as registration deadlines, voting periods, staking timelines, and reward allocations.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`details`|`{ registration-cutoff: uint, voting-cutoff: uint, stake-cutoff: uint, stake-end: uint, reward-amount: uint, snapshot-block: uint }`|
|
||||
|
||||
#### `update-campaign-registrations`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the registration details of a liquidity pool within a campaign. This function allows modifying the reward amounts allocated in token X and token Y, as well as the total staked amount in the pool. If the pool is not already registered in the campaign, it will be added to the list of registered pools.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-id`|`uint`|
|
||||
|`reward-amount-x`|`uint`|
|
||||
|`reward-amount-y`|`uint`|
|
||||
|`total-staked`|`uint`|
|
||||
|
||||
#### `update-campaign-stakers`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the staking details of a participant in a specific liquidity pool within a campaign. This function modifies the amount of LP tokens staked by a user and whether they have claimed their rewards.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-id`|`uint`|
|
||||
|`staker`|`principal`|
|
||||
|`amount`|`uint`|
|
||||
|`claimed`|`bool`|
|
||||
|
||||
#### `update-campaign-registrants`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the amount of token X and token Y recorded for a registrant when adding a liquidity pool to a campaign. These values represent voter rewards allocated to the pool, which can be modified or revoked before the registration cut-off date.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-id`|`uint`|
|
||||
|`registrant`|`principal`|
|
||||
|`token-x-amount`|`uint`|
|
||||
|`token-y-amount`|`uint`|
|
||||
|
||||
#### `set-project-reward-ignore-list`
|
||||
|
||||
A public function, governed through the `is-dao-or-extension`, that updates the list of addresses excluded from receiving voter rewards.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`addresses`|`(list 1000 principal)`|
|
||||
|
||||
### Getters
|
||||
|
||||
#### `get-campaign-nonce`
|
||||
|
||||
#### `get-campaign-or-fail`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|
||||
#### `get-campaigns-or-fail-many`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-ids`|`(list 200 uint)`|
|
||||
|
||||
#### `get-campaign-registration-by-id-or-fail`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-id`|`uint`|
|
||||
|
||||
#### `get-campaign-registration-by-id-or-fail-many`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-ids`|`(list 200 uint)`|
|
||||
|`pool-ids`|`(list 200 uint)`|
|
||||
|
||||
#### `get-campaign-staker-or-default`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-id`|`uint`|
|
||||
|`staker`|`principal`|
|
||||
|
||||
#### `get-campaign-staker-or-default-many`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-ids`|`(list 200 uint)`|
|
||||
|`pool-ids`|`(list 200 uint)`|
|
||||
|`stakers`|`(list 200 principal)`|
|
||||
|
||||
#### `get-pool-whitelisted`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
|
||||
#### `get-whitelisted-pools`
|
||||
|
||||
#### `voting-power`
|
||||
|
||||
#### `get-campaign-registered-pools`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|
||||
#### `get-campaign-summary`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|
||||
#### `get-campaign-staker-history-many`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`address`|`principal`|
|
||||
|`campaign-ids`|`(list 200 uint)`|
|
||||
|
||||
#### `get-registration-or-default`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-id`|`uint`|
|
||||
|`registrant`|`principal`|
|
||||
|
||||
#### `get-registration-or-default-many`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|`pool-ids`|`(list 1000 uint)`|
|
||||
|`registrant`|`principal`|
|
||||
|
||||
#### `get-revoke-enabled`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`campaign-id`|`uint`|
|
||||
|
||||
### Relevant internal functions
|
||||
|
||||
#### `update-pool-votes`
|
||||
|
||||
This private function updates the voting records for a liquidity pool. It is invoked by the `vote-campaign` function when a user submits votes.
|
||||
The function retrieves the current vote counts for the specified pool and updates the following vote-tracking maps: `campaign-pool-votes-for-project-reward`, `campaign-pool-votes-for-alex-reward` and `campaign-pool-votes-by-voter`.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`vote`|`{ pool-id: uint, votes: uint }`|
|
||||
| `context`| `{ campaign-id: uint, voter: principal }`|
|
||||
|
||||
#### `calculate-lp-voting-power`
|
||||
|
||||
This private function is used to calculate the LP voting power of a user for a specific liquidity pool. It is called by the `voting-power` function to determine the contribution of LP tokens to a user's total voting power.
|
||||
The function retrieves the pool's details from `amm-registry-v2-01` and `amm-pool-v2-01`. It then queries `alex-farming` contract to check if the user has staked LP tokens. Using this data, it calculates the user's LP voting power by determining how much ALEX-equivalent liquidity they provided, factoring in both directly held and staked LP tokens.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------| ---- |
|
||||
|`pool-id`|`uint`|
|
||||
| `acc`| `{ address: principal, total: uint }`|
|
||||
|
||||
## Storage
|
||||
|
||||
### `campaign-nonce`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Variable | `uint` |
|
||||
|
||||
A counter that keeps track of the total number of campaigns created. Each new campaign increments this value by `1`, ensuring a unique identifier for every Surge round.
|
||||
|
||||
### `revoke-enabled`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Variable | `bool` |
|
||||
|
||||
A flag that determines whether a registered liquidity pool can be revoked from a campaign before the registration cut-off date. When set to `true`, the registrant of a pool can cancel its participation and recover the reward tokens added during registration.
|
||||
By default, this value is set to `false`, meaning that once a pool is registered, it cannot be removed from the campaign.
|
||||
|
||||
### `whitelisted-pools`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Variable | `list (1000 uint)` |
|
||||
|
||||
A list of approved liquidity pools that are eligible to participate in ALEX Surge campaigns. Only pools included in this list can register for a campaign.
|
||||
By default, this list is empty, meaning that no pools are eligible until explicitly added. The DAO or an authorized contract can update this list through governance functions.
|
||||
|
||||
### `project-reward-ignore-list`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Variable | `list (1000 principal)` |
|
||||
|
||||
A list of addresses that are excluded from receiving voter rewards in ALEX Surge. If a voter's address is included in this list, they will not be eligible to claim any voter rewards, even if they participated in voting.
|
||||
By default, this list is empty, meaning no addresses are excluded initially. The DAO or an authorized contract can update this list through governance functions.
|
||||
|
||||
### `campaigns`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `uint → { registration-cutoff: uint, voting-cutoff: uint, stake-cutoff: uint, stake-end: uint, reward-amount: uint, snapshot-block: uint }` |
|
||||
|
||||
This map stores campaign data, where each entry is identified by a campaign ID (`uint`). It tracks the key timeline phases and reward details for each ALEX Surge campaign.
|
||||
|
||||
- `registration-cutoff`: the deadline for registering pools in the campaign.
|
||||
- `voting-cutoff`: the deadline for casting votes.
|
||||
- `stake-cutoff`: indicates the moment from which LP tokens can no longer be staked.
|
||||
- `stake-end`: the point at which the staking period ends and the reward emission phase begins.
|
||||
- `reward-amount`: the total $ALEX allocated for distribution in the campaign.
|
||||
- `snapshot-block`: the block height at which participant balances are recorded for voting power calculations.
|
||||
|
||||
### `campaign-registrations`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint } → { reward-amount-x: uint, reward-amount-y: uint, total-staked: uint }` |
|
||||
|
||||
This map stores the registration data of each liquidity pool within a specific Surge round.
|
||||
|
||||
Fields:
|
||||
- `campaign-id`: the unique identifier of the Surge round.
|
||||
- `pool-id`: the unique identifier of the registered liquidity pool.
|
||||
- `reward-amount-x`: the amount of rewards in token X allocated to the pool.
|
||||
- `reward-amount-y`: the amount of rewards in token Y allocated to the pool.
|
||||
- `total-staked`: the total amount of LP tokens staked in the pool.
|
||||
|
||||
This map is updated when a pool registers for a campaign and when LPs stake tokens in it.
|
||||
|
||||
### `campaign-stakers`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint, staker: principal } → { amount: uint, claimed: bool }` |
|
||||
|
||||
This map stores staking data for individual participants in a specific liquidity pool within a Surge round.
|
||||
|
||||
Fields:
|
||||
- `campaign-id`: The unique identifier of the Surge round.
|
||||
- `pool-id`: The unique identifier of the liquidity pool where the staking occurs.
|
||||
- `staker`: the principal identifier of the user who staked LP tokens.
|
||||
- `amount`: The total amount of LP tokens staked by the user in the pool.
|
||||
- `claimed`: A boolean value indicating whether the user has claimed their rewards.
|
||||
|
||||
This map is updated when users stake LP tokens and when they claim their rewards at the end of the campaign.
|
||||
|
||||
### `campaign-total-vote`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `campaign-id: uint → total-votes: uint` |
|
||||
|
||||
This map tracks the total number of votes cast in a specific Surge round. It is updated whenever users vote for liquidity pools during the voting phase.
|
||||
|
||||
### `campaign-registered-pools`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `campaign-id: uint → pool-ids: (list 1000 uint)` |
|
||||
|
||||
This map stores the list of liquidity pools that have been successfully registered in a specific Surge round.
|
||||
|
||||
### `campaign-registrants`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint, registrant: principal } → { token-x-amount: uint, token-y-amount: uint }` |
|
||||
|
||||
This map records the amount of token X and token Y added by a registrant when adding a liquidity pool to a Surge round. These tokens are used as rewards for voters but can be revoked before the registration cut-off date.
|
||||
|
||||
### `campaign-voter-votes`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, voter: principal } → uint` |
|
||||
|
||||
This map tracks the total voting power spent by a voter across all liquidity pools in a given Surge round.
|
||||
|
||||
### `campaign-pool-votes-by-voter`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint, voter: principal } → uint` |
|
||||
|
||||
This map records the number of votes a specific voter has allocated to a particular liquidity pool within a Surge round. It is primarily used to calculate project rewards.
|
||||
|
||||
### `campaign-pool-votes-for-project-reward`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint } → uint` |
|
||||
|
||||
This map stores the total number of votes received by a liquidity pool in a Surge round, specifically for the calculation of project rewards.
|
||||
|
||||
### `campaign-pool-votes-for-alex-reward`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint } → uint` |
|
||||
|
||||
This map tracks the total number of votes received by a liquidity pool in a Surge round, specifically for the $ALEX reward distribution.
|
||||
|
||||
### `campaign-vote-rewards-claimed`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Map | `{ campaign-id: uint, pool-id: uint, voter: principal } → bool` |
|
||||
|
||||
This map tracks whether a voter has claimed their voter rewards for a specific pool in a Surge round.
|
||||
|
||||
## Contract calls
|
||||
- `executor-dao`: calls are made to verify whether a certain contract-caller is designated as an extension.
|
||||
- `token-alex`: this contract is called to mint and transfer $ALEX rewards to liquidity providers when they unstake.
|
||||
- `token-wlialex`: this contract is called to retrieve the $LiALEX balance of a voter at the snapshot block to calculate their voting power.
|
||||
- `auto-alex-v3-wrapped`: this contract is necessary for user's voting power calculations.
|
||||
- `alex-staking-v2`: this contract is called to retrieve a user's manually staked $ALEX balance, which is included in the calculation of their total voting power.
|
||||
- `token-amm-pool-v2-01`: this contract is called to transfer staked LP tokens during the staking process and to return them when users unstake. It is also used to validate reward token compatibility when adding voter rewards.
|
||||
- `amm-pool-v2-01`: this contract is called to transfer staked LP tokens during the staking process and to return them when users unstake. It is also used to retrieve LP token balances and total supply when calculating a user's voting power.
|
||||
- `reward-token-trait`: this trait represents the fungible tokens used for distributing staking and voter rewards. It follows the `SIP-010` standard.
|
||||
- `reward-token-x-trait`: this trait refers to one of the two possible reward tokens in a liquidity pool.
|
||||
- `reward-token-y-trait`: this trait refers to one of the two possible reward tokens in a liquidity pool.
|
||||
- Tokens (`token-trait`): this trait is used to interact with fungible tokens when transferring staking deposits, rewards, and voter incentives. It is a customized version of Stacks' standard definition for Fungible Tokens (`sip-010`), with support for 8-digit fixed notation.
|
||||
- `amm-registry-v2-01`: this contract is called to retrieve data about a liquidity pool. It is used in the calculation of LP voting power.
|
||||
- `alex-farming`: this contract is called to retrieve staking information for users who have deposited LP tokens into the Alex Farming system. It is used to calculate LP voting power.
|
||||
|
||||
## Errors
|
||||
|
||||
| Error Name | Value |
|
||||
| ---------------- | ------------- |
|
||||
| `err-not-authorized` | `(err u1000)` |
|
||||
| `err-get-block-info` | `(err u1001)` |
|
||||
| `err-invalid-campaign-registration` | `(err u1002)` |
|
||||
| `err-invalid-campaign-id` | `(err u1003)` |
|
||||
| `err-registration-cutoff-passed` | `(err u1004)` |
|
||||
| `err-stake-cutoff-passed` | `(err u1005)` |
|
||||
| `err-campaign-not-ended` | `(err u1006)` |
|
||||
| `err-token-mismatch` | `(err u1007)` |
|
||||
| `err-invalid-input` | `(err u1008)` |
|
||||
| `err-invalid-reward-token` | `(err u1010)` |
|
||||
| `err-already-claimed` | `(err u1011)` |
|
||||
| `err-stake-end-passed` | `(err u1005)` |
|
||||
| `err-not-registered` | `(err u1013)` |
|
||||
| `err-revoke-disabled` | `(err u1014)` |
|
||||
| `err-registration-cutoff-not-passed` | `(err u1015)` |
|
||||
| `err-voting-cutoff-passed` | `(err u1016)` |
|
||||
| `err-pool-not-registered` | `(err u1017)` |
|
||||
| `err-pool-already-registered` | `(err u1018)` |
|
||||
@@ -0,0 +1,317 @@
|
||||
# self-listing-helper-v3a.clar
|
||||
|
||||
- Location: `./contracts/extensions/self-listing-helper-v3a.clar`
|
||||
- [Deployed contract](https://explorer.hiro.so/txid/SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.self-listing-helper-v3a?chain=mainnet)
|
||||
|
||||
The `self-listing-helper-v3a` contract enables the creation of trading pools on the ALEX DEX through two distinct mechanisms: a governance-controlled flow and a permissionless flow. In both cases, pools are formed by pairing a governance-approved anchor token (`token-x`) with a listed token (`token-y`), which is the asset being introduced for trading.
|
||||
|
||||
This dual approach gives projects the flexibility to choose between a guided listing process or a fully autonomous, on-chain setup — all while using the same core infrastructure.
|
||||
|
||||
## Permissioned
|
||||
|
||||
Pools can be created by following a guided process through the [ALEX Lab UI](https://app.alexlab.co/self-service-listing). The user supplies a `token-y` that must be pre-approved by governance before the pool can be initialized.
|
||||
|
||||
## Permissionless
|
||||
|
||||
Users can list a new `token-y` without prior approval by deploying a wrapper contract that matches a governance-approved template. The contract includes a verification system, based on the [`clarity-stacks`](https://github.com/MarvinJanssen/clarity-stacks) library, that reconstructs and validates the original deployment transaction using Merkle proofs and block data. Once verification succeeds, the token is dynamically approved and the pool is created.
|
||||
|
||||
## Additional Capabilities
|
||||
|
||||
The contract also supports:
|
||||
|
||||
- Liquidity locking or burning for pool integrity
|
||||
- On-chain parameter configuration (fees, oracles, thresholds)
|
||||
- Governance-controlled token approvals
|
||||
- Rebates management for AMM incentives
|
||||
|
||||
## Features
|
||||
|
||||
### Public
|
||||
|
||||
#### `create`
|
||||
|
||||
Permissioned pool creation. The listed token (`token-y`) must be pre-approved to initiate the process.
|
||||
|
||||
The function first runs validation checks via [`pre-check`](#pre-check), which ensures the anchor token (`token-x`) is approved and that the caller provides sufficient liquidity. It also checks that no existing pool with the given token pair and `factor` already exists.
|
||||
|
||||
Next, it verifies that the listing token has a reserve in the `amm-vault-v2-01` contract, which serves as a proxy for its approval status.
|
||||
|
||||
If all validations pass, the function calls [`post-check`](#post-check), which:
|
||||
|
||||
- Creates the new pool on `amm-pool-v2-01`
|
||||
- Configures its parameters (fees, thresholds, oracle)
|
||||
- Applies LP token lock or burn rules via `liquidity-locker` if requested
|
||||
|
||||
The function emits a print log with the full pool configuration for transparency.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `request-details` | `{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) }` |
|
||||
|
||||
#### `create2`
|
||||
|
||||
Permissionless pool creation. The pool is created in a single transaction using a wrapper contract that matches an approved template and includes on-chain verification data.
|
||||
|
||||
The function begins by validating the request with [`pre-check`](#pre-check). It then calls `verify-deploy`, which:
|
||||
|
||||
- Reconstructs the transaction ID based on the deployment parameters
|
||||
- Validates that the contract was mined using a Merkle proof and block data
|
||||
- Ensures the code matches the wrapper template stored in this contract
|
||||
|
||||
If verification succeeds, the wrapper is stored in `wrap-token-map`, and `token-y` is dynamically approved via `amm-vault-v2-01.set-approved-token`.
|
||||
|
||||
Finally, [`post-check`](#post-check) is executed to create the pool and configure its parameters. The function emits a print log with both the request and verification details.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `request-details` | `{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) }` |
|
||||
| `verify-params` | `{ nonce: (buff 8), fee-rate: (buff 8), signature: (buff 65), contract: principal, token-y: principal, proof: { tx-index: uint, hashes: (list 14 (buff 32)), tree-depth: uint }, tx-block-height: uint, block-header-without-signer-signatures: (buff 712) }` |
|
||||
|
||||
#### `lock-liquidity`
|
||||
|
||||
This function locks a specified amount of LP tokens for a given pool. It is typically used immediately after a pool is created, when the creator chooses to lock the initial liquidity to signal trust to other users.
|
||||
|
||||
Internally, it calls the `lock-liquidity` function of the `liquidity-locker` contract. That contract:
|
||||
|
||||
- Transfers the LP tokens from the caller to its own custody
|
||||
- Records the locked amount and sets an unlock block height (default: ~6 months)
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ------ |
|
||||
| `amount` | `uint` |
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
#### `burn-liquidity`
|
||||
|
||||
This function allows the caller to burn a specified amount of LP tokens from a given pool. It is one of the options available when configuring the pool after creation, typically used to make the initial liquidity permanently inaccessible.
|
||||
|
||||
Internally, it calls the `burn-liquidity` function of the `liquidity-locker` contract. That contract:
|
||||
|
||||
- Calls the `burn-fixed` function on the pool contract to destroy the LP tokens
|
||||
- Updates the internal `burnt-liquidity` record for that pool
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ------ |
|
||||
| `amount` | `uint` |
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
#### `claim-liquidity`
|
||||
|
||||
This function allows users to reclaim their previously locked LP tokens after the lock period has expired.
|
||||
|
||||
Internally, it calls the `claim-liquidity` function from the `liquidity-locker` contract. That contract:
|
||||
|
||||
- Checks that the caller has a non-zero locked amount
|
||||
- Verifies that the current block is past the `end-burn-block` set during locking
|
||||
- Transfers the LP tokens back to the user
|
||||
- Deletes the corresponding lock record
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ------ |
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
### Governance Features
|
||||
|
||||
#### `is-dao-or-extension`
|
||||
|
||||
This standard protocol function checks whether a caller (`tx-sender`) is the DAO executor or an authorized extension, delegating the extensions check to the `executor-dao` contract.
|
||||
|
||||
#### `approve-token-x`
|
||||
|
||||
A public function, governed through `is-dao-or-extension`, that sets the approval status and minimum required balance for a token to be used as the anchor token (`token-x`) in pool creation.
|
||||
|
||||
This function updates the `approved-token-x` map, enabling the protocol to define which tokens can serve as anchors and to enforce a minimum contribution threshold (`min-x`) for those tokens.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ---------- | ----------- |
|
||||
| `token` | `principal` |
|
||||
| `approved` | `bool` |
|
||||
| `min-x` | `uint` |
|
||||
|
||||
#### `set-fee-rebate`
|
||||
|
||||
A public function, governed through `is-dao-or-extension`, that sets the default fee rebate value used during pool creation.
|
||||
|
||||
This value is stored locally in the contract and passed as an argument to the `set-fee-rebate` function of the `amm-registry-v2-01` contract when a new pool is initialized.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ---------------- | ------ |
|
||||
| `new-fee-rebate` | `uint` |
|
||||
|
||||
#### `set-wrapped-token-template`
|
||||
|
||||
A public function, governed through `is-dao-or-extension`, that sets the reference template used to validate wrapper token contracts during permissionless pool creation.
|
||||
|
||||
The `wrapped-token-template` is a list of code segments (as ASCII strings) that represent the expected body of a compliant wrapper contract. When a user submits a deployment proof via `create2`, this template is used to reconstruct the expected code and verify that the deployed contract matches it exactly.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| -------------- | ------------------------------- |
|
||||
| `new-template` | `(list 20 (string-ascii 5000))` |
|
||||
|
||||
### Getters
|
||||
|
||||
#### `get-approved-token-x-or-default`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ----------- |
|
||||
| `token-x` | `principal` |
|
||||
|
||||
#### `get-fee-rebate`
|
||||
|
||||
#### `get-lock-period`
|
||||
|
||||
#### `get-locked-liquidity-or-default`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ----------- |
|
||||
| `owner` | `principal` |
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
#### `get-locked-liquidity-for-pool-or-default`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ------ |
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
#### `get-burnt-liquidity-or-default`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| --------- | ------ |
|
||||
| `pool-id` | `uint` |
|
||||
|
||||
#### `get-wrapped-token-contract-code`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ------- | ----------- |
|
||||
| `token` | `principal` |
|
||||
|
||||
### Relevant internal functions
|
||||
|
||||
#### `pre-check`
|
||||
|
||||
This private function performs validations prior to pool creation in both permissioned and permissionless flows.
|
||||
|
||||
It verifies that:
|
||||
|
||||
- The `token-x` is approved and has sufficient balance (`bal-x`).
|
||||
- A pool with the given pair and factor does not already exist (in either order).
|
||||
- The provided `lock` parameter is valid (`NONE`, `LOCK`, or `BURN`).
|
||||
|
||||
It retrieves the approval and minimum balance requirements from the internal `approved-token-x` map and interacts with the `amm-pool-v2-01` contract to check pool existence.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `request-details` | `{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) }` |
|
||||
|
||||
#### `post-check`
|
||||
|
||||
This private function finalizes pool creation by initializing the AMM pool and applying additional configuration parameters.
|
||||
|
||||
It performs the following actions:
|
||||
|
||||
- Calls the `create-pool` function from the `.amm-pool-v2-01` contract to initialize the pool with the provided liquidity amounts.
|
||||
- If the `lock` is set to `LOCK`, it calls `lock-liquidity` from the `liquidity-locker` contract to lock the initial LP tokens.
|
||||
- If the `lock` is set to `BURN`, it calls `burn-liquidity` from the `liquidity-locker` contract instead.
|
||||
- It applies pool parameters like fee rates, max ratios, thresholds, oracle settings, and the `start-block` by calling their respective setter functions in the `amm-pool-v2-01` contract.
|
||||
- Finally, it applies the global fee rebate for the pool by calling `set-fee-rebate` from the `amm-registry-v2-01` contract.
|
||||
|
||||
This function is used after both `create` and `create2` to complete the pool setup.
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `request-details` | `{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) }` |
|
||||
|
||||
## Storage
|
||||
|
||||
### `wrapped-token-template`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ----------------------------- |
|
||||
| Variable | `list 20 (string-ascii 5000)` |
|
||||
|
||||
A list of strings that define the expected code template for a valid wrapper token contract. Each entry represents a fragment of the full contract body, and the full code is reconstructed by concatenating these parts with the listed token's contract address.
|
||||
|
||||
This template is used during permissionless pool creation (`create2`) to verify that a wrapper contract deployed by a user matches the expected safe implementation.
|
||||
|
||||
### `approved-token-x`
|
||||
|
||||
| Data | Type |
|
||||
| ---- | ---------------------------------------------- |
|
||||
| Map | `principal => { approved: bool, min-x: uint }` |
|
||||
|
||||
A map that stores the approval status and minimum liquidity threshold for tokens used as `token-x` (anchor token) in pool creation. This validation is applied in both permissioned and permissionless listing flows.
|
||||
|
||||
### `fee-rebate`
|
||||
|
||||
| Data | Type |
|
||||
| -------- | ------ |
|
||||
| Variable | `uint` |
|
||||
|
||||
A global rebate value that is assigned to newly created pools. This value is passed to the `amm-registry-v2-01` contract during pool setup, where it determines the protocol fee discount applied to the pool.
|
||||
|
||||
### `wrap-token-map`
|
||||
|
||||
| Data | Type |
|
||||
| ---- | ------------------------ |
|
||||
| Map | `principal => principal` |
|
||||
|
||||
A map that links a listed token (`token-y`) to its corresponding verified wrapper contract.
|
||||
It is only populated during the permissionless listing flow, once the deployment proof is validated.
|
||||
This allows the AMM system to recognize and route trades through the correct wrapper contract.
|
||||
|
||||
## Contract calls
|
||||
|
||||
- `executor-dao`: calls are made to verify whether a certain contract-caller is designated as an extension.
|
||||
- `liquidity-locker`: this contract is used to manage post-creation liquidity settings. It allows the contract to lock, burn, or later claim LP tokens based on the pool creator’s configuration.
|
||||
- `clarity-stacks`: this contract is used to verify that a wrapper contract was properly deployed on the Stacks blockchain. It checks that the contract was mined and included in a valid block. This system is built on top of Marvin Janssen’s [`clarity-stacks`](https://github.com/MarvinJanssen/clarity-stacks) proof framework.
|
||||
- `clarity-stacks-helper`: this contract is called to convert a Clarity string into its consensus-encoded buffer format.
|
||||
- `amm-vault-v2-01`: this contract is called to verify that `token-y` has reserves before pool creation and to approve it in the permissionless listing flow after successful wrapper verification.
|
||||
- `amm-pool-v2-01`: this contract is used to validate pool existence, create new trading pools, and configure pool parameters such as fees, slippage thresholds, oracles, and start block.
|
||||
- `amm-registry-v2-01`: this contract is called during pool creation to assign the fee rebate configuration for the newly created pool.
|
||||
|
||||
## Errors
|
||||
|
||||
| Error Name | Value |
|
||||
| ------------------------------- | ------------- |
|
||||
| `err-not-authorised` | `(err u1000)` |
|
||||
| `err-token-not-approved` | `(err u1002)` |
|
||||
| `err-insufficient-balance` | `(err u1003)` |
|
||||
| `err-pool-exists` | `(err u1004)` |
|
||||
| `err-invalid-lock-parameter` | `(err u1005)` |
|
||||
| `err-invalid-length-nonce` | `(err u2000)` |
|
||||
| `err-invalid-length-fee` | `(err u2001)` |
|
||||
| `err-invalid-length-signature` | `(err u2002)` |
|
||||
| `err-invalid-principal-version` | `(err u2003)` |
|
||||
| `err-principal-not-contract` | `(err u2004)` |
|
||||
|
||||
<!-- Documentation Contract Template v0.1.1 -->
|
||||
103
developers/faq.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# FAQ
|
||||
|
||||
## Why Stacks?
|
||||
|
||||
Stacks makes Bitcoin programmable, enabling decentralized apps and smart contracts that inherit all of Bitcoin’s powers. Back-of-envelope calculation tells us that the DeFi market on Bitcoin could be as big as $300bn. ALEX will be part of it. We are one of the first DeFi projects on Stacks. And we are building the DeFi primitives essential to more sophisticated DeFi projects.
|
||||
|
||||
For example, with ALEX on Stacks, Bitcoin holders will be able to lend and borrow Bitcoin with better user experience at a more competitive rate. Bitcoin traders can build sophisticated services and strategies on ALEX to provide liquidity and participate in yield farming across multiple pools available at ALEX. Start-ups can issue tokens and raise Bitcoin on ALEX to build better community-owned projects with low capital requirements from the team.
|
||||
|
||||
## What is Yield Token?
|
||||
|
||||
Yield Token, for example, yield-BTC-2020sep30, is like a "certificate of deposit" on BTC that pays a fixed interest to its holder at a pre-defined maturity \(that is, Sep 30, 2020\).
|
||||
|
||||
## What is Collateral Rebalancing Pool?
|
||||
|
||||
Collateral Rebalancing Pool \("CRP"\) uses [Weighted Equation](https://docs.alexgo.io/protocol/platform-architecture-that-supports-ecosystem-development) and dynamically rebalances between Token and Collateral.
|
||||
|
||||
CRP dynamically rebalances collateral to ensure the ayToken minted \(i.e. the loan\) remain solvent especially in an adverse market environment \(i.e. the value of the loan does not exceed the value of collateral\). This dynamic rebalancing, together with a careful choice of the key parameters \(including LTV and volatilty assumption\) allows ALEX to eliminate the needs for liquidation. Any residual gap risk \(which CRP cannot address entirely\) is addressed through maintaining a strong reserve fund.
|
||||
|
||||
## What is Liquidity Bootstrapping Pool?
|
||||
|
||||
Liquidity Bootstrapping Pool \("LBP"\) uses [Weighted Equation](https://docs.alexgo.io/protocol/platform-architecture-that-supports-ecosystem-development) and is designed to facilitate a capital efficient launch of a token \(the "Base Token"\) relative to another token \(the "Target Token"\).
|
||||
|
||||
LBP was first offered by [Balancer](https://docs.balancer.fi/v/v1/guides/smart-pool-templates-gui/liquidity-bootstrapping-pool) in 2020 and can be an interesting alternative to ICOs, IDOs or IEOs to bootstrap liquidity with little initial investment from the team.
|
||||
|
||||
ALEX brings LBP to Stacks, allowing Stacks projects to build deep liquidity and find its price efficiently with low capital requirements.
|
||||
|
||||
LBPs can result in a significantly better-funded project whose governance tokens are more evenly distributed among the community. This means the tokens remain in the hands of those that are invested in the project in the long term, instead of speculators looking for quick profits.
|
||||
|
||||
## How does Stacks allow much better DeFi user experience for Bitcoin holders?
|
||||
|
||||
Currently for a Bitcoin holders to use DeFi on Ethereum, he/she needs to “wrap” his/her Bitcoin.
|
||||
|
||||
This means:
|
||||
|
||||
1. The Bitcoin holder needs to find a WBTC merchant,
|
||||
2. Opens an account subject to KYC/AML,
|
||||
3. Transfer BTC to the merchant,
|
||||
4. The merchant then goes to a WBTC custodian,
|
||||
5. Transfers BTC to the custodian,
|
||||
6. The custodian mints/transfers WBTC to the custodian,
|
||||
7. The custodian transfers WBTC to the holder,
|
||||
8. Now the holder can use WBTC to use DeFi on Ethereum.
|
||||
|
||||
On Stacks, the same Bitcoin holder would do the following:
|
||||
|
||||
1. The Bitcoin holder uses his/her BTC to use DeFi on Stacks.
|
||||
2. \(and that’s it!\)
|
||||
|
||||
The key technical difference between Stacks and Ethereum, that allows Stacks to do the above, is that Stacks has a read access to Bitcoin blockchain state \(something not possible on Ethereum\).
|
||||
|
||||
So smart contracts written on Stacks can see BTC being locked and issue “wrapped” BTC, which can then be used freely on Stacks.
|
||||
|
||||
Such a “wrapping” of BTC on Stacks, however, is done by a smart contract and does not affect the holder’s user experience \(i.e. that process is invisible to him/her\).
|
||||
|
||||
So from the user experience perspective, you are almost natively accessing Bitcoin on Stacks.
|
||||
|
||||
Compared to using WBTC on ETH, a Bitcoin holder, therefore, is not subject to:
|
||||
|
||||
* Intermediary risk \(of WBTC merchant and custodian\),
|
||||
* KYC/AML process \(duplicate/redundant for many, if not most, existing BTC holders\), and
|
||||
* Costs \(which can be expensive\) to convert from BTC to WBTC and vice versa.
|
||||
|
||||
## What tokens can and will ALEX support?
|
||||
|
||||
ALEX will support all native/SIP10-compatible tokens on Stacks.
|
||||
|
||||
## Who are the key actors on ALEX?
|
||||
|
||||
There are five actors on ALEX:
|
||||
|
||||
* **Lender**: Lender deposits tokens at fixed yield for a fixed term.
|
||||
* **Borrower**: Borrower posts collateral and borrows tokens at a fixed ield for a fixed term.
|
||||
* **Liquidity Provider**: Liquidity Provider provides liquidity and ensures smooth functioning of pools at ALEX
|
||||
* **Arbitrageur**: Arbitrageurs work with Liquidity Providers to ensure smooth functioning of pools at ALEX.
|
||||
|
||||
See[ Use Case](https://docs.alexgo.io/developers/smart-contracts/diagrams/protocol-use-case).
|
||||
|
||||
## What Collateralization Ratio \(or Loan-to-Value\) can we expect on ALEX?
|
||||
|
||||
While details are being finalized, we can expect, for example, a collateralization ratio of 1.25x \(i.e. 80% LTV\) for a BTC loan against USD stablecoin collateral.
|
||||
|
||||
Further, lending and borrowing on ALEX will not be subject to liquidation risk.
|
||||
|
||||
All of this is made possible by our [Collateral Rebalancing Pool](protocol/collateral-rebalancing-pool.md), which dynamically rebalances between borrowed token and collateral to manage the default risk.
|
||||
|
||||
## What kind of transaction fee and speed do you require?
|
||||
|
||||
The design of our [Collateral Rebalancing Pool ](https://docs.alexgo.io/protocol/collateral-rebalancing-pool)requires low transaction fee. The transaction fee on Stacks at the moment is negligible.
|
||||
|
||||
The Bitcoin block time is too slow to support decentralized apps like ALEX. To work around Bitcoin's limited speed, Stacks uses microblocks that result in near-instant confirmation on the Stacks blockchain. At the rate of the Bitcoin block time, these blocks will settle from Stacks to Bitcoin to provide the finality and security of Bitcoin.
|
||||
|
||||
Scaling independently of Bitcoin ensures that Stacks transactions are fast enough for ALEX, while still benefiting from Bitcoin’s security and settlement.
|
||||
|
||||
## Will you provide cross chain capability?
|
||||
|
||||
Yes, we will develop cross chain capability in the future. Our [core architecture](https://docs.alexgo.io/protocol/platform-architecture-that-supports-ecosystem-development) is not tied to Stacks.
|
||||
|
||||
## What’s your borrowing rate right now?
|
||||
|
||||
Our lending and borrowing rates are [market driven](https://docs.alexgo.io/protocol/automated-market-making-designed-for-lending-protocols).
|
||||
|
||||
|
||||
|
||||
72
developers/launchpad/using-the-launchpad.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Using the Launchpad
|
||||
|
||||
## Deployment
|
||||
|
||||
[https://explorer.hiro.so/txid/SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-launchpad-v1-1?chain=mainnet](https://explorer.hiro.so/txid/SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.alex-launchpad-v1-1?chain=mainnet)
|
||||
|
||||
## Listing
|
||||
|
||||
`contract-owner` calls `create-pool` with the following parameters.
|
||||
|
||||
* `launch-token-trait` : the trait reference of `project token` (e.g. ALEX)
|
||||
* `payment-token-trait` : trait reference of `payment token` (e.g. sUSDT)
|
||||
* `launch-owner` : address of the project that launches the `project token`
|
||||
* `launch-tokens-per-ticket` : number of `project token` per `ticket`
|
||||
* `price-per-ticket-in-fixed` : `payment token` deposit required per `ticket` (in 8-digit fixed notation)
|
||||
* `activation-threshold` : number of tickets required to activate the launch
|
||||
* `registration-start-height` : start (inclusive) block-height of registration period
|
||||
* `registration-end-height` : end (inclusive) block-height of registration period
|
||||
* `claim-end-height` : end (inclusive) block-height of claim (i.e. lottery) period
|
||||
* `apower-per-ticket-in-fixed` : `apower` required for each `ticket` (can be a list, in 8-digit fixed notation)
|
||||
* `registration-max-tickets` : maximum number of `ticket` an address can register
|
||||
* `fee-per-ticket-in-fixed` : listing `fee` charged by the platform as percentage of `price-per-ticket-in-fixed` (in 8-digit fixed notation)
|
||||
|
||||
**Launch price** of `project token` in `payment token` = `launch-tokens-per-ticket` / `price-per-ticket-in-fixed`
|
||||
|
||||
## Project Token Transfer
|
||||
|
||||
Once the pool is created, and before the registration period starts, `launch-owner` must call `add-to-position` with the following parameters:
|
||||
|
||||
* `launch-id` : id of the launch
|
||||
* `tickets` : number of `tickets` `launch-owner` wants to allocate to
|
||||
* `launch-token-trait` : trait reference of `project token`
|
||||
|
||||
**Total raise** for `project token` = `tickets` x `launch-tokens-per-ticket` x Launch price of `token`.
|
||||
|
||||
Upon calling `add-to-position`, (`tickets` x `launch-tokens-per-ticket`) of `project token` will be transferred from `launch-owner` to the contract.
|
||||
|
||||
## Registration
|
||||
|
||||
Participants call `register` with the following parameters:
|
||||
|
||||
* `launch-id` : id of the launch
|
||||
* `tickets` : number of `ticket` the participant wants to register
|
||||
* `payment-token-trait` : trait reference of `payment token`
|
||||
|
||||
Assuming (1) registration period has started, (2) registration period has not ended and (3) the participant is not already registered, the contract will register the participant and:
|
||||
|
||||
* burn the required number of `apower` from the participant's wallet, and
|
||||
* transfer `tickets` x `price-per-ticket-in-fixed` of `payment token` from the participant's wallet to the contract.
|
||||
|
||||
## Lottery
|
||||
|
||||
The lottery will be drawn one block after the registration ended. The claim/lottery period ends at `claim-end` block-height.
|
||||
|
||||
`contract-owner` or `launch-owner` will draw the lottery off-chain using the [prescribed rule](what-is-the-launchpad.md#e255) and call `claim` repeatedly with the following parameters
|
||||
|
||||
* `launch-id` : id of the launch
|
||||
* `input` : list of participants who won the lottery (up to 200)
|
||||
* `launch-token-trait` : trait reference of `project token`
|
||||
* `payment-token-trait` : trait reference of `payment token`
|
||||
|
||||
Upon calling `claim`, assuming (1) registration period has ended, (2) not all tickets are already won, (3) the launch is activated and (4) the claim/lottery period has not ended yet, the contract will verify the validity of `input` and
|
||||
|
||||
* transfer the proceeds of `payment token`, net of `fee`, to `launch-owner`,
|
||||
* transfer `fee` to the platform, and
|
||||
* transfer the appropriate number of `project token` to the winners.
|
||||
|
||||
Refund will be processed by either `contract-owner` or `launch-owner` in a similar manner to the claim.
|
||||
37
developers/launchpad/what-is-the-launchpad.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# What is the Launchpad
|
||||
|
||||
<figure><img src="../.gitbook/assets/image (4).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Every project needs a platform to launch their project tokens and our Launchpad is a lottery-based token launch platform that uses a hybrid off-chain / on-chain model.
|
||||
|
||||
All user funds related transactions are on chain. These include the submission of the Launch ticket together with the required payment tokens, the distribution or claim of the project tokens won, and the distribution or refund of the payment tokens in the case of not winning the lottery.
|
||||
|
||||
What is computationally expensive, i.e. the lottery drawing itself, is done off chain, but submitted to our on-chain contract for verification. The lottery drawing is also transparent and verifiable as it is based on the random seed available from the latest block height, i.e. anyone can independently verify the winners' table.
|
||||
|
||||
## Off-chain lottery system <a href="#e255" id="e255"></a>
|
||||
|
||||
Lottery system is based on a random number generator called “linear congruential generator”, which is [one of the oldest and best-known pseudorandom number generator algorithms](https://en.wikipedia.org/wiki/Linear\_congruential\_generator).
|
||||
|
||||
It starts by firstly drawing a verifiable random function seed (“seed”) from the Stacks block following the registration end. The seed is then
|
||||
|
||||
1. multiplied by a constant (_134775813_),
|
||||
2. added to another constant (_1_), and, finally,
|
||||
3. the modulus of its outcome by another constant (_4294967296_) is calculated to serve as the next random number.
|
||||
|
||||
This random number is then scaled by `maximum step size`, the ratio of the total number of registered tickets over the total number of tickets to be won (i.e. oversubscription ratio), multiplied by 1.5 times `walk resolution`.
|
||||
|
||||
This `maximum step size` helps ensure the fair-ness of the lottery system.
|
||||
|
||||
If a random number drawn falls between a particular `walk resolution` within a block that corresponds to a ticket held by a user, the ticket is determined to have won the lottery.
|
||||
|
||||
To generate the next random number, we move to the end of the `walk resolution` of the current random number, and draw another random number using the above linear congruential generator with the current random number as its seed.
|
||||
|
||||
The process is repeated until we reach the end of the chain, with the tickets upon whose corresponding `walk resolution` random numbers fell having won the lottery.
|
||||
|
||||
These “winners” are first determined off-chain, without the need for any on-chain events, thereby greatly increasing the overall efficiency of the lottery system.
|
||||
|
||||
## On-chain verification <a href="#a897" id="a897"></a>
|
||||
|
||||
In order to ensure these “winners” are not tempered with or generated in error, upon submission of the list to process claim (whereby the “winners” receive the project tokens) and refund, the contract verifies independently that the list is correct using the same process outlined above, before triggering on-chain events (i.e. processing claims and refunds).
|
||||
|
||||
This hybrid on-chain/off-chain lottery system therefore allows ALEX to create a Launchpad that combines the efficiency/speed of off-chain processing, while maintaining verifiability/immutability of on-chain processing.
|
||||
10
developers/orderbook/understanding-the-orderbook.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Understanding the Orderbook
|
||||
|
||||
Orderbook uses a hybrid on-chain/off-chain design, whereby a commitment to buy or sell certain asset is communicated in a cryptographically signed message, which is then matched by an off-chain matching engine before settling on-chain.
|
||||
|
||||
<figure><img src="../.gitbook/assets/Screenshot 2023-01-07 at 2.51.48 PM.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
127
developers/orderbook/using-the-orderbook.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
hidden: true
|
||||
---
|
||||
|
||||
# Using the Orderbook
|
||||
|
||||
ALEX Orderbook is available at [https://app.alexlab.co/orderbook](https://app.alexlab.co/orderbook).
|
||||
|
||||
## Register with the Orderbook
|
||||
|
||||
Users register with the Orderbook and deploy their own wallet to which they make deposits and withdrawals.
|
||||
|
||||
At the registration, users provide their public keys so the Orderbook can verify their signed orders.
|
||||
|
||||
## Place buy / sell orders gas-free
|
||||
|
||||
Users can place buy / sell orders of any tokens supported by the Orderbook without paying transaction fees. They can cancel orders any time. Orderbook ensures that the user wallet balance is sufficient.
|
||||
|
||||
All orders are signed by the originating users and the orders are validated with the users’ public keys before settlement.
|
||||
|
||||
## Orders are matched and confirmed
|
||||
|
||||
Order Matching Engine continuously matches buy and sell orders. Matched orders are sent to Exchange Contract.
|
||||
|
||||
## Orders are settled in aggregate
|
||||
|
||||
Exchange Contract validates the matched orders, aggregate them and settle in a single transaction. It updates the order fill, which is then used by Order Matching Engine to optimise the order matching.
|
||||
|
||||
## REST API
|
||||
|
||||
Once user registration is complete, you can use our REST API ([https://stxdx-api.alexlab.co/](https://stxdx-api.alexlab.co/)) to interact with the Orderbook.
|
||||
|
||||
For example, [b20-trading-bot](https://github.com/alexgo-io/b20-trading-bot) uses our API to automate grid trading on the Orderbook.
|
||||
|
||||
For more details, please contract your ALEX representatives.
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/login" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts:getByPrincipal" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts/{uid}" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts/pnl/{uid}/today" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/assets" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts/{uid}:updateSettings" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts/{uid}:sendVerificationEmail" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts/{uid}:verifyEmail" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/accounts/{uid}/fund-history" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orders" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orders" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orders:make" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook/{market}" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orders/{order_hash}" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orders/{order_hash}:cancel" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orders:cancel_all" method="post" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook:tickers" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/fills" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook/{market}:fills" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook/{market}:trades" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook/{market}:trading-view" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook:overview" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
|
||||
{% swagger src="https://stxdx-api.alexlab.co/swagger-ui-json" path="/v1/orderbook/{market}:overview" method="get" %}
|
||||
[https://stxdx-api.alexlab.co/swagger-ui-json](https://stxdx-api.alexlab.co/swagger-ui-json)
|
||||
{% endswagger %}
|
||||
35
developers/orderbook/what-is-orderbook.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# What is the Orderbook?
|
||||
|
||||
<figure><img src="../.gitbook/assets/image (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Orderbook is ALEX's scaling solution layer that brings **instant trade confirmation** to the security of Bitcoin.
|
||||
|
||||
Orderbook uses a hybrid on-chain/off-chain design, whereby a commitment to buy or sell certain asset is communicated in a cryptographically signed message, which is then matched by an off-chain matching engine before settling on-chain.
|
||||
|
||||
Orderbook is designed such that many types of market exchanges, not only a traditional CLOB but also an NFT marketplace or social trading, can be built on top.
|
||||
|
||||
## Why do we need the Orderbook? <a href="#cdf8" id="cdf8"></a>
|
||||
|
||||
Orderbook is ALEX's scaling solution layer that brings **instant trade confirmation** to the security of Bitcoin. Orderbook therefore addresses a key user experience issue our community has on Stocks - that the trade confirmation requires waiting of 10-15 minutes (along with Bitcoin block confirmation).
|
||||
|
||||
## What are the benefits of using the Orderbook?
|
||||
|
||||
There are a number of benefits for Bitcoin/Stacks users to use Orderbook to trade assets.
|
||||
|
||||
### Instant trade confirmation with Bitcoin finality
|
||||
|
||||
As we said earlier, Orderbook is our scaling solution layer that combines instant trade confirmation with Bitcoin finality. Orderbook therefore addresses a key user experience issue our community has on Stocks - that the trade confirmation requires waiting of 10-15 minutes (along with Bitcoin block confirmation).
|
||||
|
||||
### Gas-free orders
|
||||
|
||||
Orderbook uses a hybrid on-chain/off-chain design, whereby a commitment to buy or sell certain asset is communicated in a cryptographically signed message, which is then matched by an off-chain matching engine before settling on-chain.
|
||||
|
||||
This design means users of Orderbook can create/close orders gas-free and confirm their orders instantly without having to wait for the underlying block confirmation.
|
||||
|
||||
### Security of your assets
|
||||
|
||||
You have the full ownership and control of your assets on Orderbook. Zero credit risk.
|
||||
|
||||
### By developers, for developers
|
||||
|
||||
Ease and fun of development is at the core of Orderbook design. Orderbook is designed such that many types of market exchanges, not only a traditional CLOB but also an NFT marketplace or social trading, can be built on top.
|
||||
174
developers/whitepaper/automated-market-making-of-alex/README.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# Automated Market Making of Trading Pool
|
||||
|
||||
## Abstract
|
||||
|
||||
We introduce a new invariant function associated with generalised mean that underpins the ALEX AMM. ALEX builds DeFi primitives targeting developers looking to build ecosystem on Bitcoin, enabled by [Stacks](https://www.stacks.co/). With a suitable parameterisation, the invariant function supports both risky pairs (i.e. $$x y=L$$), stable pairs (i.e. $$x +y=L$$) and any linear combination in-between (i.e. Curve). We also show that our invariant function maps $$L$$ to the liquidity distribution of [Uniswap V3](https://uniswap.org/whitepaper-v3.pdf).
|
||||
|
||||
## Introduction
|
||||
|
||||
At ALEX, we build DeFi primitives targeting developers looking to build ecosystem on Bitcoin, enabled by [Stacks](https://www.stacks.co/). As such, we focus on trading, lending and borrowing of crypto assets with Bitcoin as the settlement layer and Stacks as the smart contract layer. At the core of this focus is the automated market making ("AMM") protocol, which allows users to exchange one crypto asset with another trustlessly. This paper focuses on technical aspects of AMM.
|
||||
|
||||
## AMM and Invariant Function
|
||||
|
||||
ALEX AMM is built on three beliefs: (i) it is mathematically neat and reflect economic demand and supply and (ii) it is a type of mean, like other AMMs.
|
||||
|
||||
We will firstly review some desirable features of AMM that ALEX hopes to exhibit.
|
||||
|
||||
### Properties of AMM
|
||||
|
||||
AMM protocol, which provides liquidity algorithmically, is the core engine of DeFi. In the liquidity pool, two or more assets are deposited and subsequently swapped resulting in both reserve and price movement. The protocol follows an invariant function $$f(X)=L$$, where $$X=\left(x_1,x_2,\dots,x_d\right)$$ is $$d$$ dimension representing $$d$$ assets and $$L$$ is constant. When $$d=2$$, which is the common practise by a range of protocols, AMM $$f(x_1,x_2)=L$$ can be expressed as $$x_2=g(x_1)$$. Although it is not always true, $$g$$ tends to be twice differentiable and satisfies the following
|
||||
|
||||
* monotonically decreasing, i.e. $$\frac{dg(x_1)}{dx_1}<0$$. This is because price is often defined as $$-\frac{dg(x_1)}{dx_1}$$. A decreasing function ensures price to be positive.
|
||||
* convex, i.e. $$\frac{d^2g(x_1)}{dx_1^2} \geq 0$$. This is equivalent to say that $$-\frac{dg(x_1)}{dx_1}$$ is a non-increasing function of $$x_1$$. It is within the expectation of economic theory of demand and supply, as more reserve of $$x_1$$ means declining price.
|
||||
|
||||
Meanwhile, $$f$$ can usually be interpreted as a form of mean, for example, [mStable](https://docs.mstable.org) relates to arithmetic mean, where $$x_1+x_2=L$$ (constant sum formula); one of the most popular platforms [Uniswap](https://uniswap.org/whitepaper-v3.pdf) relates to geometric mean, where $$x_1 x_2=L$$ (constant product formula); [Balancer](https://balancer.fi/whitepaper.pdf), which our [collateral rebalancing pool](../automated-market-making-of-collateral-rebalancing-pool.md) employs, applies weighted geometric mean. Its AMM is $$x_1^{w_1} x_2^{w_2}=L$$ where $$w_1$$ and $$w_2$$ are fixed weights. ALEX AMM extends these to create a generalised mean.
|
||||
|
||||
### ALEX AMM
|
||||
|
||||
After extensive research, we consider it possible for ALEX AMM to be connected to generalised mean defined as
|
||||
|
||||
$$
|
||||
\left( \frac{1}{d} \sum _{i=1}^{d} x_i^{p} \right)^{\frac{1}{p}}
|
||||
$$
|
||||
|
||||
where $$0 \leq p \leq 1$$. The expression might remind readers of $$p$$-norm when $$x_i \geq 0$$. It is however not true when $$p<1$$ as triangle inequality doesn't hold.
|
||||
|
||||
When $$d=2$$ and $$p=1-t$$ $$(0\leq t<1)$$ is fixed, the core component of generalised mean is assumed constant as below.
|
||||
|
||||
$$
|
||||
\begin{split}x_1^{1-t}+x_2^{1-t}&=L\\
|
||||
-\frac{dx_2}{dx_1}&=\left(\frac{x_2}{x_1} \right)^{t}\end{split}
|
||||
$$
|
||||
|
||||
This equation is regarded reasonable as AMM, because (i) function $$g$$ where $$x_2=g(x_1)$$ is monotonically decreasing and convex; and (ii) The boundary value of $$t=0$$ and $$t=1$$ corresponds to constant sum and constant product formula respectively. When $$t$$ decreases from 1 to 0, price $$-\frac{dg(x_1)}{x_1}$$ gradually converges to 1, i.e. the curve converges from constant product to constant sum (see [Appendix 1](./#appendix-1-generalised-mean-when-d-2) for the relevant proofs).
|
||||
|
||||
Though purely theoretical at this stage, [Appendix 2](./#appendix-2-liquidity-mapping-to-uniswap-v3) maps $$L$$ to the liquidity distribution of [Uniswap V3](https://uniswap.org/whitepaper-v3.pdf). This is motivated by an independent research from [Paradigm](https://www.paradigm.xyz/2021/06/uniswap-v3-the-universal-amm/).
|
||||
|
||||
## Trading Formulae
|
||||
|
||||
Market transaction, which involves exchange of one crypto asset and another, satisfies the invariant function. Please note the formulae do not account for the fee re-investment, which results in a slight increase of $$L$$ after each transaction, like _Uniswap V2_.
|
||||
|
||||
### Out-Given-In
|
||||
|
||||
In order to purchase $$\Delta y$$ amount of token Y from the pool, the buyer needs to deposit $$\Delta x$$ amount of token X. $$\Delta x$$ and $$\Delta y$$ satisfy the following
|
||||
|
||||
$$
|
||||
(x+\Delta x)^{1-t}+(y-\Delta y)^{1-t}=x^{1-t}+y^{1-t}
|
||||
$$
|
||||
|
||||
After each transaction, balance is updated as below: $$x\rightarrow x+\Delta x$$ and $$y\rightarrow y-\Delta y$$. Rearranging the formula results in
|
||||
|
||||
$$
|
||||
\Delta y=y-\left[x^{1-t}+y^{1-t}-(x+\Delta x)^{1-t}\right]^{\frac{1}{1-t}}
|
||||
$$
|
||||
|
||||
When transaction cost exists, the actual deposit to the pool is less than $$\Delta x$$. Assuming $$\lambda\Delta x$$ is the actual amount and $$(1-\lambda)\Delta x$$ is the fee, above can now be expressed as
|
||||
|
||||
$$
|
||||
\begin{split} &(x+\lambda\Delta x)^{1-t}+(y-\Delta y)^{1-t}=x^{1-t}+y^{1-t}\\ &\Delta y=y-\left[x^{1-t}+y^{1-t}-(x+\lambda\Delta x)^{1-t}\right]^{\frac{1}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
To keep $$L$$ constant, the updated balance is: $$x\rightarrow x+\lambda\Delta x$$ and $$y\rightarrow y-\Delta y$$.
|
||||
|
||||
### In-Given-Out
|
||||
|
||||
This is the opposite case to above. We are deriving $$\Delta x$$ from $$\Delta y$$.
|
||||
|
||||
$$
|
||||
\Delta x=\frac{1}{\lambda}{\left[x^{1-t}+y^{1-t}-(y-\Delta y)^{1-t}\right]^{\frac{1}{1-t}}-x}
|
||||
$$
|
||||
|
||||
### In-Given-Price
|
||||
|
||||
Sometimes, trader would like to adjust the price, perhaps due to deviation of AMM price to the market value. Define $$p'$$ the AMM price after rebalancing the token X and token Y in the pool
|
||||
|
||||
$$
|
||||
p'=\left(\frac{y-\Delta y}{x+\lambda\Delta x}\right)^{t}
|
||||
$$
|
||||
|
||||
Then, the added amount of $$\Delta x$$ can be calculated from the formula below
|
||||
|
||||
$$
|
||||
\begin{split} &(x+\lambda\Delta x)^{1-t}+(y-\Delta y)^{1-t}=x^{1-t}+y^{1-t}\\ &1+\left(\frac{y}{x}\right)^{1-t}=\left(1+\lambda\frac{\Delta x}{x}\right)^{1-t}+(\frac{y-\Delta y}{x})^{1-t}\\ &1+p^{\frac{1-t}{t}}=\left(1+\lambda\frac{\Delta x}{x}\right)^{1-t}+p'^{\frac{1-t}{t}}\left(1+\lambda\frac{\Delta x}{x}\right)^{1-t}\\ &\Delta x=\frac{x}{\lambda}\left[\left(\frac{1+p^{\frac{1-t}{t}}}{1+p'^{\frac{1-t}{t}}}\right)^{\frac{1}{1-t}}-1\right]\\ \end{split}
|
||||
$$
|
||||
|
||||
## Appendix 1: Generalised Mean when d=2
|
||||
|
||||
ALEX's invariant function is $$f(x_{1},x_{2};p)=x{_1}^{p}+x_{2}^{p}=L.$$ It can be rearranged as $$x{2}=g(x_{1})=(L-x_{1}^{p})^{\frac{1}{p}}$$. $$x_{1}$$ and $$x_{2}$$ should both be positive meaning the liquidity pool contains both tokens.
|
||||
|
||||
#### Theorem
|
||||
|
||||
When $$0<p<1$$, $$g\left(x_{1}\right)$$ is monotonically decreasing and convex.
|
||||
|
||||
#### Proof
|
||||
|
||||
This is equivalent to prove $$\frac{dg(x_{1})}{dx_{1}}<0$$ and $$\frac{d^{2}g(x_{1})}{dx_{1}^{2}}\geq0$$.
|
||||
|
||||
$$
|
||||
\begin{split} &\frac{dg(x_{1})}{dx_{1}}=\frac{1}{p}(L-x_{1}^{p})^{\frac{1}{p}-1}\left(-px_{1}^{p-1}\right)=-\left(\frac{L-x_{1}^{p}}{x_{1}^{p}}\right)^{\frac{1-p}{p}}<0\\ &\frac{d^{2}g(x_{1})}{dx_{1}^{2}}=-\frac{1-p}{p}\left(\frac{L-x_{1}^{p}}{x_{1}^{p}}\right)^{\frac{1-2p}{p}}\left[\frac{-px_{1}^{p-1}x_{1}^{p}-(L-x_{1}^{p})px^{p-1}}{x_{1}^{2}p}\right]\\ &=L(1-p)\left(\frac{x_{2}}{x_{1}}\right)^{1-2p}x_{1}^{-p-1}\geq0 \end{split}
|
||||
$$
|
||||
|
||||
The last inequality holds because each component is positive.
|
||||
|
||||
When $$p$$= 1, it is straightforward to see that the invariant function is constant sum. To show that the invariant function converges to constant product when $$p$$= 0, we will show and prove an established result in a generalised $$d$$ dimensional setting.
|
||||
|
||||
#### Theorem
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\left(\frac{1}{d}\sum_{i=1}^{d}x_{i}^{p}\right)^{\frac{1}{p}}=({\prod_{i=1}^{d}x_{i}})^{\frac{1}{d}}
|
||||
$$
|
||||
|
||||
#### Proof
|
||||
|
||||
$$\left(\frac{1}{d}\sum{i=1}^{d}x_{i}^{p}\right)^{\frac{1}{p}}=\text{exp}\left[\frac{\text{log}\left(\frac{1}{d}\sum{i=1}^{d}x_{i}^{p}\right)}{p}\right]$$. Applying _L'Hospital_ rule to the exponent, which is 0 in both denominator and nominator when $$p\rightarrow0$$, we have
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\frac{\text{log}\left(\frac{1}{d}\sum_{i=1}^{d}x_{i}^{p}\right)}{p}=\lim_{p\rightarrow0}\sum_{i=1}^{d}\frac{\text{log}(x_{i})}{\sum_{j=1}^{d}\left(\frac{x_{j}}{x_{i}}\right)^{p}}=\frac{\sum_{i=1}^{d}\text{log}(x_{i})}{d}
|
||||
$$
|
||||
|
||||
Therefore
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\left(\frac{1}{d}\sum_{i=1}^{d}x_{i}^{p}\right)^{\frac{1}{p}}=\lim_{p\rightarrow0}\text{exp}\frac{\sum_{i=1}^{d}\text{log}(x_{i})}{d}=({\prod_{i=1}^{d}x_{i}})^{\frac{1}{d}}
|
||||
$$
|
||||
|
||||
#### Corollary
|
||||
|
||||
When d = 2,
|
||||
|
||||
$$
|
||||
x_{1}x_{2}=\lim_{p\rightarrow0}\left[\frac{1}{2}(x_{1}^{p}+x_{2}^{p})\right]^{\frac{2}{p}}
|
||||
$$
|
||||
|
||||
Proof of the corollary is trivial, as it is a direct application of the theorem. It shows that generalised mean AMM implies constant product AMM when $$p\rightarrow0$$.
|
||||
|
||||
## Appendix 2: Liquidity Mapping to Uniswap v3
|
||||
|
||||
As Uniswap v3 is able to simulate liquidity curve of any AMM, we are interested in exploring the connection between ALEX's AMM and that of _Uniswap_'s. Interesting questions include: what is the shape of the liquidity distribution? Which point(s) has the highest liquidity? We acknowledge that the section is more of a theoretical study for now.
|
||||
|
||||
_Uniswap V3_ AMM can be expressed as a function of invariant constant $$L$$ with respect to price $$p$$, $$L_{\text{Uniswap}}=\frac{dy}{d\sqrt{p}}$$. For us, the difference in the invariant function means we can write price as $$p=e^{rt}$$ (or, equivalently, $$r=\frac{1}{t}\ln{p}$$ ) and we have
|
||||
|
||||
$$
|
||||
L_{\text{Uniswap}}=\frac{dy}{d\sqrt{p}}=\frac{2}{t}e^{-\frac{1}{2}rt}\frac{dy}{dr}
|
||||
$$
|
||||
|
||||
Based on the previous sections, we can then express $$y$$ as 
|
||||
|
||||
$$
|
||||
y=\left[\frac{L}{1+e^{-(1-t)r}}\right]^{\frac{1}{1-t}}
|
||||
$$
|
||||
|
||||
Therefore
|
||||
|
||||
$$
|
||||
\begin{split} &\frac{dy}{dr}=L^{\frac{1}{1-t}}\frac{e^{-(1-t)r}}{(1+e^{-(1-t)r})^{\frac{2-t}{1-t}}}\\ &L_{\text{Uniswap}}=\frac{2}{t}L^{\frac{1}{1-t}}\left(e^{\frac{r(1-t)}{2}}+e^{\frac{-r(1-t)}{2}}\right)^{\frac{-2+t}{1-t}}\\ &=\frac{2}{t}L^{\frac{1}{1-t}}\big\{2\cosh\left[\frac{r(1-t)}{2}\right]\big\}^{\frac{-2+t}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
 (2) (2) (2) (2) (2) (2) (1).png>)
|
||||
|
||||
Figure 1 plots $$L_{\text{Uniswap}}$$ against $$r$$ (which is proportional to $$p$$) regarding various levels of $$t$$. When $$0<t<1$$, $$L_{\text{Uniswap}}$$ is symmetric around 0% at which the maximum reaches . This is because
|
||||
|
||||
1. $$\cosh\left[(\frac{r(1-t)}{2})\right]$$ is symmetric around $$r$$= 0% with minimum at 0% and the minimum value 1;
|
||||
2. $$x^z$$ is a decreasing function of $$x$$ when $$x$$ is positive and power $$z$$ is negative. In our case, we have $$z=\frac{-2+t}{1-t}<-1$$. Therefore, it is the maximum rather than minimum that $$L_{\text{Uniswap}}$$ achieves at 0.
|
||||
|
||||
Furthermore, the higher the $$t$$, the flatter the liquidity distribution is. When $$t$$ approaches 1, i.e. AMM converges to the constant product formula, the liquidity distribution is close to a flat line. When $$t$$ approaches 0, the distribution concentrates around 0%.
|
||||
@@ -0,0 +1,365 @@
|
||||
# Automated Market Making of Yield Token Pool
|
||||
|
||||
## Abstract
|
||||
|
||||
ALEX aims to provide a fixed rate borrowing and lending service with pre-determined maturity in the world of decentralised finance (DeFi). We include forward contracts in our trading pool, with Automated Market Making (AMM) engine in association with generalised mean. While we formalise the trading practise swapping forward contracts with underlying asset, we incorporate the latest innovation in the industry - concentrated liquidity. Consequently, liquidity provider of ALEX can save decent amount of capital by making markets on a selected range of interest rate.
|
||||
|
||||
## Introduction
|
||||
|
||||
ALEX stands for **A**utomated **L**iquidity **EX**change. It is a hybrid of automated market making and on-chain loanable fund built on Stacks blockchain network. While lenders and borrowers can minimise uncertainty by securing the loan with fixed rate and tenor, liquidity providers are able to take advantage of our capital efficiency mechanism by imposing cap and floor on the interest rate. This allows liquidity to be offered on parts of the curve that contains majority of trading activities and leads to efficient capital management.
|
||||
|
||||
On ALEX, lending and borrowing activities are facilitated by a forward contract based token “ayToken”. It is similar to an OTC bilateral forward contract in the conventional financial market, which specifies underlying asset “Token” and expiry date. This paper assumes ayToken is minted and ready to be exchanged. Lenders purchase ayToken at a discount to the spot Token price when the contract is initiated and reclaim underlying asset upon expiration when forward price converges to spot price. Borrowers sell ayToken in return for Token on day one and return Token upon expiration. Implied interest rate depends on how much discount that the forward price is to the spot price at the time of transaction, which is executed on AMM.
|
||||
|
||||
Last but not least, ALEX hopes to bridge the gap between Defi and conventional finance by applying an AMM protocol derived from one of the basic instruments in fixed income market - zero coupon bond firstly proposed by [Yield Space](https://yield.is/YieldSpace.pdf). This empowers ALEX to learn from the fiat world and offer more decentralised financial products in the future.
|
||||
|
||||
This paper focuses on technical aspects of AMM and is the first of a series of ALEX papers unveiling all exciting features and applications of ALEX development.
|
||||
|
||||
## AMM and Invariant Function
|
||||
|
||||
ALEX AMM is built on three beliefs: (i) it is mathematically neat and reflect economic demand and supply; (ii) it is a type of mean, like other AMMs; and (iii) it is derived and can be interpreted in terms of yield and is somehow related to conventional finance, where research has been conducted for decades.
|
||||
|
||||
We will firstly review some desirable features of AMM that ALEX hopes to exhibit.
|
||||
|
||||
### Properties of AMM
|
||||
|
||||
AMM protocol, which provides liquidity algorithmically, is the core engine of Defi. In the liquidity pool, two or more assets are deposited and subsequently swapped resulting in both reserve and price movement. The protocol follows an invariant function $$f(X)=L$$, where $$X=\left(x_1,x_2,\dots,x_d\right)$$ is $$d$$ dimension representing $$d$$ assets and $$L$$ is constant. When $$d=2$$, which is the common practise by a range of protocols, AMM $$f(x_1,x_2)=L$$ can be expressed as $$x_2=g(x_1)$$. Although it is not always true, $$g$$ tends to be twice differentiable and satisfies the following
|
||||
|
||||
* monotonically decreasing, i.e. $$\frac{dg(x_1)}{dx_1}<0$$. This is because price is often defined as $$-\frac{dg(x_1)}{dx_1}$$. A decreasing function ensures price to be positive.
|
||||
* convex, i.e. $$\frac{d^2g(x_1)}{dx_1^2} \geq 0$$. This is equivalent to say that $$-\frac{dg(x_1)}{dx_1}$$ is a non-increasing function of $$x_1$$. It is within the expectation of economic theory of demand and supply, as more reserve of $$x_1$$ means declining price.
|
||||
|
||||
Meanwhile, $$f$$ can usually be interpreted as a form of mean, for example, [mStable](https://docs.mstable.org) relates to arithmetic mean, where $$x_1+x_2=L$$ (constant sum formula); one of the most popular platforms [Uniswap](https://uniswap.org/whitepaper-v3.pdf) relates to geometric mean, where $$x_1 x_2=L$$ (constant product formula); [Balancer](https://balancer.fi/whitepaper.pdf), which our collateral rebalancing pool employs, applies weighted geometric mean. Its AMM is $$x_1^{w_1} x_2^{w_2}=L$$ where $$w_1$$ and $$w_2$$ are fixed weights. However, none of these three protocols consider time to maturity, which is essential in modern interest rate theory.
|
||||
|
||||
### ALEX AMM
|
||||
|
||||
After extensive research, we consider it possible for ALEX AMM to be connected to generalised mean defined as
|
||||
|
||||
$$
|
||||
\left( \frac{1}{d} \sum _{i=1}^{d} x_i^p \right)^{\frac{1}{p}}
|
||||
$$
|
||||
|
||||
where $$0 \leq p \leq 1$$. The expression might remind readers of $$p$$-norm when $$x_i \geq 0$$. It is however not true when $$p<1$$ as triangle inequality doesn't hold.
|
||||
|
||||
When $$d=2$$ and $$p$$ is fixed, the core component of generalised mean is assumed constant as below.
|
||||
|
||||
$$
|
||||
x_1^p+x_2^p=L
|
||||
$$
|
||||
|
||||
This equation is regarded reasonable as AMM, because (i) function $$g$$ where $$x_2=g(x_1)$$ is monotonically decreasing and convex; and (ii) The boundary value of $$p=1$$ and $$p=0$$ corresponds to constant sum and constant product formula respectively. When $$p$$ increases from 0 to 1, price $$-\frac{dg(x_1)}{x_1}$$ gradually converges to 1. This is what ALEX hopes to achieve when forward becomes spot. This also means that $$p$$ is somehow related to time to maturity. Please refer to [Appendix 1](automated-market-making-of-alex.md#appendix-1-generalised-mean-when-d-2) for a detailed discussion.
|
||||
|
||||
In the benchmark research piece by [Yield Space](https://yield.is/YieldSpace.pdf), the invariant function above is formalised from the perspective of zero coupon bond. $$p$$ is replaced by $$1-t$$ where $$t$$ is time to maturity and $$L$$ is a function of $$t$$, so that
|
||||
|
||||
$$
|
||||
x_1^{1-t}+x_2^{1-t}=L\left(t\right)
|
||||
$$
|
||||
|
||||
This is derived by solving the following differential equation when $$t \neq 1$$
|
||||
|
||||
$$
|
||||
-\frac{dx_2}{dx_1}=\left(\frac{x_2}{x_1} \right)^t
|
||||
$$
|
||||
|
||||
In the rest of the paper, to be consistent with [Yield Space](https://yield.is/YieldSpace.pdf), we employ notations below
|
||||
|
||||
* $$x$$ : balance of the underlying Token
|
||||
* $$y$$ : balance of ayToken
|
||||
* $$r$$ : implied interest rate, defined as the natural logarithm of balance of ayToken and Token
|
||||
|
||||
$$
|
||||
r=log \left( \frac{y}{x} \right)
|
||||
$$
|
||||
|
||||
* $$p$$ : price of Token in terms of ayToken. The commonly quoted ayToken price is the inverse, i.e. $$\frac{1}{p}$$
|
||||
|
||||
$$
|
||||
p=\left(\frac{y}{x} \right)^t=e^{rt}
|
||||
$$
|
||||
|
||||
ALEX's implied interest rate is compound. Not only does the compound rate allow us to derive mathematical formulas throughout the paper, we can also conduct further research and offer more products by referring to vast amount of literatures and applications in conventional finance, which is largely built on Black-Scholes model with compound rate employed as the discounting factor.
|
||||
|
||||
Using notations above, the invariant function is rewritten as $$x^{1-t}+y^{1-t}=L$$ with the differential equation $$-\frac{dy}{dx}=\left(\frac{y}{x} \right)^t$$. Unless specified, we assume $$L$$ constant and call it invariant constant. This means that $$t$$ is fixed and there is no minting or burning coins. In practise, liquidity providers can add or reduce liquidity, and $$L$$ needs to be recalibrated daily when $$t$$ changes.
|
||||
|
||||
Though purely theoretical at this stage, [Appendix 2](automated-market-making-of-alex.md#appendix-2-liquidity-mapping-to-uniswap-v3) maps $$L$$ to the liquidity distribution of [Uniswap V3](https://uniswap.org/whitepaper-v3.pdf). This is motivated by an independent research from [Paradigm](https://www.paradigm.xyz/2021/06/uniswap-v3-the-universal-amm/).
|
||||
|
||||
## Trading Formulae
|
||||
|
||||
Market transaction, which involves exchange of Token and ayToken, satisfies the invariant function. While fee is deposited back to the liquidity pool in some protocols, such as _Uniswap V2_, resulting in slight increase of $$L$$ after each transaction, ALEX counts the fee separately. This is consistent with [Uniswap V3](https://uniswap.org/whitepaper-v3.pdf). Hence $$L$$ remains constant.
|
||||
|
||||
### Out-Given-In
|
||||
|
||||
In order to purchase $$\Delta y$$ amount of ayToken from the pool, the buyer needs to deposit $$\Delta x$$ amount of Token. $$\Delta x$$ and $$\Delta y$$ satisfy the following
|
||||
|
||||
$$
|
||||
(x+\Delta x)^{1-t}+(y-\Delta y)^{1-t}=x^{1-t}+y^{1-t}
|
||||
$$
|
||||
|
||||
After each transaction, balance is updated as below: $$x\rightarrow x+\Delta x$$ and $$y\rightarrow y-\Delta y$$. Balance of $$y$$ should not be less than that of $$x$$ to avoid negative interest rate, which will be discussed in detail later. Rearranging the formula results in
|
||||
|
||||
$$
|
||||
\Delta y=y-\left[x^{1-t}+y^{1-t}-(x+\Delta x)^{1-t}\right]^{\frac{1}{1-t}}
|
||||
$$
|
||||
|
||||
When transaction cost exists, the actual deposit to the pool is less than $$\Delta x$$. Assuming $$\lambda\Delta x$$ is the actual amount and $$(1-\lambda)\Delta x$$ is the fee, above can now be expressed as
|
||||
|
||||
$$
|
||||
\begin{split} &(x+\lambda\Delta x)^{1-t}+(y-\Delta y)^{1-t}=x^{1-t}+y^{1-t}\\ &\Delta y=y-\left[x^{1-t}+y^{1-t}-(x+\lambda\Delta x)^{1-t}\right]^{\frac{1}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
To keep $$L$$ constant, the updated balance is: $$x\rightarrow x+\lambda\Delta x$$ and $$y\rightarrow y-\Delta y$$.
|
||||
|
||||
### In-Given-Out
|
||||
|
||||
This is the opposite case to above. We are deriving $$\Delta x$$ from $$\Delta y$$.
|
||||
|
||||
$$
|
||||
\Delta x=\frac{1}{\lambda}{\left[x^{1-t}+y^{1-t}-(y-\Delta y)^{1-t}\right]^{\frac{1}{1-t}}-x}
|
||||
$$
|
||||
|
||||
### In-Given-Price / Yield
|
||||
|
||||
Sometimes, trader would like to adjust the price/yield, perhaps due to deviation of AMM price to the market value. Define $$p'$$ the AMM price after rebalancing the Token and ayToken in the pool
|
||||
|
||||
$$
|
||||
p'=\left(\frac{y-\Delta y}{x+\lambda\Delta x}\right)^{t}
|
||||
$$
|
||||
|
||||
Then, the added amount of $$\Delta x$$ can be calculated from the formula below
|
||||
|
||||
$$
|
||||
\begin{split} &(x+\lambda\Delta x)^{1-t}+(y-\Delta y)^{1-t}=x^{1-t}+y^{1-t}\\ &1+\left(\frac{y}{x}\right)^{1-t}=\left(1+\lambda\frac{\Delta x}{x}\right)^{1-t}+(\frac{y-\Delta y}{x})^{1-t}\\ &1+p^{\frac{1-t}{t}}=\left(1+\lambda\frac{\Delta x}{x}\right)^{1-t}+p'^{\frac{1-t}{t}}\left(1+\lambda\frac{\Delta x}{x}\right)^{1-t}\\ &\Delta x=\frac{x}{\lambda}\left[\left(\frac{1+p^{\frac{1-t}{t}}}{1+p'^{\frac{1-t}{t}}}\right)^{\frac{1}{1-t}}-1\right]\\ \end{split}
|
||||
$$
|
||||
|
||||
Denote $$r$$ and $$r'$$ the current and trader's target interest rate respectively. Because $$p=e^{rt}$$ and $$p'=e^{r't}$$, the above equation can also be rewritten as
|
||||
|
||||
$$
|
||||
\Delta x=\frac{x}{\lambda}\left[\left(\frac{1+e^{r(1-t)}}{1+e^{r'(1-t)}}\right)^{\frac{1}{1-t}}-1\right]
|
||||
$$
|
||||
|
||||
### Transaction Cost on Notional and Yield
|
||||
|
||||
In the previous sections, fee is in proportion to the notional amount. This is consistent with AMM such as _Uniswap_. However, it could be hard to interpret in the yield space, as market participants tend to think of borrowing or lending activity in terms of rate.
|
||||
|
||||
The formula below expresses $$\lambda$$ regarding bid/offer imposed on interest rate $$r$$, so that conversion in between the two is possible. Denote $$r_m$$ as the mid rate calculated from AMM
|
||||
|
||||
$$
|
||||
e^{r_m}=\frac{\Delta y}{\lambda\Delta x}
|
||||
$$
|
||||
|
||||
However, trader deposits $$\Delta x$$ rather than $$\lambda\Delta x$$. Therefore, the bid rate $$r_b$$ when purchasing ayToken satisfies
|
||||
|
||||
$$
|
||||
e^{r_b}=\frac{\Delta y}{\Delta x}
|
||||
$$
|
||||
|
||||
$$\Delta r_b=r_m-r_b$$ is then the fee charged to the purchaser in the yield space,
|
||||
|
||||
$$
|
||||
e^{\Delta r_b}=\frac{1}{\lambda}
|
||||
$$
|
||||
|
||||
Hence, $$\lambda$$ can be expressed as a function of $$\Delta r_b$$
|
||||
|
||||
$$
|
||||
\lambda=e^{-\Delta r_b}
|
||||
$$
|
||||
|
||||
Actual fee is $$1- \lambda=1-e^{-\Delta r_b} \approx \Delta r_b$$ using Taylor expansion to the first order. Thus $$\lambda \approx 1-\Delta r_b$$ .
|
||||
|
||||
It can be shown that the above equality also holds when redeeming ayToken for Token, except $$\Delta r_b$$ replaced by $$\Delta r_o=r_o-r_m$$, where $$e^{r_m}=\frac{\lambda\Delta y}{\Delta x}$$ and $$e^{r_o}=\frac{\Delta y}{\Delta x}$$. Here, $$r_o$$ is the offer rate when selling ayToken and $$\Delta r_o$$ is the corresponding fee charged to the seller in the yield space.
|
||||
|
||||
## Concentrated Liquidity
|
||||
|
||||
In the current setting, liquidity provider can make market on any rate between $$-\infty$$ to $$+\infty$$. However, market participants might wish to impose certain constraint, for example no negative interest rate. One solution is to set up bounds on $$\frac{y}{x}$$, which are related to the rate. In the case of positive rate, this means balance of ayToken always larger than Token. Although it solves the problem, the amount of ayToken lower than Token would be excluded from trading activities in any means. We are proposing an alternative approach by introducing virtual tokens.
|
||||
|
||||
Virtual tokens constitute part of the trading pool reserve that would never be touched hence underutilised. Liquidity providers should not be required to maintain this part of the pool and we are therefore set them as virtual. For example, when rate is floored at 0%, $$t$$= 0.5 and $$L$$= 20, liquidity providers will never face the situation of ayToken balance falling below 100, which can then be regarded as virtual to save the actual capital cost.
|
||||
|
||||
The idea is inspired by concentrated liquidity in _Uniswap v3_.
|
||||
|
||||
### Pool with interest rate floored at zero
|
||||
|
||||
This section only allows liquidity on non-negative interest rate. Concentrated liquidity is achieved by introducing virtual token reserves $$y_v$$, which satisfies
|
||||
|
||||
$$
|
||||
x^{1-t}+(y+y_{v})^{1-t}=L
|
||||
$$
|
||||
|
||||
Figure 1 illustrates the example above of $$t$$= 0.5 and $$L$$= 20 by displaying two sets of curves: Invariant Function Curve (“IFC") satisfying $$x^{1-t}+y^{1-t}=L$$ and Capital Efficiency Curve (“CEC") satisfying $$x^{1-t}+(y+y_v)^{1-t}=L$$. Intuitively CEC is attained by lowering IFC by $$y_v$$= 100.
|
||||
|
||||

|
||||
|
||||
#### Initialisation
|
||||
|
||||
Instead of contributing equal amount of Token and ayToken to initialise the pool with interest rate 0%, liquidity provider only needs to contribute x amount of Token. This is because virtual token $$y_v=x=\left(\frac{1}{2}L\right)^{\frac{1}{1-t}}$$.
|
||||
|
||||
#### Trading
|
||||
|
||||
Balance of Token and ayToken, including both actual and virtual, still satisfy the invariant function. However, once the actual ayToken is depleted and only Token is left in the pool, trading would be ceased until more ayToken is deposited.
|
||||
|
||||
#### Minting and Burning
|
||||
|
||||
Before liquidity expansion or reduction by minting or burning coins, assume that the old pool has Token $$x$$ and ayToken $$y$$ satisfying $$x^{1-t}+y^{1-t}=L$$, where $$y=y_a+y_v$$ and $$y_a$$ and $$y_v$$ are balance of actual and virtual ayToken respectively.
|
||||
|
||||
Minting and burning should not affect price and interest rate. This means that newly added or withdrawn coins would be in proportion to x and y. Denote new amount of Token and ayToken as $$x'=kx$$ and $$y'=ky$$ respectively. $$y'=y'_a+y'_v$$ where $$y'_a$$ is actual whereas $$y'_v$$ virtual. They satisfy the following
|
||||
|
||||
$$
|
||||
\begin{split} &y'_a+y'_v=ky\\ &2y'^{1-t}_v=k^{1-t}L \end{split}
|
||||
$$
|
||||
|
||||
Solution to the above equations is
|
||||
|
||||
$$
|
||||
\begin{split} &y'_{a}=ky-y'_{v}\\y'_{v} &=\left(\frac{1}{2}L\right)^{\frac{1}{1-t}}k \end{split}
|
||||
$$
|
||||
|
||||
This means $$y'_v=ky_v$$ and $$y'_a=ky_a$$.
|
||||
|
||||
#### Example
|
||||
|
||||
Assume $$t$$= 0.5. Rachel initialises a liquidity pool of 0% interest rate with 100 Token on CEC. Although there is no actual ayToken, 0% rate implies 100 virtual tokens and $$L$$= 20 on IFC.
|
||||
|
||||
Suppose Rachel then sells 50 ayToken to the pool on the same day. On IFC, this means ayToken amount of 150 (50 actual and 100 virtual) and the amount of 60.10 Token remaining on IFC.
|
||||
|
||||
Now suppose Billy wants to mint 10% of the liquidity pool. This means that Billy needs to deposit 6.01 (10% of 60.10) Token. Virtual balance is updated to $$\left(\frac{1}{2}\times20\right)^{\frac{1}{0.5}}\times1.1=110$$. Billy needs to deposit 5 ayToken ($$1.1\times150-110-50$$), so that the summation of actual and virtual ayToken is 165. Interest rate remains the same before and after Billy's participation. Note that both actual and virtual ayToken balance increase by 10%, which is the same proportion as the growth of liquidity pool.
|
||||
|
||||
### Range-bound Pool
|
||||
|
||||
The above section can be extended to any constraint pool with upper interest rate $$r_{u}$$ and lower interest rate $$r_{l}$$. If interest rate falls out of \[$$r_{l}$$,$$r_{u}$$], swapping would be suspended as one of the tokens would have been depleted.
|
||||
|
||||
Denote $$x_{a}$$, $$x_{v}$$, $$y_{a}$$ and $$y_{v}$$ balance of actual Token, virtual Token, actual ayToken and virtual ayToken respectively. They satisfy invariant function on IFC, i.e. $$(x{a}+x{v})^{1-t}+(y{a}+y{v})^{1-t}=L$$.
|
||||
|
||||
The amount of Token an ayToken can be expressed as a function of L and current interest rate $$r_{c}=\frac{y_{a}+y_{v}}{x_{a}+x_{v}}$$.
|
||||
|
||||
$$
|
||||
\begin{split} &x_{a}+x_{v}&=\left[\frac{L}{1+e^{(1-t)r_{c}}}\right]^{\frac{1}{1-t}}\\ &y_{a}+y_{v}&=\left[\frac{L}{1+e^{-(1-t)r_{c}}}\right]^{\frac{1}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
Intuitively, when $$r_{c}=r_{l}$$, ayToken is depleted; Similarly, when $$r_{c}=r_{u}$$, Token is used up. Therefore,
|
||||
|
||||
$$
|
||||
\begin{split} &x_{v}=\left[\frac{L}{1+e^{(1-t)r_{u}}}\right]^{\frac{1}{1-t}}\\ &y_{v}=\left[\frac{L}{1+e^{-(1-t)r_{l}}}\right]^{\frac{1}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
See [Appendix 3](automated-market-making-of-alex.md#appendix-3-derivation-of-actual-and-virtual-token-reserve) for a detailed derivation of virtual, as well as actual token reserve.
|
||||
|
||||
Similar to the case of 0% floor, minting or burning coins would result in invariant constant changing from $$L$$ to $$k^{1-t}L$$. Meanwhile, both actual and virtual Token and ayToken would grow proportionally by $$k$$, as they are linear function of $$L^{\frac{1}{1-t}}$$.
|
||||
|
||||
#### Example
|
||||
|
||||
We aim to show here how virtual token is able to assist liquidity providers to efficiently manage capital.
|
||||
|
||||
.png>)
|
||||
|
||||
In Figure 2, assume lower bound is 0%, whereas upper bound is 50%. We also set $$t$$= 0.5 and $$L$$= 20. If interest rate is 0%, $$L$$= 20 means holding equal amount of Token and ayToken of 100 each $$\left(100^{0.5}+100^{0.5}=20\right)$$. The figure compares actual holding of Token and ayToken with and without cap and floor.
|
||||
|
||||
According to the figure, when current implied interest rate is 10%, without capital efficiency, liquidity provider is required to deposit 95.06 Token and 105.06 ayToken. This is in comparison with 18.39 Token and 5.06 ayToken after imposing cap and floor. In this example, the capital saving is at least 77%.
|
||||
|
||||
## Appendix 1: Generalised Mean when d=2
|
||||
|
||||
ALEX's invariant function is $$f(x_{1},x_{2};p)=x{_1}^{p}+x_{2}^{p}=L.$$ It can be rearranged as $$x{2}=g(x_{1})=(L-x_{1}^{p})^{\frac{1}{p}}$$. $$x_{1}$$ and $$x_{2}$$ should both be positive meaning the liquidity pool contains both tokens.
|
||||
|
||||
#### Theorem
|
||||
|
||||
When $$0<p<1$$, $$g\left(x_{1}\right)$$ is monotonically decreasing and convex.
|
||||
|
||||
#### Proof
|
||||
|
||||
This is equivalent to prove $$\frac{dg(x_{1})}{dx_{1}}<0$$ and $$\frac{d^{2}g(x_{1})}{dx_{1}^{2}}\geq0$$.
|
||||
|
||||
$$
|
||||
\begin{split} &\frac{dg(x_{1})}{dx_{1}}=\frac{1}{p}(L-x_{1}^{p})^{\frac{1}{p}-1}\left(-px_{1}^{p-1}\right)=-\left(\frac{L-x_{1}^{p}}{x_{1}^{p}}\right)^{\frac{1-p}{p}}<0\\ &\frac{d^{2}g(x_{1})}{dx_{1}^{2}}=-\frac{1-p}{p}\left(\frac{L-x_{1}^{p}}{x_{1}^{p}}\right)^{\frac{1-2p}{p}}\left[\frac{-px_{1}^{p-1}x_{1}^{p}-(L-x_{1}^{p})px^{p-1}}{x_{1}^{2}p}\right]\\ &=L(1-p)\left(\frac{x_{2}}{x_{1}}\right)^{1-2p}x_{1}^{-p-1}\geq0 \end{split}
|
||||
$$
|
||||
|
||||
The last inequality holds because each component is positive.
|
||||
|
||||
When $$p$$= 1, it is straightward to see that the invariant function is constant sum. To show that the invariant function converges to constant product when $$p$$= 0, we will show and prove an established result in a generalised $$d$$ dimensional setting.
|
||||
|
||||
#### Theorem
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\left(\frac{1}{d}\sum_{i=1}^{d}x_{i}^{p}\right)^{\frac{1}{p}}=({\prod_{i=1}^{d}x_{i}})^{\frac{1}{d}}
|
||||
$$
|
||||
|
||||
#### Proof
|
||||
|
||||
$$\left(\frac{1}{d}\sum{i=1}^{d}x_{i}^{p}\right)^{\frac{1}{p}}=\text{exp}\left[\frac{\text{log}\left(\frac{1}{d}\sum{i=1}^{d}x_{i}^{p}\right)}{p}\right]$$. Applying _L'Hospital_ rule to the exponent,which is 0 in both denominator and nominator when $$p\rightarrow0$$, we have
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\frac{\text{log}\left(\frac{1}{d}\sum_{i=1}^{d}x_{i}^{p}\right)}{p}=\lim_{p\rightarrow0}\sum_{i=1}^{d}\frac{\text{log}(x_{i})}{\sum_{j=1}^{d}\left(\frac{x_{j}}{x_{i}}\right)^{p}}=\frac{\sum_{i=1}^{d}\text{log}(x_{i})}{d}
|
||||
$$
|
||||
|
||||
Therefore
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\left(\frac{1}{d}\sum_{i=1}^{d}x_{i}^{p}\right)^{\frac{1}{p}}=\lim_{p\rightarrow0}\text{exp}\frac{\sum_{i=1}^{d}\text{log}(x_{i})}{d}=({\prod_{i=1}^{d}x_{i}})^{\frac{1}{d}}
|
||||
$$
|
||||
|
||||
#### Corollary
|
||||
|
||||
When d = 2,
|
||||
|
||||
$$
|
||||
x_{1}x_{2}=\lim_{p\rightarrow0}\left[\frac{1}{2}(x_{1}^{p}+x_{2}^{p})\right]^{\frac{2}{p}}
|
||||
$$
|
||||
|
||||
Proof of the corollary is trivial, as it is a direct application of the theorem. It shows that generalised mean AMM implies constant product AMM when $$p\rightarrow0$$.
|
||||
|
||||
## Appendix 2: Liquidity Mapping to Uniswap v3
|
||||
|
||||
As Uniswap v3 is able to simulate liquidity curve of any AMM, we are interested in exploring the connection between ALEX's AMM and that of _Uniswap_'s. Interesting questions include: what is the shape of the liquidity distribution? Which point(s) has the highest liquidity? We acknowledge that the section is more of a theoretical study for now.
|
||||
|
||||
_Uniswap V3_ AMM can be expressed as a function of invariant constant $$L$$ with respect to price $$p$$, $$L_{\text{Uniswap}}=\frac{dy}{d\sqrt{p}}$$. In terms of ALEX, as price p=e^{rt}, where $$r$$ is the implied interest rate, we have
|
||||
|
||||
$$
|
||||
L_{\text{Uniswap}}=\frac{dy}{d\sqrt{p}}=\frac{2}{t}e^{-\frac{1}{2}rt}\frac{dy}{dr}
|
||||
$$
|
||||
|
||||
In the previous sections, we express $$y$$ as
|
||||
|
||||
$$
|
||||
y=\left[\frac{L}{1+e^{-(1-t)r}}\right]^{\frac{1}{1-t}}
|
||||
$$
|
||||
|
||||
Therefore
|
||||
|
||||
$$
|
||||
\begin{split} &\frac{dy}{dr}=L^{\frac{1}{1-t}}\frac{e^{-(1-t)r}}{(1+e^{-(1-t)r})^{\frac{2-t}{1-t}}}\\ &L_{\text{Uniswap}}=\frac{2}{t}L^{\frac{1}{1-t}}\left(e^{\frac{r(1-t)}{2}}+e^{\frac{-r(1-t)}{2}}\right)^{\frac{-2+t}{1-t}}\\ &=\frac{2}{t}L^{\frac{1}{1-t}}\big\{2\cosh\left[\frac{r(1-t)}{2}\right]\big\}^{\frac{-2+t}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
 (2) (2) (2) (2) (2) (2) (1).png>)
|
||||
|
||||
Figure 3 plots $$L_{\text{Uniswap}}$$ against interest rate $$r$$ regarding various levels of $$t$$. When $$0<t<1$$, $$L_{\text{Uniswap}}$$ is symmetric around 0% at which the maximum reaches . This is because
|
||||
|
||||
1. $$\cosh\left[(\frac{r(1-t)}{2})\right]$$ is symmetric around $$r$$= 0% with minimum at 0% and the minimum value 1;
|
||||
2. $$x^z$$ is a decreasing function of $$x$$ when $$x$$ is positive and power $$z$$ is negative. In our case, we have $$z=-2+t1-t<-1$$. Therefore, it is the maximum rather than minimum that $$L_{\text{Uniswap}}$$ achieves at 0.
|
||||
|
||||
Furthermore, the higher the $$t$$, the flatter the liquidity distribution is. When $$t$$ approaches 1, i.e. AMM converges to the constant product formula, the liquidity distribution is close to a flat line. When $$t$$ approaches 0, the distribution concentrates around 0%. This makes sense, as forward price starts to converge to spot price upon expiration.
|
||||
|
||||
## Appendix 3: Derivation of Actual and Virtual Token Reserve
|
||||
|
||||
On CEC, there are two boundary points ($$x_{b}$$,0) and (0,$$y_{b}$$) corresponding to the lower and upper bound of interest rate $$r_{l}$$ and $$r_{u}$$ respectively. We assume $$L$$ is pre-determined, as liquidity provider knows the pool size. We aim to find $$x_{b}$$, $$y_{b}$$, $$x_{v}$$ and $$y_{v}$$ which satisfy the following equations
|
||||
|
||||
$$
|
||||
\begin{split} &(x_{b}+x_{v})^{1-t}+y_{v}^{1-t}=L\\ &x_{v}^{1-t}+(y_{b}+y_{v})^{1-t}=L\\ &\frac{y_{v}}{x_{b}+x_{v}}=e^{r_{l}}\\ &\frac{y_{b}+y_{v}}{x_{v}}=e^{r_{u}} \end{split}
|
||||
$$
|
||||
|
||||
As there are four unknown variables with four equations, solutions can be expressed as below
|
||||
|
||||
$$
|
||||
\begin{split} &x_{v}=\left[\frac{L}{1+e^{(1-t)r_{u}}}\right]^{\frac{1}{1-t}}\\ &y_{v}=\left[\frac{L}{1+e^{-(1-t)r_{l}}}\right]^{\frac{1}{1-t}}\\ &x_{b}=y_{v}e^{-r_{l}}-x_{v}=\left[\frac{L}{1+e^{r_{l}(1-t)}}\right]^{\frac{1}{1-t}}-\left[\frac{L}{1+e^{r_{u}(1-t)}}\right]^{\frac{1}{1-t}}\\ &y_{b}=x_{v}e^{r_{u}}-y_{v}=\left[\frac{L}{1+e^{-r_{u}(1-t)}}\right]^{\frac{1}{1-t}}-\left[\frac{L}{1+e^{-r_{l}(1-t)}}\right]^{\frac{1}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
When $$r_{l}=0$$, the pool is floored at 0%. This means that $$x_{v}=0$$, $$y_{v}=\left(\frac{1}{2}L\right)^{\frac{1}{1-t}}$$, $$x_{b}=y_{v}$$.
|
||||
|
||||
When the current interest rate $$r_{c}$$ is known and $$r_{c}\in[r_{l},r_{u}]$$, we can calculate $$x_{a}$$ and $$y_{a}$$ satisfying the following equations. When $$r_{c} \notin[r_{l},r_{u}]$$, only one token exists and swapping activities are suspended.
|
||||
|
||||
$$
|
||||
\begin{split} &(x_{v}+x_{a})^{1-t}+(y_{v}+y_{a})^{1-t}=L\\ &\frac{y_{v}+y_{a}}{x_{v}+x_{a}}=e^{r_{c}} \end{split}
|
||||
$$
|
||||
|
||||
Solution to above is
|
||||
|
||||
$$
|
||||
\begin{split} &x_{a}=\left[\frac{L}{1+e^{r_{c}(1-t)}}\right]^{\frac{1}{1-t}}-x_{v}=\left[\frac{L}{1+e^{r_{c}(1-t)}}\right]^{\frac{1}{1-t}}-\left[\frac{L}{1+e^{r_{u}(1-t)}}\right]^{\frac{1}{1-t}}\\ &y_{a}=\left[\frac{L}{1+e^{-r_{c}(1-t)}}\right]^{\frac{1}{1-t}}-y_{v}=\left[\frac{L}{1+e^{-r_{c}(1-t)}}\right]^{\frac{1}{1-t}}-\left[\frac{L}{1+e^{-r_{l}(1-t)}}\right]^{\frac{1}{1-t}} \end{split}
|
||||
$$
|
||||
|
||||
At the boundary points, when $$r_{c}=r_{l}$$, $$x_{a}=x_{b}$$ and $$y_{a}=0$$; when $$r_{c}=r_{u}$$, $$x_{a}=0$$ and $$y_{a}=y_{b}$$.
|
||||
@@ -0,0 +1,176 @@
|
||||
# Automated Market Making of Collateral Rebalancing Pool
|
||||
|
||||
## Abstract
|
||||
|
||||
Collateral pools of many DeFi platforms typically comprise a single asset reflecting a borrower’s crypto ownership and risk appetite. While single asset pools benefit from asset appreciation, a pool's value can diminish swiftly in volatile market conditions. The increasing chance of default and potential shortening of the loan term affect both borrowers and lenders who enter fixed-term and fixed-rate contract hoping to remove uncertainties.
|
||||
|
||||
Unlike many DeFi platforms, ALEX uses diversified rather than single collateral pools. Diversified pools consist of a risky asset and risk-free asset. As a result, diversified pools reduce default risk while maintaining potential upside gains. Diversified pools are similar to portfolios with equity and government bonds, where the former represents the risky asset while the latter represents the risk-free asset. Importantly, diversified collateral pools are systematically managed. An algorithmic engine dynamically adjusts the split of the risky and risk-free asset in the diversified pool, based on Black-Scholes' model.
|
||||
|
||||
ALEX's algorithmic engine and diversified pools minimize the risk of a borrower defaulting. The result is a smoother lending and borrowing experience. Parties have more peace of mind, are interrupted less frequently, and achieve robust returns even in volatile market conditions. This represents a radical improvement over existing alternatives.
|
||||
|
||||
## Introduction
|
||||
|
||||
Protocols for loanable funds (PLF) enable borrowing and lending activities. Examples PLFs are Compound and Aave on Ethereum. The lender provides a token in need and earns interest in return. The borrower deposits collateral and gets access to a preferred asset. The borrower must pay back the borrowed asset in due time. Protocols enabling this borrowing and lending functionality are incredibly useful. Simply, they enable the present consumption on future earnings. This idea is powerful, and has been at the core of DeFi's rise, including the rise of protocols such as Uniswap.
|
||||
|
||||
However, one of the risks posed to market participants in existing PLFs is default risk. While each loan must be secured with collateral, the price of crypto collateral can fluctuate wildly and quickly. As a result, many PLFs ask borrows to significantly overcollateralise their positions. Overcollateralisation refers to value of collateralised assets being higher than the value of the loaned assets. The proportion of the collateral value to loaned value is often called "collateralisation ratio" (CR), the inverse of "loan to value" (LTV). For simplicity sake, we use the term LTV throughout the paper. The higher the LTV is, the more likely the default occurs. A LTV larger than 1 means the value of collateral cannot cover the value of the loaned asset.
|
||||
|
||||
In variable rate platforms, such as Aave, collateral in the form of more liquid assets tends to have a higher LTV. In fixed-rate fixed-term protocols, such as YieldSpace, using ETH as collateral to borrow Dai requires a LTV of 67%. In the event that the portfolio is underfunded, three scenarios could emerge in the existing protocols: (i) a borrower could top up the collateral asset to stay afloat; (ii) a borrower could return some of the borrowing asset to decrease the LTV; and (iii) the loan could be unwound by a third party such as liquidator if the borrower defaults. A third party unwinds a borrower's position by paying back the loan, and in return earns certain fees. In cases when a collateral asset is illiquid, fees can be as high as 15% on Aave, representing a significant penalty to defaulting borrowers. This also poses disruption to borrowing/lending activity, as a pre-agreed loan is terminated early.
|
||||
|
||||
ALEX abolishes liquidation. ALEX keeps the loan active until maturity, regardless of market condition, solving problems plaguing many existing PLFs. The basis for ALEX's superior solution is based on an innovative combination of asset management and collateral pools. This is how it works.
|
||||
|
||||
First, unlike many others, ALEX does not use a static collateral pool with a single asset. Instead, ALEX maintains robust performance in the collateral pool by splitting the deposited asset between a risky and a riskless asset. The collateral pool systematically rebalances the allocation of these two assets based on market conditions. Typically, the better the performance of one asset relative to the other asset, the higher its relative allocation. In mathematical terms, weight is calculated and modified from option delta derived from Black-Scholes model.
|
||||
|
||||
So the collateral pool consists of two assets. This opens up new opportunities. For example, ALEX can enable borrowers to gain additional income by engaging in automated market marking (AMM). Automated market making helps guarantee a constant proportion of assets in the collateral pool. The AMM takes the form a geometric mean, made popular by [Balancer](https://balancer.fi/whitepaper.pdf). The notion that users _get paid_ is different from much of conventional finance, where portfolio holders are typically required to pay fees to rebalance the portfolio.
|
||||
|
||||
Importantly, in market downturns, a risky asset may constantly depreciate. In these cases, ALEX's relative allocation of a riskless asset will gradually increase by design. In the event of a loan close to being under-collateralized or defaulting, ALEX converts the remaining portion of the risky asset so that only the riskless asset remains. This ensures no interruption to borrowing/lending activities. Similarly, the agreed rate and maturity remains unaffected. This is different from liquidation. In other platforms, liquidations usually unwind the loan partially, or even fully, resulting in the early termination of a loan. ALEX's design allows for borrowing and lending activity to unfold without the interruptions that plague many of ALEX's alternatives.
|
||||
|
||||
## Two-Asset Collateral Pool: Rationale
|
||||
|
||||
Most loanable funds assume a single asset in the collateral pool. While this type of pool benefits when prices of collateral assets appreciate, a pool's value can depreciate rapidly when volatility is large and prices of collateral assets plummet.
|
||||
|
||||
In conventional finance, whether or not to hold a risky asset depends on investors' risk appetite and their perception of the market environment. A "risk on" market environment entices investors to purchase risky assets and to seek larger returns. In our view, collateral pools made up of single assets are more suitable during "risk on" environments. In these environments, "risk-seeking" borrowers worry less about defaulting and believe risky assets will rally further. This contrasts with "risk-off" environments, when market uncertainty increases. Investors become more risk-averse and tend to hold riskless assets which exhibit small volatility and smaller return.
|
||||
|
||||
Many investors would like to profit in both "risk on" and "risk off" periods by holding a diversified portfolio comprised of both risky and riskless assets. A typical example is a portfolio consisting of an S\&P 500 index and of US Treasury bonds. Diversification is essential to portfolio management. Diversification ensures portfolios are not overly exposed to one specific asset. Diversifications reduces unsystematic risk. Thus, diversification is a core reason why ALEX creates collateral pools with more than one asset: diversified collateral pools reduce pool volatility while enhancing returns.
|
||||
|
||||
## AMM: Geometric Mean Market Maker
|
||||
|
||||
AMMs are the key drivers behind many DeFi trading platforms. We discuss its general features in our [first white paper](https://docs.alexgo.io/whitepaper/automated-market-making-of-alex). Our AMM design adopts a "generalised mean market maker". This design is powerful because it incorporates time to maturity features while aligning various AMM derivations with traditional financial pricing theory.
|
||||
|
||||
In the collateral pool, as weights of the underlying assets change regularly, we employ an AMM which has embedded weights in its expression: the geometric mean market maker (GMMM). Each weight of the GMMM corresponds to the proportion of a relevant asset's value to the whole portfolio's value. This is a desirable property for any portfolio manager who sets target weights for a portfolio's assets.
|
||||
|
||||
GMMMs were first introduced by Balancer. A GMMM represents an extension to the AMM of the popular AMM platform Uniswap. Uniswap's AMM is a special case of Balancer's GMMM by imposing weights of 50% each on two assets in a given pool.
|
||||
|
||||
Mathematically, a GMMM consisting of two assets can be expressed as follows:
|
||||
|
||||
$$
|
||||
x(t)^{w_{x}(t)}\times y(t)^{w_{y}(t)}=L(t)
|
||||
$$
|
||||
|
||||
where $$x(t)$$ and $$y(t)$$ are the balance of the risky asset and the riskless asset respectively, whereas $$w_{x}(t)$$ and $$w_{y}(t)$$ are the corresponding weights and $$w_{x}(t)+w_{y}(t)=1$$. $$L(t)$$ is the invariant constant, which remains unchanged when weights are fixed in between rebalancing time.
|
||||
|
||||
Prices $$p_{x}(t)$$ and $$p_{y}(t)$$, which share the same numeraire such as USD, satisfy the following no-arbitrage condition:
|
||||
|
||||
$$
|
||||
\frac{\frac{y(t)}{w_{y}(t)}}{\frac{x(t)}{w_{x}(t)}}=\frac{p_{x}(t)}{p_{y}(t)}
|
||||
$$
|
||||
|
||||
Denote the pool value as $$v(t)=x(t)p_{x}(t)+y(t)p_{y}(t)$$. Combining with a no-arbitrage condition, we can show that:
|
||||
|
||||
$$
|
||||
\begin{split} w_{x}(t)&=\frac{x(t)p_{x}(t)}{v(t)}\\ w_{y}(t)&=\frac{y(t)p_{y}(t)}{v(t)}\\ \end{split}
|
||||
$$
|
||||
|
||||
This means that a pool's weight represents the underlying asset value in proportion to the pool's value.
|
||||
|
||||
Lastly, GMMM is related to the generalised mean AMM employed in the Yield Token Pool by setting $$w_{x}(t)=w_{y}(t)=0.5$$ because:
|
||||
|
||||
$$
|
||||
\lim_{p\rightarrow0}\left[w_{x}(t)x(t)^{p}+w_{y}(t)y(t)^{p}\right]^{\frac{1}{p}}=x(t)^{w_{x}(t)}y(t)^{w_{y}(t)}
|
||||
$$
|
||||
|
||||
## Rebalancing Set-up and Collateral Pool Valuation
|
||||
|
||||
In conventional finance, rebalancing results in updated allocation of underlying assets without altering the portfolio value. However, this is not the case when an AMM is implemented in DeFi. The portfolio value changes reflecting the effort in preserving the price, while adjusting the invariant function with the newly calibrated weights.
|
||||
|
||||
Assume the loan is borrowed at time 0 and returned at time T. There are k-1 rebalancing events throughout the life time of the loan, $$t_{1},t_{2},\cdots,t_{k-1}$$ , satisfying $$0=t_{0}<t_{1}<t_{2}<\cdots<t_{k}=T$$.
|
||||
|
||||
At the start of the contract $$t_{0}=0$$, the initially deposited risky asset is split into $$x(t_{0})$$ and $$y(t_{0})$$. The split may occur using any trading platform, including our in-house DEX.
|
||||
|
||||
At rebalancing time $$t_{i}(i=1,2,\cdots,k-1)$$, price will deviate from the market as soon as weights are updated. Our system relies on arbitrageurs to align the price with the market by trading in the pool. This subsequently impacts token balances, the invariant constant, and portfolio value.
|
||||
|
||||
The process is summarised below. We further denote $$t_{\tilde{i}}$$ as the continuous adjacent time right before $$t_{i}$$.
|
||||
|
||||
1. Update weights $$w_{x}(t_{i})$$ and $$w_{y}(t_{i})$$. Weights calculation will be discussed in the next section.
|
||||
2. Evaluate invariant constant $$L(t_{i})$$:
|
||||
|
||||
$$
|
||||
L(t_{i})=x(t_{\tilde{i}})^{w_{x}(t_{i})}\times y(t_{\tilde{i}})^{w_{y}(t_{i})}
|
||||
$$
|
||||
|
||||
1. Compute token balance to align the price with the market. This involves arbitrageurs:
|
||||
|
||||
$$
|
||||
\begin{split} x(t_{i})&=L(t_{i})\left(\frac{w_{x}(t_{i})}{w_{y}(t_{i})}\frac{p_{y}(t_{i})}{p_{x}(t_{i})}\right)^{w_{y}(t_{i})}\\y(t_{i})&=L(t_{i})\left(\frac{w_{y}(t_{i})}{w_{x}(t_{i})}\frac{p_{x}(t_{i})}{p_{y}(t_{i})}\right)^{w_{x}(t_{i})} \end{split}
|
||||
$$
|
||||
|
||||
1. Calculate portfolio value:
|
||||
|
||||
$$
|
||||
v(t_{i})=x(t_{i})p_{x}(t_{i})+y(t_{i})p_{y}(t_{i})
|
||||
$$
|
||||
|
||||
$$w(t)$$ and $$L(t)$$ are adjusted at time $$t_{i}$$ and stay fixed between $$[t{i},t_{i+1})$$.
|
||||
|
||||
When a loan expires at $$t_{k}=T$$, the remaining balance of $$x(t_{k})$$ and $$y(t_{k})$$ are all converted to the agreed asset.
|
||||
|
||||
## Dynamic Rebalancing
|
||||
|
||||
ALEX's rebalancing collateral pool is dynamics. It integrates the concept of asset management with collateral management. By holding and dynamically managing both a risky asset and a riskless asset, several benefits result. When the risky asset depreciates, the collateral pool increasingly holds more of the riskless rather than the risky asset, dynamically reducing the threat of undercollatisation. On the contrary, a higher weight is dynamically assigned to a risky asset when the its price surges, ensuring that the collateral pool captures most of the upside gains. This dynamic is similar to a call option, whose upside is protected whereas its downside is limited. With ALEX, no actual option is involved however, and thus the borrower is not required to pay any expensive option premiums. Options premiums are significant with many cryptoassets because many cryptoassets are very volatile.
|
||||
|
||||
In the current version, a collateral pool's allocation mechanism has close ties with option delta. Option delta measures the sensitivity of the option's valuation to the underlying asset price movement. The delta of a call option ranges between 0 and 1 depending on an asset's spot price and the option's strike price, as shown in Figure 1. The higher the spot price, the larger the delta. Therefore, the more weight would be assigned to risky asset. When the strike price is set to be the same as asset spot price (at-the-money option), the delta is around 0.5. In ALEX's design, this means holding an equal amount of the risky and of the riskless assets.
|
||||
|
||||

|
||||
|
||||
In mathematical terms, option delta $$\delta(t)$$ is calculated from Black Scholes model as follows:
|
||||
|
||||
$$
|
||||
\delta(t)=N\left[\frac{\text{ln}\left(\frac{p(t)}{K}\right)+\left(r+\frac{\sigma^{2}}{2}\right)(T-t)}{\sigma(T-t)}\right]
|
||||
$$
|
||||
|
||||
where $$p(t)=\frac{p_{x}(t)}{p_{y}(t)}$$ is the price of asset $$x$$ in terms of asset $$y$$; $$K$$ is the strike price; $$r$$ is the expected return; $$\sigma$$ is implied volatility; $$T$$ is the tenor and $$N(.)$$ is the cumulative distribution of the standard normal distribution.
|
||||
|
||||
Ideally, the relative weights of the risky and riskless assets should be updated continuously to reflect spot price movements and delta changes. In practice, we are updating the weights periodically (e.g. daily). However as cryptoassets typically exhibit higher volatility than other asset classes, delta changes can be significantly different between time periods. Significant movements tend to imply considerable price deviations from the market after rebalancing. This leads to significant profits for arbitrageurs, but arbitrageurs' gains are often a collateral pool losses. This is similar to impermanent loss. However, while impermanent loss is caused by token balances moving along an AMM curve, here it is caused by weight changes and the effort to preserve price.
|
||||
|
||||

|
||||
|
||||
To mitigate the impact of weight changes, ALEX smooths the delta using an exponential moving average. At rebalancing time $$t_{i}$$, the holding of a risky asset $$w_{x}(t_{i})$$ is calculated as
|
||||
|
||||
$$
|
||||
w_{x}(t_{i})=\alpha\delta(t_{i})+(1-\alpha)w_{x}(t_{i-1})
|
||||
$$
|
||||
|
||||
where $$\alpha$$ is the smoothing factor. Allocation to the riskless asset is thus $$1-w_{x}(t_{i})$$. Figure 2 compares the risky asset weight and the option delta of a simulated bitcoin path over a three-month period.
|
||||
|
||||
In comparison with a collateral pool consisting of single asset, a collateral rebalancing pool could underperform when the market is risk-on and a risky asset exhibits strong upward price momentum. This is because holding a risky asset is a smoothed version of option delta, suggesting the asset's weight hardly reaches 100%. However, when the market is tumbling and the risky asset depreciates, more weight is assigned to the riskless asset, reducing losses. This rebalancing slows down portfolio value depreciation. It also increases the chance of the loan staying afloat. Taken together, both these effects ensure robust performance with dynamic collateral pools across market conditions.
|
||||
|
||||
## Flight to Quality
|
||||
|
||||
Every effort is made to ensure the loan is overcollateralised by mimicking a call option whose downside is limited. However, the lack of an actual option means that the loan might still default, especially when the volatility of the risky asset increases or the market is in crisis.
|
||||
|
||||
If the collateral pool value drops below a pre-determined threshold, ALEX guarantees sustainability of the loan by converting the entire balance of the collateral pool's risky asset to the collateral pool's riskless asset. This ensures that borrowers can always cover the loan's initial value. It also ensures no interruption of borrowing/lending activity more broadly.
|
||||
|
||||
These benefits are not possible by other protocols for loanable funds that use and enforce liquidation dynamics. Not only would the fixed term loan be interrupted due to early termination, but the price of liquidation might also not be known, adding an extra layer of uncertainty. Furthermore, liquidators can usually claim what is called a liquidation bonus, another source of loss to the borrower. For example, on Aave, liquidation bonuses range between 5% and 15%. On ALEX, borrowers are protected from these risks and losses.
|
||||
|
||||
ALEX's protocol also faces less pressure should liquidity shrink amid turmoil. This is because ALEX's design increases the holding of a riskless asset gradually when the market starts to shown signs of downturns. Although this is clearly an advantage compared to other platforms, the rare event of a mass market disruption might cause slow conversions and the collateral value dropping below the loan amount. To address such a black swan situation, ALEX also maintains a reserve fund. The fund is the protocol's last resort for covering loans. It grows by way of collecting reserve premiums and is meant to secure the long term sustainability of ALEX as a whole.
|
||||
|
||||
In conventional finance, selling a risky asset to purchase a riskless asset is often called "flight to quality". This often occurs during bear markets. In bear markets, investors endeavour to avoid economic losses, reduce risks, and thus seek "high quality" assets. ALEX incorporates this dynamic automatically and dynamically by rebalancing the assets in a collateral pool to contain more of the riskless than the risky asset.
|
||||
|
||||
To limit downside risks, once the collateral pool is rebalanced to only contain the riskless asset, all activities in the pool cease to function. This includes no more dynamic weights adjustments from price movements, even if the market rebounds.
|
||||
|
||||
## Appendix
|
||||
|
||||
### Collateral Pool Key Parameters
|
||||
|
||||
Most of the contents below are discussed in the main sections. Nonetheless, we list key parameters as they are essential to the collateral pool's functioning, and for securing ALEX's long term sustainability.
|
||||
|
||||
#### Contract Initialisation
|
||||
|
||||
* **Loan-to-Value (LTV)**: The ratio of the loan amount to the value of the collateral ("collateralised asset(s)"). For example, if LTV is set to be 80%, a loan amount equivalent to 80 BTC requires 100 BTC as collateral. There is generally no objectively correct LTV ratio; the LTV ratio depends on the quality of the collateralised asset, as well as the market condition when the loan is taken out. **Collateralisation Ratio (CR)** is the inverse of LTV.
|
||||
* **Tenor**: The length of time remaining before the loan expires.
|
||||
* **Strike Price**: In the Black-Scholes model, strike price refers to the price at which the contract holder can purchase the underlying security when exercising a call option, or sell the underlying security when exercising a put option. In ALEX, the strike price determines the initial split of the risky and the riskless asset. For example, for an at-the-money option, in which strike price is set to be equal to the spot price, there would be an equal split of between two assets in the pool (i.e. \~50%).
|
||||
* **Implied Volatility**: In the Black-Scholes model, implied volatility is the volatility estimate of an underlying security. A crude approximation of implied volatility is historical volatility. In practise, implied volatility is usually backed out from the observed option price.
|
||||
* **Risk-free Interest Rate**: In the Black-Scholes model using risk-neutral valuation, the risk-free interest rate equals the expected return. The risk-free interest rate is usually assumed to be 0%, as future direction of the underlying security is unknown.
|
||||
|
||||
#### Pool Rebalancing
|
||||
|
||||
* **Rebalancing Frequency**: Theoretically, continuous rebalancing is preferred for price continuity. In practise, ALEX updates the weights periodically to avoid over-calibration.
|
||||
* **Smoothing Factor of Exponential Moving Average (EMA)**: EMA is an averaging method that places more weight on more recent observations. Assume y(t) is the observation value of y at time t, and that {y}(t) is the corresponding moving average, where $$\alpha$$ is the smoothing factor. Then:
|
||||
|
||||
$$
|
||||
\hat{y}(t)=\alpha y(t)+(1-\alpha)\hat{y}(t-1)
|
||||
$$
|
||||
|
||||
#### Flight to Quality
|
||||
|
||||
* **Conversion Threshold**: This is the LTV level when the risky asset in the collateral pool is completely converted to the riskless asset to prevent the loan from under-collateralization.
|
||||
* **Reserve Premium**: The reserve premium is collected on behalf of a reserve fund. The reserve fund serves as the protocol's last resort. In the extreme event that market turmoil dries up liquidity and ALEX cannot convert all risky assets quickly enough to cover the loan amount, the protocol would cover the difference. The reserve premium is thus another mechanism to guarantee continuity of borrowing and lending activity on ALEX.
|
||||
129
developers/whitepaper/dive-into-collateral-rebalancing-pool.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Dive Into Collateral Rebalancing Pool!
|
||||
|
||||
## Introduction
|
||||
|
||||
ALEX's collateral rebalancing pools \(CRP\) introduce the concept of portfolio management to DeFi protocols for loanable funds \(PLFs\). A collateral rebalancing pool can hold more than one asset in the collateral pool. Typically, pools hold two assets. One asset is the risky or "collateral" asset, while the other is the riskless or "loan" asset. This design of collateral pools aims to address the most important problem facing PLFs today: under-collateralisation resulting from collateral pool value shrinking significantly during market turmoil
|
||||
|
||||
ALEX avoids under-collateralisation and thus liquidation risks through algorithmic rebalancing. As market conditions and the prices of the risky and riskless assets change, a collateral pool is automatically rebalanced to prevent under-collateralisation. During "risk-on" periods, more relative weight is assigned to the risky asset over the riskless asset. During "risk-off" periods, more relative weight is assigned to the riskless asset over the risky asset. This latter feature ensures that pools cannot become undercollateralised. This dynamic rebalancing, along with other key risk parameters, removes the threat of liquidation. Liquidation often threatens system stability and is extremely costly to market participants. ALEX removes these threats and costs from market participants.
|
||||
|
||||
Due to an abundance of caution, ALEX also maintains a reserve fund to deal with black-swan situations. Although limited by design, a collateral pool's value may drop below the loan's value. Should this happen, the reserve fund would cover any losses. More detail about this reserve fund, and the collateral rebalancing pool system more broadly, is documented in ALEX’s white paper entitled "Automated Marking Making of Collateral Rebalancing Pool".
|
||||
|
||||
This report below displays the results of both simulated and real datasets. The results show the strength and robustness of our novel approach to collateral pool management. We exploit the results through an agent-based simulation of various market environments, including both momentum and mean-reversion. We also assess its performance on real data during black-swan events, such as when an underlying risky asset declines massively and abruptly. In our tests, the risky asset is BTC, and the riskless asset is USDC.
|
||||
|
||||
## Set-Up
|
||||
|
||||
### Key Parameters
|
||||
|
||||
Key parameters are discussed in detail in our white paper. While some of them are assumed fixed in this report, such as tenor of the fixed rate contract set at three-month, others are studied in more depth to better understand their impact to CRP. Key parameters that are varied include:
|
||||
|
||||
* **Loan-to-Value \(LTV\)**: The ratio of the loan amount to the value of the collateral. For example, if LTV is set to be 80, a loan amount equivalent to 80 BTC requires 100 BTC as collateral. There is generally no objectively correct LTV ratio; the LTV ratio depends on the quality of the collateralised asset, as well as the market condition when the loan is taken out.
|
||||
* **Implied Volatility**: In the Black-Scholes model, implied volatility is the volatility estimate of an underlying security. A crude approximation of implied volatility is historical volatility. In practise, implied volatility is usually backed out from the observed option price.
|
||||
* **Rebalancing Frequency**: Theoretically, continuous rebalancing is preferred for price continuity. However, this is impractical due to transaction costs and on-chain implementations. Thus, ALEX updates the weights periodically, e.g. hourly.
|
||||
* **Conversion Threshold**: This is the LTV level where the risky asset in the collateral pool is completely converted to the riskless asset to prevent the loan from becoming under-collateralised.
|
||||
|
||||
### Evaluation Metrics
|
||||
|
||||
We assess performance using the following metrics below, which are functions of the initial LTV and the conversion threshold.
|
||||
|
||||
* **Insolvent Rate**: The proportion of loan defaults, i.e. loans becoming under-collateralised.
|
||||
* **Insolvent Loss Ratio**: Insolvent Loss is the difference between loan value and collateral pool value when a loan defaults. Insolvent loss ratio refers to the average ratio between insolvent loss and initial pool value in terms of USDC.
|
||||
* **Conversion Rate**: The proportion of time that a "flight-to-quality" occurs, meaning the proportion of time that a risky asset is completely converted to a riskless asset in the collateral pool.
|
||||
* **BTC Weight at Conversion**: The average weight of BTC when "flight-to-quality" occurs.
|
||||
* **Impermanent Loss Due to Weight Rebalance**: Total loss of collateral pool value due to weight change divided by the initial pool value in terms of USDC.
|
||||
* **Final Pool Value Ratio**: The ratio of the collateral pool value between expiry and start of the loan contract.
|
||||
|
||||
### Simulation Design
|
||||
|
||||
Collateral rebalancing pools, or "CRPs", serve as an agent \(bot\) allocating dynamic weights to risky and riskless assets in a collateral pool. To understand the performance of CRPs, we ran several rigorous simulations. In our simulations, we model the risky asset by way of tracking the underlying BTC price. Specifically, we model the price using the standard and widely accepted form of geometric Brownian motion. This includes two key parameters: BTC's annualized mean $$\mu$$ and BTC's implied volatility $$\sigma$$. These two parameters can be adjusted to reflect various market conditions.
|
||||
|
||||
$$\mu$$ controls market direction. Positive/negative $$\mu$$ refers to a market with upward/downward momentum, whereas $$\mu$$= 0 corresponds to mean reversion in a market without obvious trend. $$\sigma$$ represents a market's degree of volatility. In conventional finance, implied volatility is derived from observed option prices. However, option markets for cryptoassets are in their infancy and used by a small number of market participants. Therefore, rather than back-calculating implied volatility, we assume it to be the same as historical volatility. In this report, $$\sigma$$ is set to 80%, which is the average historical volatility of the past five years.
|
||||
|
||||
Our results are based on 5,000 simulated paths of BTC prices and hourly rebalancing, variously altering initial LTV and conversion threshold parameters. All the key results are described below. Note that the grey area is not relevant in this study--either the conversion threshold is lower than initial LTV or the metrics are not applicable.
|
||||
|
||||
## Mean-Reverting Market
|
||||
|
||||
Mean-reverting markets refer to markets where no clear trend is observed. Simulating mean-reverting markets suggests that the expected price at maturity is equivalent to the initial price. As future price movements are hard to predict, a mean-reverting market with $$\mu$$=0 is the default case when deriving parameters such as option delta.
|
||||
|
||||
### Performance
|
||||
|
||||
Performance metrics of the simulated ALEX CRP are presented in Figure 1 below. In summary:
|
||||
|
||||
* Figure 1 \(a\) and \(b\) show that the insolvent rate and insolvent loss ratio of the ALEX CRP is almost 0, with the exception of an initial LTV close to 0.8 and a conversion threshold close to 1.
|
||||
* Implication: Setting conversion thresholds lower than 0.95 avoids load defaults and liquidations.
|
||||
* Figure 1 \(c\) highlights that the greater the difference between the initial LTV value and the conversion threshold value, the lower the conversion rate i.e. the more rarely a pool's risky asset is entirely converted into the pool's riskless asset.
|
||||
* A careful selection of conversion thresholds can see conversion rates close to zero, as the collateral pool value would rarely hit the thresholds.
|
||||
* Figure 1 \(d\) underscores that the weight of the risky asset goes down when the pool value decreases with the conversion threshold rising. This indicates smoother performance of the collateral pool and helps reducing the loss.
|
||||
* Figure 1 \(e\) reveals that the maximum Impermanent loss resulting from rebalancing weights is generally less than 2%. Figure 1 \(f\) highlights that despite a maximum potential 2% impermanent loss, the final pool value is on average within 3% of the initial pool value. This is due to the assumption that the market is mean reverting.
|
||||
|
||||

|
||||
|
||||
\(\* Weight is not shown if the conversion rate is < 0.01\)
|
||||
|
||||
### Comparison with Single Asset Collateral Pool
|
||||
|
||||
ALEX introduces an innovative system to manage collateral pools with two assets. ALEX's system is different from other PLFs. Other PLFs use collateral pools that typically consist of a single asset. We refer to collateral pools with a single asset as static pools. If the value of a static pool falls below a pre-determined threshold, a loan is partially or fully liquidated by a third-party liquidator. Such a threshold is called "liquidation threshold" in our analysis.
|
||||
|
||||
Liquidation thresholds are comparable to the "conversion threshold" of ALEX, meaning the % value of the LTV at which all of the risky asset is converted into the riskless asset. In addition, the "liquidation rate" for a static pool, which is the percentage of time that liquidation occurs, is also similar to the "conversion rate" of ALEX, which is the percentage of time that all of a risky asset has been converted into the riskless asset.
|
||||
|
||||
We set a 5% liquidation penalty in the static pool model. This reflects current practice in other PLFs. The liquidation penalty represents an additional loss to the borrower when the loan is subject to liquidation. For example, AAVE’s liquidation penalty ranges between 5% and 15%, depending on the exact collateral asset. We use a conservative 5% penalty, as $BTC has ample liquidity during normal market conditions.
|
||||
|
||||

|
||||
|
||||
The performance of the static pool is presented in Figure 2. Comparing the static pool's performance to that of ALEX's pool, several insights emerge:
|
||||
|
||||
* Additional liquidation penalties increase the chance of borrowers facing insolvency. We reach this insight by comparing data in Figure 2 \(a\) and \(b\) with data in Figure 1 \(a\) and \(b\).
|
||||
* Because a static pool value drops more than in ALEX's pools when faced with the same market movement, under-collateralised loans occur relatively more often in static pools. This can be seen by comparing the liquidation rate of the static pool in Figure 2 \(c\) and the conversion rate of ALEX in Figure 1 \(c\). Moreover, a static pool is significantly more often required to liquidate up to 100% of the risky asset. During turbulent markets when liquidity dries up swiftly, this can be challenging. As a result, static pools are significantly more risky than ALEX's pools.
|
||||
* As seen in Figure 2 \(d\), the final pool value of a static pool is almost the same as the initial pool value. Compared to LEX's pools, static pools are not quite the same in terms of the final pool value, however, as seen in Figure 1 \(f\). Nonetheless, the results of the static pool and of ALEX's pool are both largely due to the mean-reverting assumption in our models.
|
||||
|
||||
### Rebalancing Frequency
|
||||
|
||||
Theoretically, continuous rebalancing is ideal. Continuous rebalancing fully captures all price movements. However, continuous rebalancing is not practically possible. On one hand, data might be affected by short term noise, such as prices bouncing back between bids and asks. On the other hand, there can be confirmation lags when trades are executed on-chain. We therefore model a periodic rather than continuous rebalancing frequency.
|
||||
|
||||
Figure 3, below, displays the simulation results when rebalancing daily. As expected, rebalancing hourly \(Figure 1\) performs better on most metrics, as the system responds more promptly to price movements.
|
||||
|
||||

|
||||
|
||||
\(\* Weight is not shown if the conversion rate is < 0.01\)
|
||||
|
||||
## Extreme Downward Market
|
||||
|
||||
Extreme downward market conditions, also called black swan events, refer to unexpected and extreme market movements. Usually, these black swan events lead to large loss to a majority of market participants. Black swan events are a systematic risk that cannot be completely hedged. Although ALEX aims to reduce the impact of black swan events through diversification in the collateral pool, industry-wide issues remain. Two issues are particularly critical: \(i\) the pool can be insolvent as the unforeseen shock to the market price is largely one-way and substantial; and \(ii\) liquidity can evaporate swiftly. This is usually accompanied by large price slippages if participants are forced to trade during black swan events. To ALEX pools, trading out of all risky assets might become problematic when liquidity dries up. While the risk is minimized because ALEX pools constantly rebalance, the risk still exists.
|
||||
|
||||
### Simulation
|
||||
|
||||
We assume an annual return $$\mu$$=-200% in the simulation. This is equivalent to a -50% BTC price drop within our contract loan term of three months.
|
||||
|
||||
As shown in Figure 4, although conversion rates of 100% of the risky asset to the riskless asset can be high, pools largely remain solvent. The average weight of the risky asset is around 15% at the conversion given initial LTV 75% and conversion LTV 90%. It demonstrates again that the pool faces less pressure at conversion, even during extreme market condition which could dry up liquidity and increase slippage.
|
||||
|
||||

|
||||
|
||||
\(\* Weight is not shown if the conversion rate is < 0.01\)
|
||||
|
||||
### Case Study: Black Swan Event of March 2020
|
||||
|
||||
Due to pandemic and market uncertainty, all risky assets declined sharply in March 2020. On March 12th, 2020, Bitcoin experienced its largest price drop in history – an unprecedented daily change of -49%. How would ALEX's CRP have performed if the contract had been initiated during this black swan event?
|
||||
|
||||
Assume a three-month contract. The contract starts on Mar 1st, 2020. Implied volatility is 80%. The pool rebalances hourly. Initial LTV is set at 75%, and the conversion threshold is set at 90%. The strike price is set to be the spot price at 7,956 – the BTC price on the start day.
|
||||
|
||||
ALEX CRP pool would have hit the conversion threshold at 12:00 PM, Mar 12th, 2020, when the remaining BTC in pool, whose relative weight had dropped to 44% in the pool, needed to be converted to USDC. With conversions taking place, the pool would have stayed solvent, and final pool value would have had a 83.16% ratio.
|
||||
|
||||
While slippage is essential and should be included in the calculation, it is not easy to quantify in such a scenario. Comparatively, our pressure of converting BTC to USDC would have been lower compared to other PLFs because ALEX would have decreased BTC exposure gradually before the peak of the crisis unfolded.
|
||||
|
||||
## Extreme Upward Market
|
||||
|
||||
To complete the report and in contrast with the previous analysis of extreme downward market, we also assess the performance of ALEX CRP during market euphoria. We model market euphoria by assuming an annual return $$\mu$$ of +200%. This is equivalent to a 50% BTC price increase within our contract term of three months. The simulation results are presented in Figure 5. The results confirm ALEX CRP’s ability in capturing potential upside gains while minimizing the risk of default.
|
||||
|
||||

|
||||
|
||||
\(\* Weight is not shown if the conversion rate is < 0.01\)
|
||||
|
||||
## Conclusion
|
||||
|
||||
This report evaluates the performance of ALEX's CRP via an agent-based simulation for various market environments under different key parameters. In particular, a stress test is implemented to model black swan events. Taken together, we show that ALEX's CRP is able to:
|
||||
|
||||
* capture potential upside gains while limiting the downside market losses
|
||||
* eliminate liquidation risks with insolvent rates close to 0 under various market conditions
|
||||
* significantly reduce conversion pressure when liquidity shrinks amid market turmoil.
|
||||
|
||||
In short, ALEX's protocol delivers a unique and smooth experience to both borrowing and lending activities by minimizing interruption from market noise. Systematic risk still exists and cannot be fully hedged. However, compared to other PLFs, ALEX's innovative dynamic pool mechanism helps market participants sail smoothly through challenging times and consequently achieve better and more robust returns.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
root: ./docs/
|
||||
root: ./
|
||||
# All other options that specify paths will be relative to this root folder.
|
||||
|
||||
structure:
|
||||
|
Before Width: | Height: | Size: 482 KiB After Width: | Height: | Size: 482 KiB |
|
Before Width: | Height: | Size: 564 KiB After Width: | Height: | Size: 564 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 893 KiB After Width: | Height: | Size: 893 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 733 KiB After Width: | Height: | Size: 733 KiB |
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 440 KiB |
|
Before Width: | Height: | Size: 441 KiB After Width: | Height: | Size: 441 KiB |
|
Before Width: | Height: | Size: 905 KiB After Width: | Height: | Size: 905 KiB |
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 829 KiB After Width: | Height: | Size: 829 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 327 KiB After Width: | Height: | Size: 327 KiB |