A lending protocol for the Token program on the Solana blockchain inspired by Aave and Compound.
Lending Market: 6T4XxKerq744sSuj3jaoV6QiZ8acirf4TrPwQzHAoSy5
| Asset Name | Reserve Address | | :--- | ----: | | SOL | X9ByyhmtQH3Wjku9N5obPy54DbVjZV7Z99TPJZ2rwcs | | USDC | DcENuKuYd6BWGhKfGr7eARxodqG12Bz1sN5WA8NwvLRx | | USDT | 4tqY9Hv7e8YhNQXuH75WKrZ7tTckbv2GfFVxmVcScW5s | | PAI | DSw99gXoGzvc4N7cNGU7TJ9bCWFq96NU2Cczi1TabDx2 | | SRM | ZgS3sv1tJAor2rbGMFLeJwxsEGDiHkcrR2ZaNHZUpyF | | BTC | DSST29PMCVkxo8cf5ht9LxrPoMc8jAZt98t6nuJywz8p | | MER | BnhsmYVvNjXK3TGDHLj1Yr1jBGCmD1gZMkAyCwoXsHwt | | mSOL | 9gDF5W94RowoDugxT8cM29cX8pKKQitTp2uYVrarBSQ7 | | pSOL | GRJyCEezbZQibAEfBKCRAg5YoTPP2UcRSTC7RfzoMypy |
Actually all the information below you can get by parsing the reserve data. Here is provided for convenience.
| Asset Name | pToken Mint | | :--- | ---: | | SOL | 8ezDtNNhX91t1NbSLe8xV2PcCEfoQjEm2qDVGjt3rjhg | | USDC | FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58 | | USDT | 3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ | | PAI | GaqxUwFGGrDouYLqghchmZU97Y1rNhyF7noMTJNvpQPa | | SRM | 77TBgKmTNtMdGrt1ewNRb56F2Xw6fNLZZj33JZ3oGwXh | | BTC | QN2HkkBaWHfYSU5bybyups9z1UHu8Eu7QeeyMbjD2JA | | MER | 6UgGnLA3Lfe8NBLAESctsUXWdP3zjMFzSLEZxS3tiaKh | | mSOL | Dt1Cuau5m5CSmun8hZstjEh9RszxAmejnq7ZaHNcuXfA |
| Asset Name | Oracle Pubkey | | :--- | ---: | | SOL | H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG | | USDC | N / A | | USDT | 3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL | | PAI | N/A | | SRM | 3NBReDRTLKMQEKiLD5tGcx4kXbTf88b7f2xLS9UuGjym | | BTC | GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU | | MER | G4AQpTYKH1Fmg38VpFQbv6uKYQMpRhJzNPALhp7hqdrs | | pSOL | H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG |
| Asset Name | Supply Public Keys | | :--- | ---: | | SOL | BLAFX12cDmsumyB6k3L6whJZqNqySaWeCmS5rVuzy3SS | | USDC | 2xPnqU4bWhUSjZ74CibY63NrtkHHw5eKntsxf8dzwiid | | USDT | QyvfrbqH7Mo8W5tHN31nzbfNiwFwqPqahjm9fnzo5EJ | | PAI | 42kNZrAuwZHLtuc7jvVX7zMfkfgwbPynqzFB3zdkAEGM | | SRM | DjhMNdgdbxNud1gmc4DUwrQqJxNbjhxiwNnhc4usSXmQ | | BTC | FZKP27Zxz9GbW86hhq3d1egzpBH5ZnYkyjQZVf86NQJ8 | | MER | 6UmrawFZgdPvMe6BLZdZCNRFz9u2TWsu5enFbTufA3a1 |
Program id: pdQ2rQQU5zH2rDgZ7xH2azMBJegUzUyunJ5Jd637hC4
Lending Market: H27Quk3DSbu55T4dCr1NddTTSAezXwHU67FPCZVKLhSW
| Asset Name | Reserve Address | | :--- | ----: | | SOL | 6FeVStQAGPWvfWijDHF7cTWRCi7He6vTT3ubfNhe9SPt | | USDC | G1CcAWGhfxhHQaivC1Sh5CWVta6P4dc7a5BDSg9ERjV1 | | USDT | B4dnCXcWXSXy1g3fGAmF6P2XgsLTFYaQxYpsU3VCB33Q | | BTC | A8krqNC1WpWYhqUe2Y5WbLd1Zy4y2rRN5wJC8o9Scbyk | | MER | FdPnmYS7Ma8jfSy7UHAN5QM6teoqwd3vLQtoU6r2Umwy |
Actually all the information below you can get by parsing the reserve data. Here is provided for convenience.
| Asset Name | pToken Mint | | :--- | ---: | | SOL | So11111111111111111111111111111111111111112 | | USDC | G6YKv19AeGZ6pUYUwY9D7n4Ry9ESNFa376YqwEkUkhbi | | USDT | 9NGDi2tZtNmCCp8SVLKNuGjuWAVwNF3Vap5tT8km5er9 | | BTC | EbwEYuUQHxcSHszxPBhA2nT2JxhiNwJedwjsctJnLmsC | | MER | Tm9LcR74uJHPw3zY3j3nSh5xfcyaLbvXgAtTJwbqnnp |
| Asset Name | pToken Mint | | :--- | ---: | | SOL | Hk4Rp3kaPssB6hnjah3Mrqpt5CAXWGoqFT5dVsWA3TaM | | USDC | HyxraiKfdajDbYTC6MVRToEUBdevBN5M5gfyR4LC3WSF | | USDT | 4xEXmSfLFPkZaxdL98XkoxKpXEvchPVs21GYqa8DvbAm | | BTC | 95XGx3cM83Z1Bbx8pJurAHwxJjvShTJE4BtfgMWfV6NB | | MER | FQzruvtLTk6qtPNEAJHQWMVs4M9UMP9T3cGAVfUskHfP |
| Asset Name | Oracle Pubkey | | :--- | ---: | | SOL | J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix | | USDC | N/A | | USDT | 38xoQ4oeJCBrcVvca2cGk7iV1dAfrmTR1kmhSCJQ8Jto | | BTC | HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J | | MER | 6Z3ejn8DCWQFBuAcw29d3A5jgahEpmycn7YDMX7yRNrn |
| Asset Name | Supply Public Keys | | :--- | ---: | | SOL | AbKeR7nQdHPDddiDQ71YUsz1F138a7cJMfJVtpdYUSvE | | USDC | GAPyFes3o7S7coY9nsuhaRZBEA7DdQPHBfVdY2DdgNua | | USDT | AeGbAqYZUURTykyCsgAUfopBMqQ3eAwrDxYhXoRhiw8q | | BTC | 75iyCxiPoj3MaUVo3SynmhaN3cbLDEhd4d9VHik6Kkvr | | MER | AMjhzse1TtTcKBFw5tQPLGtVoEsL4gt9YowNnzMKEGUr |
For assets that have liquidity mining reward, you need first create a stake account in order to get the reward. First,
get the data of reserve you want deposit into and unpack it to get the field reserve.config.deposit_staking_pool
which
is the staking pool id, and generates the seed and keypair by using the Solana built in sha256
hashing
function solana_sdk::hash::hashv(&[owner.as_ref(), staking_pool.as_ref(), staking_program_id.as_ref()])
, where owner
is the then generate the keypair for stake account by solana_sdk::signer::keypair::keypair_from_seed
. Then
call create_account
and create_stake_account
instruction to create the stake account, where the owner should be your
wallet's public key. Owner need to sign the instruction of claiming reward.
rust
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
)
];
Assuming that you already have your stake account or you are depositing to a reserve without liquidity mining reward, you need refresh all the reserves the obligation has interacted with and the obligation itself in the same instruction before you depositing / withdrawing / repaying / liquidating.
rust
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(),
)
);
rust
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()),
);
rust
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()
)
rust
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),
)
rust
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),
)
There will be a coming withdrawAndRedeem
instruction soon, while it is under auditing. So now, you need first
uncollateralized the asset then withdraw.
rust
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),
)
rust
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(),
)
To repay, you can pass number greater then amount you borrow to repay all, for example you can pass u64::MAX
in to
repay all.
rust
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(),
)