Token-lending program

A lending protocol for the Token program on the Solana blockchain inspired by Aave and Compound.

Public Keys for Port Finance

Mainnet

Lending Market: 6T4XxKerq744sSuj3jaoV6QiZ8acirf4TrPwQzHAoSy5

Reserve Public Keys

| Asset Name | Reserve Address | | :--- | ----: | | SOL | X9ByyhmtQH3Wjku9N5obPy54DbVjZV7Z99TPJZ2rwcs | | USDC | DcENuKuYd6BWGhKfGr7eARxodqG12Bz1sN5WA8NwvLRx | | USDT | 4tqY9Hv7e8YhNQXuH75WKrZ7tTckbv2GfFVxmVcScW5s | | PAI | DSw99gXoGzvc4N7cNGU7TJ9bCWFq96NU2Cczi1TabDx2 | | SRM | ZgS3sv1tJAor2rbGMFLeJwxsEGDiHkcrR2ZaNHZUpyF | | BTC | DSST29PMCVkxo8cf5ht9LxrPoMc8jAZt98t6nuJywz8p | | MER | BnhsmYVvNjXK3TGDHLj1Yr1jBGCmD1gZMkAyCwoXsHwt | | mSOL | 9gDF5W94RowoDugxT8cM29cX8pKKQitTp2uYVrarBSQ7 | | pSOL | GRJyCEezbZQibAEfBKCRAg5YoTPP2UcRSTC7RfzoMypy |

pToken Mint

| Asset Name | pToken Mint | | :--- | ---: | | SOL | 8ezDtNNhX91t1NbSLe8xV2PcCEfoQjEm2qDVGjt3rjhg | | USDC | FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58 | | USDT | 3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ | | PAI | GaqxUwFGGrDouYLqghchmZU97Y1rNhyF7noMTJNvpQPa | | SRM | 77TBgKmTNtMdGrt1ewNRb56F2Xw6fNLZZj33JZ3oGwXh | | BTC | QN2HkkBaWHfYSU5bybyups9z1UHu8Eu7QeeyMbjD2JA | | MER | 6UgGnLA3Lfe8NBLAESctsUXWdP3zjMFzSLEZxS3tiaKh | | mSOL | Dt1Cuau5m5CSmun8hZstjEh9RszxAmejnq7ZaHNcuXfA |

Oracle Public Keys

| Asset Name | Oracle Pubkey | | :--- | ---: | | SOL | H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG | | USDC | N / A | | USDT | 3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL | | PAI | N/A | | SRM | 3NBReDRTLKMQEKiLD5tGcx4kXbTf88b7f2xLS9UuGjym | | BTC | GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU | | MER | G4AQpTYKH1Fmg38VpFQbv6uKYQMpRhJzNPALhp7hqdrs | | pSOL | H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG |

Supply Public Keys

| Asset Name | Supply Public Keys | | :--- | ---: | | SOL | BLAFX12cDmsumyB6k3L6whJZqNqySaWeCmS5rVuzy3SS | | USDC | 2xPnqU4bWhUSjZ74CibY63NrtkHHw5eKntsxf8dzwiid | | USDT | QyvfrbqH7Mo8W5tHN31nzbfNiwFwqPqahjm9fnzo5EJ | | PAI | 42kNZrAuwZHLtuc7jvVX7zMfkfgwbPynqzFB3zdkAEGM | | SRM | DjhMNdgdbxNud1gmc4DUwrQqJxNbjhxiwNnhc4usSXmQ | | BTC | FZKP27Zxz9GbW86hhq3d1egzpBH5ZnYkyjQZVf86NQJ8 | | MER | 6UmrawFZgdPvMe6BLZdZCNRFz9u2TWsu5enFbTufA3a1 |

Dev Net

Lending Market: H27Quk3DSbu55T4dCr1NddTTSAezXwHU67FPCZVKLhSW

Reserve Public Keys

| Asset Name | Reserve Address | | :--- | ----: | | SOL | 6FeVStQAGPWvfWijDHF7cTWRCi7He6vTT3ubfNhe9SPt | | USDC | G1CcAWGhfxhHQaivC1Sh5CWVta6P4dc7a5BDSg9ERjV1 |

pToken Mint

| Asset Name | pToken Mint | | :--- | ---: | | SOL | Hk4Rp3kaPssB6hnjah3Mrqpt5CAXWGoqFT5dVsWA3TaM | | USDC | HyxraiKfdajDbYTC6MVRToEUBdevBN5M5gfyR4LC3WSF |

Oracle Public Keys

| Asset Name | Oracle Pubkey | | :--- | ---: | | SOL | J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix | | USDC | N/A |

Supply Public Keys

| Asset Name | Supply Public Keys | | :--- | ---: | | SOL | AbKeR7nQdHPDddiDQ71YUsz1F138a7cJMfJVtpdYUSvE | | USDC | GAPyFes3o7S7coY9nsuhaRZBEA7DdQPHBfVdY2DdgNua |

Create StakeAccount

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 ) ];

Refresh Reserves and Obligation

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(), ) );

Initialize Obligation

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()), );

Deposit Liquidity / Collateralize

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), )

Withdraw

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(), )

Repay

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(), )