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
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_account
和 create_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,
},
}
在实现中,我们按以下顺序进行
- 执行安全检查和计算费用
- 从源流动性账户将
amount
转账到目标流动性账户 - 调用
ReceiveFlashLoan
函数(闪电贷接收程序必须具有此函数,带有标签0
)。所需的额外账户由FlashLoan
指令的第10个账户提供,即在托管费接收者之后。 - 检查在调用
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