Token deposit: Require valid oracle for new token positions (#722)

This avoids making an account accidentally or intentionally unusable
(except for deposits/withdraws) by depositing a token with a stale
oracle.
This commit is contained in:
Christian Kamm 2023-09-19 09:08:32 +02:00 committed by GitHub
parent 9b224eae1b
commit 2c4009eab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 2 deletions

View File

@ -179,7 +179,28 @@ pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64, reduce_only: bool)
{
let token_index = ctx.accounts.bank.load()?.token_index;
let mut account = ctx.accounts.account.load_full_mut()?;
account.ensure_token_position(token_index)?;
let token_position_exists = account
.all_token_positions()
.any(|p| p.is_active_for_token(token_index));
// Activating a new token position requires that the oracle is in a good state.
// Otherwise users could abuse oracle staleness to delay liquidation.
if !token_position_exists {
let now_slot = Clock::get()?.slot;
let bank = ctx.accounts.bank.load()?;
let oracle_result = bank.oracle_price(
&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?,
Some(now_slot),
);
if let Err(e) = oracle_result {
msg!("oracle must be valid when creating a new token position");
return Err(e);
}
account.ensure_token_position(token_index)?;
}
}
DepositCommon {

View File

@ -67,7 +67,7 @@ async fn test_stale_oracle_deposit_withdraw() -> Result<(), TransportError> {
.await
.unwrap();
// Make both oracles invalid by increasing deviation
// Make oracles invalid by increasing deviation
send_tx(
solana,
StubOracleSetTestInstruction {
@ -94,6 +94,35 @@ async fn test_stale_oracle_deposit_withdraw() -> Result<(), TransportError> {
)
.await
.unwrap();
send_tx(
solana,
StubOracleSetTestInstruction {
group,
mint: mints[2].pubkey,
admin,
price: 1.0,
last_update_slot: 0,
deviation: 100.0,
},
)
.await
.unwrap();
// Can't activate a token position for a bad oracle
assert!(send_tx(
solana,
TokenDepositInstruction {
amount: 11,
reduce_only: false,
account,
owner,
token_account: payer_token_accounts[2],
token_authority: payer.clone(),
bank_index: 0,
},
)
.await
.is_err());
// Verify that creating a new borrow won't work
assert!(send_tx(