#reserve #public-key #liquidity #lending #token #rate #port

port-variable-rate-lending-instructions

Port Finance 可变利率贷款方案

13 个版本

0.3.0 2021 年 12 月 23 日
0.2.9 2021 年 11 月 9 日
0.2.4 2021 年 9 月 30 日
0.1.1 2021 年 9 月 9 日
0.1.0 2021 年 7 月 16 日

#2868 in 神奇豆


用于 2 crates

Apache-2.0

110KB
2K SLoC

代币贷款程序

受 Aave 和 Compound 启发的 Solana 区块链上 Token 程序的贷款协议。

Port Finance 公钥

主网

贷款市场: 6T4XxKerq744sSuj3jaoV6QiZ8acirf4TrPwQzHAoSy5 贷款程序 ID: port_variable_rate_lending_instructions::id() 投资程序 ID: port_staking_instructions::id()

储备公钥

资产名称 储备地址
SOL X9ByyhmtQH3Wjku9N5obPy54DbVjZV7Z99TPJZ2rwcs
USDC DcENuKuYd6BWGhKfGr7eARxodqG12Bz1sN5WA8NwvLRx
USDT 4tqY9Hv7e8YhNQXuH75WKrZ7tTckbv2GfFVxmVcScW5s
PAI DSw99gXoGzvc4N7cNGU7TJ9bCWFq96NU2Cczi1TabDx2
SRM ZgS3sv1tJAor2rbGMFLeJwxsEGDiHkcrR2ZaNHZUpyF
BTC DSST29PMCVkxo8cf5ht9LxrPoMc8jAZt98t6nuJywz8p
MER BnhsmYVvNjXK3TGDHLj1Yr1jBGCmD1gZMkAyCwoXsHwt
mSOL 9gDF5W94RowoDugxT8cM29cX8pKKQitTp2uYVrarBSQ7
pSOL GRJyCEezbZQibAEfBKCRAg5YoTPP2UcRSTC7RfzoMypy
SBR 7dXHPrJtwBjQqU1pLKfkHbq9TjQAK9jTms3rnj1i3G77

以下所有信息您都可以通过解析储备数据获得。这里提供是为了方便。

pToken 铸造

资产名称 pToken 铸造
SOL 8ezDtNNhX91t1NbSLe8xV2PcCEfoQjEm2qDVGjt3rjhg
USDC FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58
USDT 3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ
PAI GaqxUwFGGrDouYLqghchmZU97Y1rNhyF7noMTJNvpQPa
SRM 77TBgKmTNtMdGrt1ewNRb56F2Xw6fNLZZj33JZ3oGwXh
BTC QN2HkkBaWHfYSU5bybyups9z1UHu8Eu7QeeyMbjD2JA
MER 6UgGnLA3Lfe8NBLAESctsUXWdP3zjMFzSLEZxS3tiaKh
mSOL Dt1Cuau5m5CSmun8hZstjEh9RszxAmejnq7ZaHNcuXfA
SBR FhraFicS7fGxHn8jfzuZ6TeTpCu8PAnQNZiT2tqM5xvv

预言机公钥

资产名称 预言机公钥
SOL H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG
USDC
USDT 3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL
PAI
SRM 3NBReDRTLKMQEKiLD5tGcx4kXbTf88b7f2xLS9UuGjym
BTC GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU
MER G4AQpTYKH1Fmg38VpFQbv6uKYQMpRhJzNPALhp7hqdrs
pSOL H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG
SBR 8Td9VML1nHxQK6M8VVyzsHo32D7VBk72jSpa9U861z2A

供应公钥

资产名称 供应公钥
SOL BLAFX12cDmsumyB6k3L6whJZqNqySaWeCmS5rVuzy3SS
USDC 2xPnqU4bWhUSjZ74CibY63NrtkHHw5eKntsxf8dzwiid
USDT QyvfrbqH7Mo8W5tHN31nzbfNiwFwqPqahjm9fnzo5EJ
PAI 42kNZrAuwZHLtuc7jvVX7zMfkfgwbPynqzFB3zdkAEGM
SRM DjhMNdgdbxNud1gmc4DUwrQqJxNbjhxiwNnhc4usSXmQ
BTC FZKP27Zxz9GbW86hhq3d1egzpBH5ZnYkyjQZVf86NQJ8
MER 6UmrawFZgdPvMe6BLZdZCNRFz9u2TWsu5enFbTufA3a1
SBR HTwd3VaDQphZgh2x7wqE2Qdndo4TT5C8fpvhKFcNh1Rt

开发网络

借贷计划ID: pdQ2rQQU5zH2rDgZ7xH2azMBJegUzUyunJ5Jd637hC4 借贷计划ID: port_staking_instructions::id() 借贷市场: H27Quk3DSbu55T4dCr1NddTTSAezXwHU67FPCZVKLhSW

储备公钥

资产名称 储备地址
SOL 6FeVStQAGPWvfWijDHF7cTWRCi7He6vTT3ubfNhe9SPt
USDC G1CcAWGhfxhHQaivC1Sh5CWVta6P4dc7a5BDSg9ERjV1
USDT B4dnCXcWXSXy1g3fGAmF6P2XgsLTFYaQxYpsU3VCB33Q
BTC A8krqNC1WpWYhqUe2Y5WbLd1Zy4y2rRN5wJC8o9Scbyk
MER FdPnmYS7Ma8jfSy7UHAN5QM6teoqwd3vLQtoU6r2Umwy

以下所有信息您都可以通过解析储备数据获得。这里提供是为了方便。

伪造代币铸造

资产名称 pToken 铸造
SOL So11111111111111111111111111111111111111112
USDC G6YKv19AeGZ6pUYUwY9D7n4Ry9ESNFa376YqwEkUkhbi
USDT 9NGDi2tZtNmCCp8SVLKNuGjuWAVwNF3Vap5tT8km5er9
BTC EbwEYuUQHxcSHszxPBhA2nT2JxhiNwJedwjsctJnLmsC
MER Tm9LcR74uJHPw3zY3j3nSh5xfcyaLbvXgAtTJwbqnnp

pToken 铸造

资产名称 pToken 铸造
SOL Hk4Rp3kaPssB6hnjah3Mrqpt5CAXWGoqFT5dVsWA3TaM
USDC HyxraiKfdajDbYTC6MVRToEUBdevBN5M5gfyR4LC3WSF
USDT 4xEXmSfLFPkZaxdL98XkoxKpXEvchPVs21GYqa8DvbAm
BTC 95XGx3cM83Z1Bbx8pJurAHwxJjvShTJE4BtfgMWfV6NB
MER FQzruvtLTk6qtPNEAJHQWMVs4M9UMP9T3cGAVfUskHfP

预言机公钥

资产名称 预言机公钥
SOL J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix
USDC
USDT 38xoQ4oeJCBrcVvca2cGk7iV1dAfrmTR1kmhSCJQ8Jto
BTC HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J
MER 6Z3ejn8DCWQFBuAcw29d3A5jgahEpmycn7YDMX7yRNrn

供应公钥

资产名称 供应公钥
SOL AbKeR7nQdHPDddiDQ71YUsz1F138a7cJMfJVtpdYUSvE
USDC GAPyFes3o7S7coY9nsuhaRZBEA7DdQPHBfVdY2DdgNua
USDT AeGbAqYZUURTykyCsgAUfopBMqQ3eAwrDxYhXoRhiw8q
BTC 75iyCxiPoj3MaUVo3SynmhaN3cbLDEhd4d9VHik6Kkvr
MER AMjhzse1TtTcKBFw5tQPLGtVoEsL4gt9YowNnzMKEGUr

创建抵押账户

对于具有流动性挖矿奖励的资产,您需要首先创建一个抵押账户,以便进行抵押并获得奖励。首先,获取您想要存入的储备金数据,并将其解包以获取字段 reserve.config.deposit_staking_pool,这是抵押池ID,然后使用Solana内置的 sha256 哈希函数 solana_sdk::hash::hashv(&[owner.as_ref(), staking_pool.as_ref(), staking_program_id.as_ref()]),其中所有者应为您的钱包公钥,然后通过 solana_sdk::signer::keypair::keypair_from_seed 生成抵押账户的密钥对。然后调用 create_accountcreate_stake_account 指令创建抵押账户。所有者需要签署奖励认领的指令。如果您正在使用程序创建抵押账户,则可以使用PDA账户。实际上,您可以使用任何地址创建抵押账户,只要确保(所有者,抵押池)与抵押账户之间有一一对应的关系,这意味着对于每个所有者和抵押池,您只有一个抵押账户。

let account_seed = hashv( & [owner.as_ref(), staking_pool.as_ref(), staking_program_id.as_ref()]);
let stake_account_key_pair = keypair_from_seed(account_seed.as_ref()).unwrap();
let instructions = vec![
    create_account(
        &payer.pubkey(),
        &stake_account_key_pair.pubkey(),
        stake_account_rent,
        StakeAccount::LEN as u64,
        &staking_program_id
    ),
    create_stake_account(
        staking_program_id,
        stake_account_key_pair.pubkey(),
        staking_pool,
        owner
    )
];

刷新储备金和义务

假设您已经有了您的质押账户,或者您正在向没有流动性挖矿奖励的储备金存款,您需要在存款/取款/偿还/清算之前,用同一指令刷新所有与义务交互的储备金以及义务本身。

let mut refresh_instructions = vec![];
//reserve_map is a map of reserve pubkey of reserve data, you can get the oracle pubkey from the reserve data or can hard code it in a config file.
let to_refresh = reserve_map.iter().filter( | (k, _) | {
        obligation
        .borrows
        .iter()
        .map(| li | li.borrow_reserve)
        .chain(obligation.deposits.iter().map(| ob | ob.deposit_reserve))
        .any( | r | r == * * k)
    });
refresh_instructions.extend(
    to_refresh.map( | (k, v) | refresh_reserve(lending_program_id, * k, v.liquidity.oracle_pubkey)),
);
refresh_instructions.push(
    refresh_obligation(
        program_id,
        obligation_pubkey,
        obligation
        .deposits
        .iter()
        .map(|d| d.deposit_reserve)
        .chain(obligation.borrows.iter().map(|b| b.borrow_reserve))
        .collect(),
    )
);

初始化义务

let mut transaction = Transaction::new_with_payer(
    &[
        create_account(
            &payer.pubkey(),
            &obligation_keypair.pubkey(),
            rent.minimum_balance(Obligation::LEN),
            Obligation::LEN as u64,
            &port_finance_variable_rate_lending::id(),
        ),
        init_obligation(
            port_finance_variable_rate_lending::id(),
            obligation.pubkey,
            lending_market.pubkey,
            user_accounts_owner.pubkey(),
        ),
    ],
    Some( & payer.pubkey()),
);

存款流动性/抵押

deposit_reserve_liquidity(
    port_variable_rate_lending::id(),
    liquidity_amount,
    user_liquidity_token_account_pubkey,
    user_collateral_token_account_pubkey,
    reserve_pubkey,
    reserve.liquidity.supply_pubkey,
    reserve.collateral.mint_pubkey,
    self.pubkey,
    user_transfer_authority.pubkey()
)
deposit_obligation_collateral(
    port_variable_rate_lending::id(),
    liquidity_amount,
    user_collateral_token_account_pubkey,
    reserve.collateral.supply_pubkey,
    reserve_pubkey,
    obligation_pubkey,
    lending_market.pubkey,
    obligation.owner,
    user_transfer_authority.pubkey(),
    Some(stake_account_pubkey),
    Some(staking_pool_pubkey),
)
deposit_reserve_liquidity_and_obligation_collateral(
    port_variable_rate_lending::id(),
    liquidity_amount,
    user_liquidity_token_account_pubkey,
    user_collateral_token_account_pubkey,
    reserve_pubkey,
    reserve.liquidity.supply_pubkey,
    reserve.collateral.mint_pubkey,
    lending_market_pubkey,
    reserve.collateral.supply_pubkey,
    obligation_pubkey,
    obligation.owner,
    user_transfer_authority.pubkey(),
    Some(stake_account_pubkey),
    Some(staking_pool_pubkey),
)

取款

即将推出withdrawAndRedeem指令,而在审计期间。因此,现在您需要首先解除资产抵押,然后取款。

withdraw_obligation_collateral(
    port_finance_variable_rate_lending::id(),
    WITHDRAW_AMOUNT,
    reserve.collateral.supply_pubkey,
    sol_test_reserve.user_collateral_pubkey,
    sol_test_reserve.pubkey,
    test_obligation.pubkey,
    lending_market.pubkey,
    test_obligation.owner,
    Some(stake_account_pubkey),
    Some(staking_pool_pubkey),
)
redeem_reserve_collateral(
    port_finance_variable_rate_lending::id(),
    COLLATERAL_AMOUNT,
    user_collateral_token_account_pubkey,
    user_liquidity_token_account_pubkey,
    reserve_pubkey,
    reserve.collateral.mint_pubkey,
    reserve.liquidity.supply_pubkey,
    lending_market.pubkey,
    user_transfer_authority.pubkey(),
)

偿还

为了偿还,您可以传递一个大于您所借款项的数字来偿还所有款项,例如,您可以将u64::MAX传递进去以偿还所有款项。

repay_obligation_liquidity(
    port_finance_variable_rate_lending::id(),
    liquidity_amount,
    user_liquidity_token_account_pubkey,
    reserve.liquidity.supply_pubkey,
    reserve_pubkey,
    obligation_pubkey,
    lending_market.pubkey,
    user_transfer_authority.pubkey(),
)

清算

请参阅https://github.com/port-finance/liquidator

闪电贷

我们有一个以下签名的闪电贷指令

pub enum LendingInstruction {
    // ....
    /// Make a flash loan.
    ///
    /// Accounts expected by this instruction:
    ///
    ///   0. `[writable]` Source liquidity token account.
    ///                     Minted by reserve liquidity mint.
    ///                     Must match the reserve liquidity supply.
    ///   1. `[writable]` Destination liquidity token account.
    ///                     Minted by reserve liquidity mint.
    ///   2. `[writable]` Reserve account.
    ///   3. `[]` Lending market account.
    ///   4. `[]` Derived lending market authority.
    ///   5. `[]` Flash loan receiver program account.
    ///             Must implement an instruction that has tag of 0 and a signature of `(repay_amount: u64)`
    ///             This instruction must return the amount to the source liquidity account.
    ///   6. `[]` Token program id.
    ///   7. `[writable]` Flash loan fee receiver account.
    ///                     Must match the reserve liquidity fee receiver.
    ///   8. `[writable]` Host fee receiver.
    ///   .. `[any]` Additional accounts expected by the receiving program's `ReceiveFlashLoan` instruction.
    FlashLoan {
        /// The amount that is to be borrowed
        amount: u64,
    },
}

在实现中,我们按以下顺序进行

  1. 执行安全检查和计算费用
  2. 从源流动性账户将amount转账到目标流动性账户
  3. 调用ReceiveFlashLoan函数(闪电贷接收程序必须具有此函数,带有标签0)。所需的额外账户由FlashLoan指令的第10个账户提供,即在托管费接收者之后。
  4. 检查在调用ReceiveFlashLoan函数后,包含费用的返回金额是否在储备账户中。

闪电贷接收程序应有一个ReceiveFlashLoan指令,该指令执行用户定义的操作,并在最后将资金返回到储备账户。

pub enum FlashLoanReceiverInstruction {
	
    /// Receive a flash loan and perform user-defined operation and finally return the fund back.
    ///
    /// Accounts expected:
    ///
    ///   0. `[writable]` Source liquidity (matching the destination from above).
    ///   1. `[writable]` Destination liquidity (matching the source from above).
    ///   2. `[]` Token program id
    ///   .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above.
    ReceiveFlashLoan {
		// Amount that is loaned to the receiver program
        amount: u64
    }
}

您可以在这里查看一个示例实现。

依赖关系

~16–25MB
~425K SLoC