This commit is contained in:
Armani Ferrante 2021-09-18 17:04:28 -05:00
parent 31ceb4e22e
commit a910d583c6
No known key found for this signature in database
GPG Key ID: D597A80BCF8E12B7
3 changed files with 67 additions and 18 deletions

View File

@ -30,6 +30,7 @@ pub mod cfo {
registrar: Pubkey,
msrm_registrar: Pubkey,
swap_interval: i64,
max_swap_usdc: u64,
) -> Result<()> {
let officer = &mut ctx.accounts.officer;
officer.authority = *ctx.accounts.authority.key;
@ -43,6 +44,7 @@ pub mod cfo {
officer.srm_vault = *ctx.accounts.srm_vault.to_account_info().key;
officer.bumps = bumps;
officer.swap_interval = swap_interval;
officer.max_swap_usdc = max_swap_usdc;
emit!(OfficerDidCreate {
pubkey: *officer.to_account_info().key,
});
@ -114,18 +116,34 @@ pub mod cfo {
ctx.accounts.market_auth.last_trade = Clock::get()?.unix_timestamp;
// Trade.
let seeds = [
ctx.accounts.dex_program.key.as_ref(),
&[ctx.accounts.officer.bumps.bump],
];
let cpi_ctx = CpiContext::from(&*ctx.accounts);
swap::cpi::swap(
cpi_ctx.with_signer(&[&seeds]),
swap::Side::Ask,
ctx.accounts.from_vault.amount,
min_exchange_rate.into(),
)
.map_err(Into::into)
let amount_traded_usdc = {
// USDC before the swap.
let usdc_before = ctx.accounts.usdc_vault.amount;
// Swap..
let seeds = [
ctx.accounts.dex_program.key.as_ref(),
&[ctx.accounts.officer.bumps.bump],
];
let cpi_ctx = CpiContext::from(&*ctx.accounts);
swap::cpi::swap(
cpi_ctx.with_signer(&[&seeds]),
swap::Side::Ask,
ctx.accounts.from_vault.amount,
min_exchange_rate.into(),
)?;
// USDC after the swap.
ctx.accounts.usdc_vault.reload()?;
ctx.accounts.usdc_vault.amount - usdc_before
};
// Reject any swap over the max size.
if amount_traded_usdc > ctx.accounts.officer.max_swap_usdc {
return Err(ErrorCode::SwapTooLarge.into());
}
Ok(())
}
/// Convert the CFO's entire token balance into SRM.
@ -151,10 +169,14 @@ pub mod cfo {
swap::cpi::swap(
cpi_ctx.with_signer(&[&seeds]),
swap::Side::Bid,
ctx.accounts.usdc_vault.amount,
std::cmp::min(
ctx.accounts.usdc_vault.amount,
ctx.accounts.officer.max_swap_usdc,
),
min_exchange_rate.into(),
)
.map_err(Into::into)
)?;
Ok(())
}
/// Distributes srm tokens to the various categories. Before calling this,
@ -694,6 +716,8 @@ pub struct Officer {
pub authority: Pubkey,
// Required trade interval in seconds.
pub swap_interval: i64,
// Maximum amount of native USDC that can be swapped in one tx.
pub max_swap_usdc: u64,
// Vault holding the officer's SRM tokens prior to distribution.
pub srm_vault: Pubkey,
// Escrow SRM vault holding tokens which are dropped onto stakers.
@ -935,6 +959,8 @@ pub enum ErrorCode {
InsufficientStakeReward,
#[msg("Swap interval must pass before another trade can occur")]
SwapIntervalBlocked,
#[msg("Swap too large")]
SwapTooLarge,
}
// Access control.

View File

@ -28,6 +28,7 @@ const SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey(
);
const FEES = "6160355581";
const SWAP_INTERVAL = new anchor.BN(1);
const MAX_SWAP_USDC = new anchor.BN(50000000000);
describe("cfo", () => {
anchor.setProvider(anchor.Provider.env());
@ -127,9 +128,23 @@ describe("cfo", () => {
});
it("BOILERPLATE: Sets up the staking pools", async () => {
await setupStakePool(ORDERBOOK_ENV.mintA, ORDERBOOK_ENV.godA);
registrar = ORDERBOOK_ENV.usdc;
msrmRegistrar = registrar;
const {
registrar: _registrar,
rewardEventQ: _rewardEventQ,
poolMint: _poolMint,
} = await setupStakePool(ORDERBOOK_ENV.mintA, ORDERBOOK_ENV.godA);
const {
registrar: _msrmRegistrar,
rewardEventQ: _msrmRewardEventQ,
poolMint: _msrmPoolMint,
} = await setupStakePool(ORDERBOOK_ENV.mintB, ORDERBOOK_ENV.godB);
registrar = _registrar;
rewardEventQ = _rewardEventQ;
poolMint = _poolMint;
msrmRegistrar = _msrmRegistrar;
msrmRewardEventQ = _msrmRewardEventQ;
msrmPoolMint = _msrmPoolMint;
});
it("BOILERPLATE: Finds PDA addresses", async () => {
@ -243,6 +258,7 @@ describe("cfo", () => {
registrar,
msrmRegistrar,
SWAP_INTERVAL,
MAX_SWAP_USDC,
{
accounts: {
officer,

View File

@ -161,6 +161,13 @@ async function setupStakePool(mint, god) {
tokenProgram: TokenInstructions.TOKEN_PROGRAM_ID,
},
});
return {
registrar: registrar.publicKey,
poolMint,
rewardEventQ: rewardQ.publicKey,
member,
};
}
module.exports = {