2 个稳定版本
1.1.0 | 2024年4月1日 |
---|---|
1.0.0 | 2024年3月6日 |
#2200 in 魔法豆
135KB
2K SLoC
DEXTER 协议 —— ::- 保险库合约
保险库是 Dexter 的核心;它是一个智能合约,持有和管理每个 Dexter 池中的所有代币。它也是大多数 Dexter 操作(交换/加入/退出)发生的门户。
管理员权限 -
Dexter 的保险库合约可以分配一个 管理员(多重签名或汇编合约),它具有以下权限,
- 管理员可以调用保险库合约中的 UpdateConfig() 函数来更新以下参数,
- Fee_collector - 保险库收取的费用转到的地址
- Generator_address - 支持将 LP 代币进行质押以获得奖励的 dexter 生成合约的地址。它只能设置一次,且不能更改。
- 这用于在用户向池提供流动性的同一交易中与生成器质押 LP 代币。
- Lp_token_code_id - 用于初始化池 LP 代币的 LP 代币合约的代码 ID。
- 管理员可以通过 UpdatePoolConfig() 函数调用,更新以下参数,
- 禁用/启用新池实例的创建:负责特定池类型的地址可以禁用或启用新实例的初始化
- 禁用/启用与 dexter 生成器的支持:负责特定池类型的地址可以禁用或启用 dexter 生成器的支持,这意味着该类型的池将无法再由生成器提供激励支持
- 更新适用于新池实例的费用信息:负责特定池类型的地址可以更新用于新池实例的费用配置
- 添加新的池类型:只有管理员可以通过 AddToRegistry() 函数将新的池类型添加到 Dexter 的保险库中。
- 所有Dexter池在初始化时都分配给Dexter管理员作为其管理员,这意味着它们可以通过Dexter管理员进行升级。
功能流程
1. JoinPool - 执行函数
-
保险库合同的JoinPool fn是向Dexter支持的任何池提供流动性的唯一入口点。
-
如果池在Dexter生成器上活跃以获取额外奖励,用户可以选择通过提供auto_stake = True使用生成器质押新铸造的LP代币。
-
保险库合同查询特定池合同,以获取以下信息,以提供流动性:
- 从用户到保险库的池流动性所转移的资产的排序列表。这是通过参数provided_assets提供的
- 要向用户/收款人铸造的LP代币数量。这是通过参数new_shares提供的
- 响应类型::成功或失败。这是通过参数response提供的
- 可选列表资产(信息和金额)作为费用收取给用户。这是通过参数fee提供的
-
只有Stable-5-Pool和Weighted Pool在以不平衡方式提供流动性时收取费用。XYK和stableswap池不收取任何费用
-
费用计算-
-
我们假设在provided_assets参数中提供的资产余额是转移到保险库的总代币数量,而协议和开发者费用尚未从这个总额中扣除。
-
对于要铸造的LP代币数量,我们假设它们与tokens_transferred_to_vault - total_fee成比例铸造,而实际上我们提供的是作为流动性的 liquidity to the pool
2. ExitPool - 执行函数
- 保险库合同的ExitPool fn是移除Dexter支持的任何池中的流动性的唯一入口点。
- 保险库合同查询要从其中移除流动性的特定池合同,以获取以下信息
- 从保险库转移到用户的资产的排序列表。这是通过参数assets_out提供的
- 用户要燃烧的LP代币数量。这是通过参数burn_shares提供的
- 响应类型::成功或失败。这是通过参数response提供的
- 可选列表资产(信息和金额)要收取。这是通过参数fee提供的
- 只有Stable-5-Pool在以不平衡方式提取流动性时收取费用。
- Weighted Pool有一个退出费用参数,费用只以LP代币收取,并且不累积到任何地方。
- XYK和stableswap池在提取流动性时不收取任何费用
费用计算-
- 我们假设在assets_out参数中提供的资产余额是转移到用户的总代币数量,而协议和开发者费用是作为费用额外转移的金额
- 对于要燃烧的LP代币数量,我们假设它们与assets_out + total_fee成比例燃烧
3. Swap - 执行函数
- 保险库合同的Swap fn是通过对任何Dexter支持的池进行代币兑换的唯一入口点。
- 保险库合同查询要从其中路由流动性的特定池合同,以获取以下信息
- 从保险库转移到用户,从用户到保险库的代币数量,这是在trade_params中返回的
- 响应类型::成功或失败。这是通过参数response提供的
- 可选资产(信息和金额)作为费用收取。这是通过参数fee提供的
费用计算-
- 我们假设在trade_params中提供的资产出金额是转移到用户的总代币数量,而协议和开发者费用是作为费用额外转移的金额,因此需要从池的当前流动性余额中额外扣除
- 出价资产池的流动性更新如下:
new_pool_liquidity=old_pool_liquidity-return_amount-protocol_fee-dev_fee
其中,
old_pool_liquidity:池流动性对于交换前的出价资产
new_pool_liquidity:池流动性对于交换后的出价资产
return_amount:转给用户的出价代币数量
protocol_fee:协议费用金额
dev_fee;开发者费用金额
- 稳定-5-池返回应转给用户的出价代币数量以及收取的出价代币费用。
- 加权池返回应转给用户的出价代币数量以及收取的出价代币费用。
- XYK池返回应转给用户的出价代币数量以及收取的出价代币费用。
- 稳定交换池返回应转给用户的出价代币数量以及收取的出价代币费用。
合约状态
消息 | 描述 |
---|---|
CONFIG |
在Config 结构体中存储保险库合约的核心配置参数。 |
REGISTERY |
在PoolType 结构体中存储保险库支持的每个PoolType 相关的配置数据。 |
ACTIVE_POOLS |
在PoolInfo 结构体中存储保险库支持的每个Pool实例的当前状态。 |
OWNERSHIP_PROPOSAL |
在保险库中当前活动的所有者提案,存储在OwnershipProposal 结构体中。 |
TMP_POOL_INFO |
暂时存储正在创建的Pool的PoolInfo,存储在PoolInfo 结构体中。 |
-
分离代币会计和池逻辑
Dexter的保险库架构受到Balancer的保险库的启发,并且同样将代币会计和管理从池逻辑中分离出来。这种分离简化了池合约,因为它们不再需要主动管理其资产;池只需要计算交换、加入和退出的金额。这种架构将不同的池设计置于同一伞下;保险库对池数学是盲目的,可以容纳任何满足一些要求的系统。任何有创新交易系统想法的人都可以创建一个自定义池,直接连接到Dexter现有的流动性,而无需构建自己的去中心化交易所。
-
安全性
需要注意的是,保险库的设计旨在保持池余额的严格独立性。维持这种独立性可以防止恶意或设计不当的代币或自定义池从任何其他池中吸走资金。
支持的执行消息
消息 | 描述 |
---|---|
ExecuteMsg::UpdateConfig |
仅由config.owner 可执行。便于更新config.fee_collector 、config.generator_address 、config.lp_token_code_id 参数。 |
ExecuteMsg::UpdatePoolConfig |
仅由pool_config.fee_info.developer_addr 或config.owner 可执行(如果未设置)。便于启用/禁用新池实例的创建(pool_config.is_disabled )以及为新池实例更新费用( pool_config.fee_info )。 |
ExecuteMsg::AddToRegistery |
添加一个新的池,带有新的PoolType 键。 |
ExecuteMsg::CreatePoolInstance |
在 asset_infos 变量中创建一个新的池,并指定参数。 |
ExecuteMsg::JoinPool |
用户加入Vault支持的池的入口点。用户可以通过提供池ID以及要提供的资产数量或要铸造给用户的LP代币(由池合约定义)来加入。 |
ExecuteMsg::Swap |
交换交易之间的入口点,涉及报价资产和询价资产。交换请求详情通过 SingleSwapRequest 类型参数传递。 |
ExecuteMsg::ProposeNewOwner |
创建一个新的更改所有权的请求。只有所有者可以执行它。 |
ExecuteMsg::DropOwnershipProposal |
删除更改所有权的请求。只有所有者可以执行它。 |
ExecuteMsg::ClaimOwnership |
新所有者主张所有权。只有新提议的所有者可以执行它。 |
支持的查询消息
消息 | 描述 |
---|---|
QueryMsg::Config() |
返回存储在自定义 ConfigResponse 结构中的 Vault 配置设置。 |
QueryMsg::QueryRegistry([ PoolType]) |
返回提供的 PoolType 的配置设置,在自定义 PoolConfigResponse 结构中。 |
QueryMsg::GetPoolById([ Uint128]) |
返回具有提供ID的当前存储的池状态,在自定义 PoolInfoResponse 结构中。 |
QueryMsg::GetPoolByAddress([ String]) |
返回池的当前存储状态,在自定义 PoolInfoResponse 结构中。 |
实例化 -::- InstantiateMsg
实例化消息接受Dexter用于针对支持的池实例实例化LP代币的代币代码ID(lp_token_code_id
),以及收集治理费用的fee_collector
地址、拥有Vault合约上的管理权限的所有者地址(owner
)、生成器合约地址(generator_address
)以及Dexter Vault支持的初始池类型,然后存储在REGISTERY中。
{
"lp_token_code_id": 123,
"fee_collector": "persistence...",
"owner": "persistence...",
"generator_address": "persistence...",
"pool_configs": "Vec<PoolConfig>"
}
执行 -::- ExecuteMsg
Receive(Cw20ReceiveMsg)
- 在移除流动性时接收LP代币
UpdateConfig
- 更新合约变量,只能由 config.owner
执行,即Dexter中使用的代币实现的代码ID、接收治理费用的地址以及生成器合约地址。
{
"update_config": {
"lp_token_code_id": 123,
"fee_collector": "terra...",
"generator_address": "terra..."
}
}
UpdatePoolConfig
- 只能由 pool_config.fee_info.developer_addr
或 config.owner
(如果未设置)执行。它有助于启用/禁用新池实例的创建,并更新新池实例的费用。
{
"update_pool_config": {
"pool_type": "PoolType",
"is_disabled": "Option<bool>",
"new_fee_info": "Option<FeeInfo>"
}
}
AddToRegistery
- 仅由 config.owner
可执行。添加一个新池,并带有新的 PoolType
键。
{
"add_to_registery": {
"new_pool_config": "PoolConfig"
}
}
CreatePoolInstance
- 根据变量 asset_infos
中的指定参数创建一个新的池。
{
"CreatePoolInstance": {
"pool_type": "PoolType",
"asset_infos": "Vec<AssetInfo>",
"lp_token_name": "Option<String>",
"lp_token_symbol": "Option<String>",
"init_params": "Option<Binary>"
}
}
JoinPool
- 用户加入 Vault 支持的池的入口点。在调用 JoinPool 函数之前,用户需要批准 Vault 合约对 CW20 代币的授权。
{
"join_pool": {
"pool_id": "Uint128",
"recipient": "Option<String>",
"assets": " Option<Vec<Asset>>",
"lp_to_mint": "Option<Uint128>",
"slippage_tolerance": "Option<Decimal>",
"auto_stake": "Option<bool>"
}
}
Swap
- 两种资产之间的交换事务的入口点。在调用 Swap 函数之前,用户需要批准 Vault 合约对 CW20 代币的授权。
{
"swap": {
"swap_request": "SingleSwapRequest",
"recipient": "Option<String>"
}
}
ProposeNewOwner
- 两种资产之间的交换事务的入口点。
{
"propose_new_owner": {
"owner": "String",
"expires_in": "u64"
}
}
DropOwnershipProposal
- 两种资产之间的交换事务的入口点。
{
"drop_ownership_proposal": {}
}
ClaimOwnership
- 两种资产之间的交换事务的入口点。
{
"claim_ownership": {}
}
执行 -::- Cw20HookMsg
ExitPool
- 从由 pool_id
标识的池中提取流动性。
{
"exit_pool": {
"pool_id": "Uint128",
"recipient": "Option<String>",
"assets": "Option<Vec<Asset>>",
"burn_amount": "Option<Uint128>"
}
}
查询 -::- QueryMsg
Config
- Config 返回在自定义 ConfigResponse
结构体中指定的控制设置。
{
"config": {}
}
QueryRigistery
- Config 返回在自定义 ConfigResponse
结构体中指定的控制设置。
{
"query_registery": {
"pool_type": "PoolType"
}
}
GetPoolById
- Config 返回在自定义 ConfigResponse
结构体中指定的控制设置。
{
"get_pool_by_id": {
"pool_id": "Uint128"
}
}
GetPoolByAddress
- Config 返回在自定义 ConfigResponse
结构体中指定的控制设置。
{
"get_pool_by_address": {
"pool_addr": "String"
}
}
枚举 & 结构体
PoolType
枚举 - 该枚举描述了 Dexter 支持的不同池类型的键。
enum PoolType {
Xyk {},
Stable2Pool {},
Stable3Pool {},
Weighted {},
Custom(String),
}
- 可以通过使用 PoolType::Custom(String) 类型添加新的池类型。
SwapType
枚举 - 该枚举描述了可用的交换类型。
enum SwapType {
GiveIn {},
GiveOut {},
Custom(String),
}
- 新池可以根据它们想要执行的数学计算逻辑支持自定义交换类型。
FeeInfo
结构体 - 该结构体描述了特定池类型支持的费率配置。
struct FeeInfo {
swap_fee_dir: SwapType,
total_fee_bps: u16,
protocol_fee_percent: u16,
dev_fee_percent: u16,
developer_addr: Option<Addr>,
}
Config
结构体 - 该结构体描述了 Vault 的主要控制配置。
struct Config {
/// The Contract address that used for controls settings for factory, pools and tokenomics contracts
owner: Addr,
/// The Contract ID that is used for instantiating LP tokens for new pools
lp_token_code_id: u64,
/// The contract address to which protocol fees are sent
fee_collector: Option<Addr>,
/// The contract where users can stake LP tokens for 3rd party rewards. Used for `auto-stake` feature
generator_address: Option<Addr>,
/// The next pool ID to be used for creating new pools
next_pool_id: Uint128,
}
PoolConfig
结构体 - 该结构体存储池类型的配置。
struct PoolConfig {
/// ID of contract which is used to create pools of this type
code_id: u64,
/// The pools type (provided in a [`PoolType`])
pool_type: PoolType,
fee_info: FeeInfo,
/// Whether a pool type is disabled or not. If it is disabled, new pools cannot be
/// created, but existing ones can still read the pool configuration
is_disabled: bool,
/// Setting this to true means that pools of this type will not be able
/// to get added to generator
is_generator_disabled: bool
}
PoolInfo
结构体 - 该结构体存储池类型的配置。
struct PoolInfo {
/// ID of contract which is allowed to create pools of this type
pool_id: Uint128,
/// Address of the Pool Contract
pool_addr: Option<Addr>,
/// Address of the LP Token Contract
lp_token_addr: Option<Addr>,
/// Assets and their respective balances
assets: Vec<Asset>,
/// The pools type (provided in a [`PoolType`])
pool_type: PoolType,
/// The address to which the collected developer fee is transferred
developer_addr: Option<Addr>,
}
SingleSwapRequest
结构体 - 该结构体存储池类型的配置。
struct SingleSwapRequest {
pool_id: Uint128,
asset_in: AssetInfo,
asset_out: AssetInfo,
swap_type: SwapType,
amount: Uint128,
max_spread: Option<Decimal>,
belief_price: Option<Decimal>,
}
构建模式并运行单元测试
cargo schema
cargo test
许可证
TBD
依赖关系
~9MB
~181K SLoC