diff --git a/programs/castle-lending-aggregator/src/instructions/mod.rs b/programs/castle-lending-aggregator/src/instructions/mod.rs index 14ae0f2..c5b2d75 100644 --- a/programs/castle-lending-aggregator/src/instructions/mod.rs +++ b/programs/castle-lending-aggregator/src/instructions/mod.rs @@ -3,6 +3,7 @@ pub mod init; pub mod rebalance; pub mod reconcile; pub mod refresh; +pub mod update_deposit_cap; pub mod withdraw; pub use deposit::*; @@ -10,4 +11,5 @@ pub use init::*; pub use rebalance::*; pub use reconcile::*; pub use refresh::*; +pub use update_deposit_cap::*; pub use withdraw::*; diff --git a/programs/castle-lending-aggregator/src/instructions/update_deposit_cap.rs b/programs/castle-lending-aggregator/src/instructions/update_deposit_cap.rs new file mode 100644 index 0000000..2e0d703 --- /dev/null +++ b/programs/castle-lending-aggregator/src/instructions/update_deposit_cap.rs @@ -0,0 +1,23 @@ +use anchor_lang::prelude::*; + +use crate::state::Vault; +use std::convert::Into; + +#[derive(Accounts)] +pub struct UpdateDepositCap<'info> { + #[account( + mut, + has_one = owner, + )] + pub vault: Box>, + + pub owner: Signer<'info>, +} + +pub fn handler(ctx: Context, deposit_cap_new_value: u64) -> ProgramResult { + #[cfg(feature = "debug")] + msg!("New deposit cap value: {}", deposit_cap_new_value); + + ctx.accounts.vault.pool_size_limit = deposit_cap_new_value; + Ok(()) +} diff --git a/programs/castle-lending-aggregator/src/lib.rs b/programs/castle-lending-aggregator/src/lib.rs index 42901f0..991a938 100644 --- a/programs/castle-lending-aggregator/src/lib.rs +++ b/programs/castle-lending-aggregator/src/lib.rs @@ -27,11 +27,18 @@ pub mod castle_lending_aggregator { _bumps: InitBumpSeeds, strategy_type: StrategyType, fees: FeeArgs, - pool_size_limit: u64 + pool_size_limit: u64, ) -> ProgramResult { instructions::init::handler(ctx, _bumps, strategy_type, fees, pool_size_limit) } + pub fn update_deposit_cap( + ctx: Context, + deposit_cap_new_value: u64, + ) -> ProgramResult { + instructions::update_deposit_cap::handler(ctx, deposit_cap_new_value) + } + pub fn deposit(ctx: Context, reserve_token_amount: u64) -> ProgramResult { instructions::deposit::handler(ctx, reserve_token_amount) } diff --git a/sdk/src/castle_lending_aggregator.ts b/sdk/src/castle_lending_aggregator.ts index 6933e39..4b251f9 100644 --- a/sdk/src/castle_lending_aggregator.ts +++ b/sdk/src/castle_lending_aggregator.ts @@ -146,6 +146,27 @@ export type CastleLendingAggregator = { } ]; }, + { + name: "updateDepositCap"; + accounts: [ + { + name: "vault"; + isMut: true; + isSigner: false; + }, + { + name: "owner"; + isMut: false; + isSigner: true; + } + ]; + args: [ + { + name: "depositCapNewValue"; + type: "u64"; + } + ]; + }, { name: "deposit"; accounts: [ @@ -1117,6 +1138,27 @@ export const IDL: CastleLendingAggregator = { }, ], }, + { + name: "updateDepositCap", + accounts: [ + { + name: "vault", + isMut: true, + isSigner: false, + }, + { + name: "owner", + isMut: false, + isSigner: true, + }, + ], + args: [ + { + name: "depositCapNewValue", + type: "u64", + }, + ], + }, { name: "deposit", accounts: [ diff --git a/sdk/src/client.ts b/sdk/src/client.ts index b8862ba..90278cf 100644 --- a/sdk/src/client.ts +++ b/sdk/src/client.ts @@ -70,7 +70,7 @@ export class VaultClient { return new VaultClient(program, vaultId, vaultState, solend, port, jet); } - private async reload() { + async reload() { this.vaultState = await this.program.account.vault.fetch(this.vaultId); // TODO reload underlying asset data also? } @@ -292,6 +292,29 @@ export class VaultClient { }; } + /** + * @param new_value + * @returns + */ + async updateDepositCap( + owner: Keypair, + new_value: number + ): Promise { + const updateCommand = new Transaction(); + updateCommand.add( + this.program.instruction.updateDepositCap( + new anchor.BN(new_value), + { + accounts: { + vault: this.vaultId, + owner: owner.publicKey, + }, + } + ) + ); + return [await this.program.provider.send(updateCommand, [owner])]; + } + /** * * TODO refactor to be more clear diff --git a/tests/castle-lending-aggregator.ts b/tests/castle-lending-aggregator.ts index 81b0cbe..3c6b7db 100644 --- a/tests/castle-lending-aggregator.ts +++ b/tests/castle-lending-aggregator.ts @@ -370,7 +370,7 @@ describe("castle-vault", () => { await mintReserveToken(userReserveTokenAccount, qty); try { await depositToVault(qty); - assert.ok(false); + assert.fail("Deposit should be rejected but was not."); } catch (err) { // TODO check err } @@ -387,6 +387,51 @@ describe("castle-vault", () => { assert.equal(userLpBalance, 0); assert.equal(lpTokenSupply, 0); }); + + it("Update deposit cap", async function () { + const newDepositCap = poolSizeLimit * 0.24; + const txs = await vaultClient.updateDepositCap( + owner, + newDepositCap + ); + await provider.connection.confirmTransaction( + txs[txs.length - 1], + "singleGossip" + ); + await vaultClient.reload(); + assert.equal( + newDepositCap, + vaultClient.vaultState.poolSizeLimit.toNumber() + ); + }); + + it("Reject unauthorized deposit cap update", async function () { + const noPermissionUser = Keypair.generate(); + + const prevDepositCap = + vaultClient.vaultState.poolSizeLimit.toNumber(); + const newDepositCap = prevDepositCap * 0.24; + + try { + const txs = await vaultClient.updateDepositCap( + noPermissionUser, + newDepositCap + ); + await provider.connection.confirmTransaction( + txs[txs.length - 1], + "singleGossip" + ); + assert.fail("Transaction should be rejected but was not."); + } catch (err) { + // TODO check err + } + + await vaultClient.reload(); + assert.equal( + prevDepositCap, + vaultClient.vaultState.poolSizeLimit.toNumber() + ); + }); } function testRebalance(