Deposit: Extend the lookup table with bank and oracle

When the position goes from inactive to active.
This commit is contained in:
Christian Kamm 2022-02-28 19:38:45 +01:00
parent 9a50325718
commit 5ebf425a65
3 changed files with 93 additions and 12 deletions

View File

@ -52,6 +52,28 @@ pub fn create_account(
// Setup the address lookup table
//
// First: Pre-pay for max-length address lookup table -- otherwise extending it
// (later, in deposit etc) will need a payer!
let rent = Rent::get()?;
let required_lamports = rent
.minimum_balance(solana_address_lookup_table_instruction::LOOKUP_TABLE_MAX_ACCOUNT_SIZE)
.max(1)
.saturating_sub(ctx.accounts.address_lookup_table.lamports());
if required_lamports > 0 {
solana_program::program::invoke(
&solana_program::system_instruction::transfer(
&ctx.accounts.payer.key(),
&ctx.accounts.address_lookup_table.key(),
required_lamports,
),
&[
ctx.accounts.payer.to_account_info(),
ctx.accounts.address_lookup_table.to_account_info(),
ctx.accounts.system_program.to_account_info(),
],
)?;
}
// Now create the account.
// TODO: We could save some CU here by not using create_lookup_table():
// it - unnecessarily - derives the lookup table address again.
let (instruction, _expected_adress_map_address) =

View File

@ -3,6 +3,7 @@ use anchor_spl::token;
use anchor_spl::token::Token;
use anchor_spl::token::TokenAccount;
use crate::solana_address_lookup_table_instruction;
use crate::state::*;
#[derive(Accounts)]
@ -54,21 +55,68 @@ impl<'info> Deposit<'info> {
// That would save a lot of computation that needs to go into finding the
// right index for the mint.
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
// Find the mint's token index
let group = ctx.accounts.group.load()?;
let mint = ctx.accounts.token_account.mint;
let token_index = group.tokens.index_for_mint(&mint)?;
let (is_new, oracle) = {
// Find the mint's token index
let group = ctx.accounts.group.load()?;
let mint = ctx.accounts.token_account.mint;
let token_index = group.tokens.index_for_mint(&mint)?;
// Get the account's position for that token index
let mut account = ctx.accounts.account.load_mut()?;
let position = account.indexed_positions.get_mut_or_create(token_index)?;
// Get the account's position for that token index
let mut account = ctx.accounts.account.load_mut()?;
let position = account.indexed_positions.get_mut_or_create(token_index)?;
let is_new = !position.is_active();
// Update the bank and position
let mut bank = ctx.accounts.bank.load_mut()?;
bank.deposit(position, amount);
// Update the bank and position
let mut bank = ctx.accounts.bank.load_mut()?;
bank.deposit(position, amount);
// Transfer the actual tokens
token::transfer(ctx.accounts.transfer_ctx(), amount)?;
// Transfer the actual tokens
token::transfer(ctx.accounts.transfer_ctx(), amount)?;
(is_new, bank.oracle)
};
// TODO: Also check if these accounts are already on the table? Otherwise a deposit-withdraw
// cycle would quickly fill up the lookup table with the same two accounts!
if is_new {
// Add the bank and oracle to the address map
//
// NOTE: Unfortunately extend() _requires_ a payer, even though we've already
// fully funded the address lookup table. No further transfer will be necessary.
// We'll pass the account as payer.
let mut instruction = solana_address_lookup_table_instruction::extend_lookup_table(
ctx.accounts.address_lookup_table.key(),
ctx.accounts.account.key(),
ctx.accounts.account.key(),
vec![ctx.accounts.bank.key(), oracle],
);
// Sneakily remove the system_program account: that way any attempted transfer would error.
instruction.accounts.pop();
let account_infos = [
ctx.accounts.address_lookup_table.to_account_info(),
ctx.accounts.account.to_account_info(),
ctx.accounts.account.to_account_info(),
];
// Signing for the account is complicated because it must work as a payer which means
// a mutable borrow. Thus we must make copies of the values in the seed.
struct AccountSeedValues {
group: Pubkey,
owner: Pubkey,
account_num: u8,
bump: u8,
}
let account_seed_values = {
let account = ctx.accounts.account.load()?;
AccountSeedValues {
group: account.group,
owner: account.owner,
account_num: account.account_num,
bump: account.bump,
}
};
let account_seeds = account_seeds!(account_seed_values);
solana_program::program::invoke_signed(&instruction, &account_infos, &[account_seeds])?;
}
Ok(())
}

View File

@ -13,10 +13,21 @@ use {
std::str::FromStr,
};
// NOTE: Manual additions start
pub fn id() -> Pubkey {
Pubkey::from_str(&"AddressLookupTab1e1111111111111111111111111").unwrap()
}
/// The maximum number of addresses that a lookup table can hold
pub const LOOKUP_TABLE_MAX_ADDRESSES: usize = 256;
/// The serialized size of lookup table metadata
pub const LOOKUP_TABLE_META_SIZE: usize = 56;
pub const LOOKUP_TABLE_MAX_ACCOUNT_SIZE: usize =
LOOKUP_TABLE_META_SIZE + LOOKUP_TABLE_MAX_ADDRESSES * 32;
// NOTE: Manual additions end
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum ProgramInstruction {
/// Create an address lookup table