#deal #cpi #account #market #index #credix #pre-mainnet

credix_client

用于执行对Credix程序CPI调用的工具包

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 魔法豆

GPL-3.0-or-later

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