17个版本 (8个破坏性更新)
0.9.1 | 2023年9月13日 |
---|---|
0.8.0 | 2023年6月13日 |
0.7.6 | 2023年8月31日 |
0.6.0 | 2023年2月24日 |
0.4.0 | 2022年11月18日 |
#1543 in 魔法豆
61KB
341 行
Credix Rust客户端
一个工具包,通过CPI与Credix程序交互
注意:此工具包使用Anchor生成的IDL生成,并添加了一些额外的函数。要了解某些pda种子或哪些账户是可变的,请参考Credix程序IDL。它在工具包源代码的每个环境中都可用。
环境
预主网
- 预主网:这是Credix程序的Solana测试网环境。它通常与主网环境非常接近。在将任何功能发布到主网之前,预主网程序会进行更新。地址:
crdRi38zEhQdzpsxnKur73WHBM9BSvXMSfGcbLyJCdP
。
市场
- 在预主网上具有种子
credix-marketplace
的市场应针对测试,不进行取款纪元。 - 在预主网上具有种子
withdraw-epochs
的市场应针对测试,进行取款纪元。
配置客户端
要针对我们的预主网环境,可以启用 pre-mainnet
功能
credix_client = { version="0.8.0", features = ["pre-mainnet"], default-features = false }
主网
- 主网:这是我们生产环境。地址:
CRDx2YkdtYtGZXGHZ59wNv1EwKHQndnRc1gT4p8i2vPX
注意:要使用任何Credix环境中的任何市场,您需要一个具有特定权限的有效Credix通行证。请联系Credix以获取一个。
配置客户端
要针对我们的主网环境,可以启用 mainnet
功能
credix_client = { version="0.8.0", features = ["mainnet"], default-features = false }
本地开发
获取Credix二进制文件
在创建本地设置时,建议在为即将到来的Credix主网版本做准备时从Solana测试网集群获取预主网二进制文件。可以使用以下命令完成此操作
solana program dump -u d crdRi38zEhQdzpsxnKur73WHBM9BSvXMSfGcbLyJCdP ./credix.so
日常稳定测试可以通过以下命令获取主网二进制文件进行
solana program dump -u m CRDx2YkdtYtGZXGHZ59wNv1EwKHQndnRc1gT4p8i2vPX ./credix.so
准备本地集群
要获得一个可工作的本地环境,必须调用某些指令来设置一切。以下指令应按顺序调用。
您可以找到更多关于每个指令的cargo 文档信息。
您可以找到更多关于每个账户的cargo 文档信息。
Credix程序准备
initialize_program_state
初始化整个Credix生态系统共享的用于管理目的的ProgramState账户。这将允许您创建市场。
initialize_market
创建一个市场。
issue_credix_pass
这为市场的任何参与者提供了权限。只能由MarketAdmins账户中列为通行证发行者的密钥或由ProgramState中指定的多签发行。
任何用户与市场的互动都需要有效的Credix通行证。
市场交互
deposit_funds
这会将资金存入池中,以换取LP代币。
create_withdraw_epoch
创建一个提取纪元。在任何人可以参与纪元之前,必须发生此操作。必须在上一个纪元完全结束后创建纪元。
create_withdraw_request
创建一个提取请求。这是您请求提取一定金额的地方。根据纪元中其他参与者请求的金额和市场池中可用的资金,将首先提供一定金额。然后进行第二轮,未提取的金额将可供其他参与者提取。不同阶段和参数的持续时间在市场级别指定。
redeem_request
在这里,我们实际上在赎回阶段或自由提取阶段提取资金。
影响LP价格
到目前为止,尚未发生利息偿还,因此LP价格没有变化。要将在测试中包含此场景,您需要执行几个步骤。同样,以下操作需要按顺序执行,并且在提取纪元设置之前执行,以查看影响和更多信息可以在之前描述的位置找到。
为了方便起见,我们将提供一些基本配置,以便能够触发利息偿还。
create_deal
创建交易。
示例配置
max_funding_duration: 255,
deal_name: "Simple Deal",
arrangement_fees: 0,
arrangement_fee_percentage: Fraction::new(0,100),
migrated: false,
set_repayment_schedule
设置偿还计划。这定义了何时需要偿还以及根据什么瀑布进行处理。
示例配置
let now = system_time::now();
// now will contain the current unix timestamp in ms.
let principal = 1000000;
let config_for_instruction= RepaymentScheduleConfig {
periods: vec![
RepaymentPeriodInput {
waterfall_index: 0,
accrual_in_days: 30,
principal_expected: None,
time_frame: TimeFrame {
start: now,
end: now + 30 * SECONDS_IN_DAY - 1,
},
},
RepaymentPeriodInput {
waterfall_index: 1,
accrual_in_days: 30,
principal_expected: Some(principal),
time_frame: TimeFrame {
start: now + 30 * SECONDS_IN_DAY,
end: now + 60 * SECONDS_IN_DAY - 1,
},
}
],
start_ts: now,
daycount_convention: DaycountConvention::Act360,
waterfall_definitions: vec![
DistributionWaterfall {
waterfall_type: DistributionWaterfallType::Revolving,
tiers: vec![
WaterfallTier {
allocations: vec![RepaymentAllocation::Interest],
tranche_indices: vec![0],
charge: true,
slash: false,
},
],
},
DistributionWaterfall {
waterfall_type: DistributionWaterfallType::Amortization,
tiers: vec![
WaterfallTier {
allocations: vec![
RepaymentAllocation::Principal,
RepaymentAllocation::Interest
],
tranche_indices: vec![0],
charge: true,
slash: false,
}
],
},
],
};
set_tranches
在这里,我们定义交易的分段组成。分段是交易的投资机会。
示例配置
这包括由池资助的分段。这意味着当交易激活时,资金将从市场的流动性池流向交易。
vec![
TrancheConfig {
index: 0,
max_deposit_percentage: Fraction::new(1, 1).unwrap(),
early_withdrawal_principal: true,
funded_by_liquidity_pool: true,
name: "A".to_string(),
size: principal, // the variable we declared earlier
interest: Fraction::new(12, 10).unwrap(),
interest_performance_fee: Fraction::new(1, 10).unwrap(),
principal_performance_fee: Fraction::new(0, 1).unwrap(),
membership_fee: Fraction::new(1, 10).unwrap(),
late_interest: Fraction::new(1, 10).unwrap(),
early_principal: Fraction::new(1, 10).unwrap(),
late_principal: Fraction::new(1, 10).unwrap(),
},
],
open_deal
一旦交易完全配置,我们必须更改其状态,以便投资者可以投资。这将为资金打开交易。
activate_deal
一旦交易完全资助(使用我们提供的配置,这是自动完成的),就必须激活交易。这将标记资金从流动性池移动到交易以资助池资助的分段的时间点。实际借款金额将可供借款人使用。
repay_deal
这允许借款人偿还交易。此时,利息将流向池,LP价格应上升,您的投资应获得回报率。
获取LP价格
LP代币价格是TVL除以LP代币的总供应量。TVL等于总未偿还信贷和流动性池代币账户中的资金。
它可以通过以下计算在链上找到
let pool_liquidity = liquidity_pool_token_account.amount;
let outstanding_credit = global_market_state.pool_outstanding_credit;
let tvl = pool_liquidity + outstanding_credit;
let lp_supply = lp_token_mint.supply;
let lp_price = tvl / lp_supply;
示例
链上
这是一个使用anchor制作的Rust程序示例,这里提供了存款、提款、创建提款请求和赎回提款请求的CPI。
use anchor_lang::prelude::*;
use credix_client::cpi::accounts::{
CreateWithdrawRequest, DepositFunds, RedeemWithdrawRequest, WithdrawFunds,
};
use credix_client::cpi::{
create_withdraw_request, deposit_funds, redeem_withdraw_request, withdraw_funds,
};
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod integrator {
use super::*;
pub fn deposit_cpi(ctx: Context<DepositFundsCpi>, amount: u64) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.credix_program.to_account_info(),
DepositFunds {
investor: ctx.accounts.investor.to_account_info(),
global_market_state: ctx.accounts.global_market_state.to_account_info(),
signing_authority: ctx.accounts.signing_authority.to_account_info(),
investor_token_account: ctx.accounts.investor_token_account.to_account_info(),
credix_pass: ctx.accounts.credix_pass.to_account_info(),
investor_lp_token_account: ctx.accounts.investor_lp_token_account.to_account_info(),
liquidity_pool_token_account: ctx
.accounts
.liquidity_pool_token_account
.to_account_info(),
lp_token_mint: ctx.accounts.lp_token_mint.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
token_program: ctx.accounts.token_program.to_account_info(),
associated_token_program: ctx.accounts.associated_token_program.to_account_info(),
base_token_mint: ctx.accounts.base_token_mint.to_account_info(),
},
);
deposit_funds(cpi_context, amount)?;
Ok(())
}
pub fn withdraw_cpi(ctx: Context<WithdrawFundsCpi>, amount: u64) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.credix_program.to_account_info(),
WithdrawFunds {
investor: ctx.accounts.investor.to_account_info(),
global_market_state: ctx.accounts.global_market_state.to_account_info(),
signing_authority: ctx.accounts.signing_authority.to_account_info(),
investor_lp_token_account: ctx.accounts.investor_lp_token_account.to_account_info(),
investor_token_account: ctx.accounts.investor_token_account.to_account_info(),
liquidity_pool_token_account: ctx
.accounts
.liquidity_pool_token_account
.to_account_info(),
lp_token_mint: ctx.accounts.lp_token_mint.to_account_info(),
program_state: ctx.accounts.program_state.to_account_info(),
credix_treasury: ctx.accounts.credix_treasury.to_account_info(),
credix_treasury_token_account: ctx
.accounts
.credix_treasury_token_account
.to_account_info(),
treasury_pool_token_account: ctx
.accounts
.treasury_pool_token_account
.to_account_info(),
credix_pass: ctx.accounts.credix_pass.to_account_info(),
base_token_mint: ctx.accounts.base_token_mint.to_account_info(),
associated_token_program: ctx.accounts.associated_token_program.to_account_info(),
token_program: ctx.accounts.token_program.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
},
);
withdraw_funds(cpi_context, amount)?;
Ok(())
}
pub fn create_withdraw_request_cpi(
ctx: Context<WithdrawRequestCpi>,
amount: u64,
) -> Result<()> {
let accounts = ctx.accounts;
let cpi_context = CpiContext::new(
accounts.credix.to_account_info(),
CreateWithdrawRequest {
payer: accounts.payer.to_account_info(),
investor: accounts.investor.to_account_info(),
credix_pass: accounts.credix_pass.to_account_info(),
global_market_state: accounts.global_market_state.to_account_info(),
investor_lp_token_account: accounts.investor_lp_token_account.to_account_info(),
liquidity_pool_token_account: accounts
.liquidity_pool_token_account
.to_account_info(),
lp_token_mint: accounts.lp_token_mint.to_account_info(),
signing_authority: accounts.signing_authority.to_account_info(),
system_program: accounts.system_program.to_account_info(),
withdraw_epoch: accounts.withdraw_epoch.to_account_info(),
},
);
create_withdraw_request(cpi_context, amount)
}
pub fn redeem_request_cpi(ctx: Context<RedeemRequestCpi>, amount: u64) -> Result<()> {
let accounts = ctx.accounts;
let cpi_context = CpiContext::new(
accounts.credix.to_account_info(),
RedeemWithdrawRequest {
investor: accounts.investor.to_account_info(),
credix_pass: accounts.credix_pass.to_account_info(),
global_market_state: accounts.global_market_state.to_account_info(),
investor_lp_token_account: accounts.investor_lp_token_account.to_account_info(),
liquidity_pool_token_account: accounts
.liquidity_pool_token_account
.to_account_info(),
lp_token_mint: accounts.lp_token_mint.to_account_info(),
signing_authority: accounts.signing_authority.to_account_info(),
system_program: accounts.system_program.to_account_info(),
withdraw_epoch: accounts.withdraw_epoch.to_account_info(),
associated_token_program: accounts.associated_token_program.to_account_info(),
base_token_mint: accounts.base_token_mint.to_account_info(),
credix_treasury: accounts.credix_treasury.to_account_info(),
credix_treasury_token_account: accounts
.credix_treasury_token_account
.to_account_info(),
program_state: accounts.program_state.to_account_info(),
investor_token_account: accounts.investor_token_account.to_account_info(),
rent: accounts.rent.to_account_info(),
token_program: accounts.token_program.to_account_info(),
treasury_pool_token_account: accounts.treasury_pool_token_account.to_account_info(),
},
);
redeem_withdraw_request(cpi_context, amount)
}
}
#[derive(Accounts)]
pub struct DepositFundsCpi<'info> {
#[account(mut)]
pub investor: Signer<'info>,
pub credix_program: Program<'info, Credix>,
/// CHECK: test program
pub global_market_state: AccountInfo<'info>,
/// CHECK: test program
pub signing_authority: AccountInfo<'info>,
/// CHECK: test program
#[account(mut)]
pub investor_token_account: AccountInfo<'info>,
/// CHECK: test program
#[account(mut)]
pub liquidity_pool_token_account: AccountInfo<'info>,
/// CHECK: test program
#[account(mut)]
pub lp_token_mint: AccountInfo<'info>,
/// CHECK: test program
#[account(mut)]
pub investor_lp_token_account: AccountInfo<'info>,
/// CHECK: test program
pub credix_pass: AccountInfo<'info>,
/// CHECK: test program
pub base_token_mint: AccountInfo<'info>,
/// CHECK: test program
pub associated_token_program: AccountInfo<'info>,
pub rent: Sysvar<'info, Rent>,
/// CHECK: test program
pub token_program: AccountInfo<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct WithdrawFundsCpi<'info> {
#[account(mut)]
pub investor: Signer<'info>,
pub credix_program: Program<'info, Credix>,
#[account(mut)]
/// CHECK: test program
pub global_market_state: AccountInfo<'info>,
/// CHECK: test program
pub program_state: AccountInfo<'info>,
/// CHECK: test program
pub signing_authority: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub investor_lp_token_account: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub investor_token_account: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub liquidity_pool_token_account: AccountInfo<'info>,
/// CHECK: test program
pub credix_treasury: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub credix_treasury_token_account: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub treasury_pool_token_account: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub lp_token_mint: AccountInfo<'info>,
#[account(mut)]
/// CHECK: test program
pub credix_pass: AccountInfo<'info>,
/// CHECK: test program
pub base_token_mint: AccountInfo<'info>,
/// CHECK: test program
pub associated_token_program: AccountInfo<'info>,
/// CHECK: test program
pub token_program: AccountInfo<'info>,
pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct WithdrawRequestCpi<'info> {
#[account(mut)]
pub payer: Signer<'info>,
#[account(mut)]
pub investor: Signer<'info>,
/// CHECK:
pub global_market_state: AccountInfo<'info>,
/// CHECK:
pub signing_authority: AccountInfo<'info>,
/// CHECK:
#[account()]
pub credix_pass: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub withdraw_epoch: AccountInfo<'info>,
/// CHECK:
#[account()]
pub investor_lp_token_account: AccountInfo<'info>,
/// CHECK:
#[account()]
pub liquidity_pool_token_account: AccountInfo<'info>,
/// CHECK:
#[account()]
pub lp_token_mint: AccountInfo<'info>,
pub credix: Program<'info, Credix>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct RedeemRequestCpi<'info> {
#[account(mut)]
pub investor: Signer<'info>,
/// CHECK:
#[account(mut)]
pub global_market_state: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub withdraw_epoch: AccountInfo<'info>,
/// CHECK:
#[account()]
pub program_state: AccountInfo<'info>,
/// CHECK: The check happens when verifying the PDA address.
#[account()]
pub signing_authority: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub investor_lp_token_account: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub investor_token_account: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub liquidity_pool_token_account: AccountInfo<'info>,
/// CHECK: The address of account is known.
#[account()]
pub credix_treasury: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub credix_treasury_token_account: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub treasury_pool_token_account: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub lp_token_mint: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub credix_pass: AccountInfo<'info>,
/// CHECK:
#[account()]
pub base_token_mint: AccountInfo<'info>,
/// CHECK:
pub associated_token_program: AccountInfo<'info>,
/// CHECK:
pub token_program: AccountInfo<'info>,
pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
pub credix: Program<'info, Credix>,
}
链下
Typescript
为了链下开发,我们提供了一个Typescript客户端,以帮助收集不同的账户。查看该包的README以开始使用。
...
const marketName = "credix-marketplace";
const market = await client.fetchMarket(marketName);
Our client can help you with finding the keys of following accounts
const globalMarketState = market.address;
const programState = (await client.fetchProgramState()).address;
const signingAuthority = (await market.generateSigningAuthorityPDA())[0];
const investorLpTokenAccount = await market.findLPTokenAccount(investor);
const investorTokenAccount = await market.findBaseTokenAccount(investor);
const liquidityPoolTokenAccount = await market.findLiquidityPoolTokenAccount();
const credixTreasury = (await client.fetchProgramState()).credixTreasury;
const credixTreasuryTokenAccount = await market.findBaseTokenAccount(credixTreasury);
const treasuryPoolTokenAccount = market.treasury;
const lpTokenMint = market.lpMintPK;
const credixPass = (await market.fetchCredixPass(investor)).address
const baseTokenMint = await market.baseMintPK;
// Withdraw Epoch related accounts
const market = await client.fetchMarket(marketName);
const withdrawEpochAddress = WithdrawEpoch.generatePDA(market, market.latestWithdrawEpochIdx);
...
Rust
此crate还提供了帮助生成PDA的函数。请参阅Rust 文档
免责声明
这些示例提供现状。请勿盲目复制粘贴用于生产。
依赖项
~21-31MB
~529K SLoC