Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sdk: add liquidate #30

Merged
merged 1 commit into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions programs/drift_vaults/src/state/vault_depositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,4 +986,62 @@ mod tests {
assert_eq!(withdraw_amount, 50000000);
assert_eq!(vd.cumulative_profit_share_amount, 0); // $0
}

#[test]
fn test_vault_depositor_request_in_profit_withdraw_in_loss() {
// test for vault depositor who requests withdraw when in pofit
// then waits redeem period for withdraw
// upon withdraw, vault depositor is in loss even though they withdrew in profit
// should get withdraw vaulation and not break invariants

let now = 1000;
let vault = &mut Vault::default();

let vd =
&mut VaultDepositor::new(Pubkey::default(), Pubkey::default(), Pubkey::default(), now);

let mut vault_equity: u64 = 100 * QUOTE_PRECISION_U64;
let amount: u64 = 100 * QUOTE_PRECISION_U64;
vd.deposit(amount, vault_equity, vault, now).unwrap();
assert_eq!(vd.vault_shares_base, 0);
assert_eq!(vd.checked_vault_shares(vault).unwrap(), 100000000);
assert_eq!(vault.user_shares, 100000000);
assert_eq!(vault.total_shares, 200000000);

vault.profit_share = 100000; // 10% profit share
vault.redeem_period = 3600; // 1 hour
vault_equity = 200 * QUOTE_PRECISION_U64;

assert_eq!(vd.checked_vault_shares(vault).unwrap(), 100000000);
assert_eq!(vd.cumulative_profit_share_amount, 0); // $0
assert_eq!(vault.user_shares, 100000000);
assert_eq!(vault.total_shares, 200000000);

// let vault_before = vault;
vd.realize_profits(vault_equity, vault, now).unwrap(); // should be noop

// request withdraw all
vd.request_withdraw(
PERCENTAGE_PRECISION,
WithdrawUnit::SharesPercent,
vault_equity,
vault,
now + 20,
)
.unwrap();
assert_eq!(vd.checked_vault_shares(vault).unwrap(), 100000000);

assert_eq!(vd.last_withdraw_request_value, 100000000);
assert_eq!(vd.last_withdraw_request_ts, now + 20);

vault_equity /= 5; // down 80%

let (withdraw_amount, _ll) = vd.withdraw(vault_equity, vault, now + 20 + 3600).unwrap();
assert_eq!(vd.checked_vault_shares(vault).unwrap(), 0);
assert_eq!(vd.vault_shares_base, 0);
assert_eq!(vault.user_shares, 0);
assert_eq!(vault.total_shares, 100000000);
assert_eq!(withdraw_amount, 20000000); // getting back 20% of deposit
assert_eq!(vd.cumulative_profit_share_amount, 0); // $0
}
}
61 changes: 61 additions & 0 deletions ts/sdk/src/vaultClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,67 @@ export class VaultClient {
}
}

/**
* Liquidates (become delegate for) a vault.
* @param
* @param
* @returns
*/
public async liquidate(
vaultDepositor: PublicKey
): Promise<TransactionSignature> {
const vaultDepositorAccount =
await this.program.account.vaultDepositor.fetch(vaultDepositor);
const vaultPubKey = vaultDepositorAccount.vault;

const vaultAccount = await this.program.account.vault.fetch(vaultPubKey);

const user = new User({
driftClient: this.driftClient,
userAccountPublicKey: vaultAccount.user,
});
await user.subscribe();
const remainingAccounts = this.driftClient.getRemainingAccounts({
userAccounts: [user.getUserAccount()],
writableSpotMarketIndexes: [vaultAccount.spotMarketIndex],
});

const userStatsKey = getUserStatsAccountPublicKey(
this.driftClient.program.programId,
vaultPubKey
);

const driftStateKey = await this.driftClient.getStatePublicKey();

const accounts = {
vault: vaultPubKey,
vaultDepositor,
vaultTokenAccount: vaultAccount.tokenAccount,
driftUserStats: userStatsKey,
driftUser: vaultAccount.user,
driftState: driftStateKey,
driftProgram: this.driftClient.program.programId,
};

if (this.cliMode) {
return await this.program.methods
.liquidate()
.accounts(accounts)
.remainingAccounts(remainingAccounts)
.rpc();
} else {
const liquidateIx = this.program.instruction.liquidate({
accounts: {
authority: this.driftClient.wallet.publicKey,
...accounts,
},
remainingAccounts,
});

return await this.createAndSendTxn(liquidateIx);
}
}

/**
* Used for UI wallet adapters compatibility
*/
Expand Down
Loading