registry: Use correct timelock and transition entity state on reward claim (#59)

This commit is contained in:
Armani Ferrante 2020-12-10 00:04:00 -08:00 committed by GitHub
parent d2d5e287d5
commit 0704adde56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 94 deletions

View File

@ -1,13 +1,15 @@
use crate::common::entity::{with_entity, EntityContext};
use serum_common::pack::Pack; use serum_common::pack::Pack;
use serum_lockup::instruction::LockupInstruction; use serum_lockup::instruction::LockupInstruction;
use serum_registry::access_control; use serum_registry::access_control;
use serum_registry::accounts::{EntityState, LockedRewardVendor, Member}; use serum_registry::accounts::{Entity, EntityState, LockedRewardVendor, Member, Registrar};
use serum_registry::error::{RegistryError, RegistryErrorCode}; use serum_registry::error::{RegistryError, RegistryErrorCode};
use solana_program::msg; use solana_program::msg;
use solana_sdk::account_info::{next_account_info, AccountInfo}; use solana_sdk::account_info::{next_account_info, AccountInfo};
use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::sysvar; use solana_sdk::sysvar;
use solana_sdk::sysvar::clock::Clock;
use spl_token::state::Account as TokenAccount; use spl_token::state::Account as TokenAccount;
#[inline(never)] #[inline(never)]
@ -41,49 +43,58 @@ pub fn handler(
spt_acc_infos.push(next_account_info(acc_infos)?); spt_acc_infos.push(next_account_info(acc_infos)?);
} }
let AccessControlResponse { let ctx = EntityContext {
ref vendor,
ref spts,
ref clock,
} = access_control(AccessControlRequest {
program_id,
signer_acc_info,
registrar_acc_info,
entity_acc_info, entity_acc_info,
member_acc_info, registrar_acc_info,
vendor_acc_info,
cursor,
spt_acc_infos,
clock_acc_info, clock_acc_info,
})?; program_id,
};
with_entity(ctx, &mut |entity: &mut Entity,
registrar: &Registrar,
ref clock: &Clock| {
let AccessControlResponse {
ref vendor,
ref spts,
} = access_control(AccessControlRequest {
program_id,
entity,
registrar,
signer_acc_info,
registrar_acc_info,
entity_acc_info,
member_acc_info,
vendor_acc_info,
cursor,
spt_acc_infos: spt_acc_infos.as_ref(),
})?;
Member::unpack_mut( Member::unpack_mut(
&mut member_acc_info.try_borrow_mut_data()?, &mut member_acc_info.try_borrow_mut_data()?,
&mut |member: &mut Member| { &mut |member: &mut Member| {
state_transition(StateTransitionRequest { state_transition(StateTransitionRequest {
cursor, cursor,
nonce, nonce,
member, member,
vendor, vendor,
registrar_acc_info, registrar_acc_info,
vendor_acc_info, vendor_acc_info,
vendor_vault_authority_acc_info, vendor_vault_authority_acc_info,
safe_acc_info, safe_acc_info,
lockup_program_acc_info, lockup_program_acc_info,
vesting_acc_info, vesting_acc_info,
vesting_vault_acc_info, vesting_vault_acc_info,
vendor_vault_acc_info, vendor_vault_acc_info,
token_program_acc_info, token_program_acc_info,
rent_acc_info, rent_acc_info,
clock_acc_info, clock_acc_info,
clock, clock,
spts, spts,
}) })
.map_err(Into::into) .map_err(Into::into)
}, },
)?; )
.map_err(Into::into)
Ok(()) })
} }
fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, RegistryError> { fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, RegistryError> {
@ -92,13 +103,14 @@ fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, Re
let AccessControlRequest { let AccessControlRequest {
program_id, program_id,
cursor, cursor,
registrar,
entity,
signer_acc_info, signer_acc_info,
registrar_acc_info, registrar_acc_info,
entity_acc_info, entity_acc_info,
member_acc_info, member_acc_info,
vendor_acc_info, vendor_acc_info,
spt_acc_infos, spt_acc_infos,
clock_acc_info,
} = req; } = req;
// Authorization. Must be either the beneficiary or the node leader. // Authorization. Must be either the beneficiary or the node leader.
@ -107,9 +119,6 @@ fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, Re
} }
// Account validation. // Account validation.
let clock = access_control::clock(clock_acc_info)?;
let registrar = access_control::registrar(registrar_acc_info, program_id)?;
let entity = access_control::entity(entity_acc_info, registrar_acc_info, program_id)?;
let member = access_control::member_belongs_to( let member = access_control::member_belongs_to(
member_acc_info, member_acc_info,
registrar_acc_info, registrar_acc_info,
@ -159,11 +168,7 @@ fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, Re
return Err(RegistryErrorCode::Unauthorized)?; return Err(RegistryErrorCode::Unauthorized)?;
} }
Ok(AccessControlResponse { Ok(AccessControlResponse { vendor, spts })
vendor,
spts,
clock,
})
} }
fn state_transition(req: StateTransitionRequest) -> Result<(), RegistryError> { fn state_transition(req: StateTransitionRequest) -> Result<(), RegistryError> {
@ -259,22 +264,22 @@ fn state_transition(req: StateTransitionRequest) -> Result<(), RegistryError> {
Ok(()) Ok(())
} }
struct AccessControlRequest<'a, 'b> { struct AccessControlRequest<'a, 'b, 'c> {
program_id: &'a Pubkey, program_id: &'a Pubkey,
cursor: u32, cursor: u32,
entity: &'c Entity,
registrar: &'c Registrar,
signer_acc_info: &'a AccountInfo<'b>, signer_acc_info: &'a AccountInfo<'b>,
entity_acc_info: &'a AccountInfo<'b>, entity_acc_info: &'a AccountInfo<'b>,
member_acc_info: &'a AccountInfo<'b>, member_acc_info: &'a AccountInfo<'b>,
registrar_acc_info: &'a AccountInfo<'b>, registrar_acc_info: &'a AccountInfo<'b>,
vendor_acc_info: &'a AccountInfo<'b>, vendor_acc_info: &'a AccountInfo<'b>,
spt_acc_infos: Vec<&'a AccountInfo<'b>>, spt_acc_infos: &'c [&'a AccountInfo<'b>],
clock_acc_info: &'a AccountInfo<'b>,
} }
struct AccessControlResponse { struct AccessControlResponse {
vendor: LockedRewardVendor, vendor: LockedRewardVendor,
spts: Vec<TokenAccount>, spts: Vec<TokenAccount>,
clock: sysvar::clock::Clock,
} }
struct StateTransitionRequest<'a, 'b, 'c> { struct StateTransitionRequest<'a, 'b, 'c> {

View File

@ -1,11 +1,13 @@
use crate::common::entity::{with_entity, EntityContext};
use serum_common::pack::Pack; use serum_common::pack::Pack;
use serum_common::program::invoke_token_transfer; use serum_common::program::invoke_token_transfer;
use serum_registry::access_control; use serum_registry::access_control;
use serum_registry::accounts::{EntityState, Member, UnlockedRewardVendor}; use serum_registry::accounts::{Entity, EntityState, Member, Registrar, UnlockedRewardVendor};
use serum_registry::error::{RegistryError, RegistryErrorCode}; use serum_registry::error::{RegistryError, RegistryErrorCode};
use solana_program::msg; use solana_program::msg;
use solana_sdk::account_info::{next_account_info, AccountInfo}; use solana_sdk::account_info::{next_account_info, AccountInfo};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::sysvar::clock::Clock;
use spl_token::state::Account as TokenAccount; use spl_token::state::Account as TokenAccount;
#[inline(never)] #[inline(never)]
@ -27,47 +29,59 @@ pub fn handler(
let vendor_vault_authority_acc_info = next_account_info(acc_infos)?; let vendor_vault_authority_acc_info = next_account_info(acc_infos)?;
let token_acc_info = next_account_info(acc_infos)?; let token_acc_info = next_account_info(acc_infos)?;
let token_program_acc_info = next_account_info(acc_infos)?; let token_program_acc_info = next_account_info(acc_infos)?;
let clock_acc_info = next_account_info(acc_infos)?;
let mut spt_acc_infos = vec![]; let mut spt_acc_infos = vec![];
while acc_infos.len() > 0 { while acc_infos.len() > 0 {
spt_acc_infos.push(next_account_info(acc_infos)?); spt_acc_infos.push(next_account_info(acc_infos)?);
} }
let AccessControlResponse { let ctx = EntityContext {
ref vendor,
ref spts,
} = access_control(AccessControlRequest {
program_id,
signer_acc_info,
registrar_acc_info,
entity_acc_info, entity_acc_info,
member_acc_info, registrar_acc_info,
vendor_acc_info, clock_acc_info,
token_acc_info, program_id,
cursor, };
spt_acc_infos, with_entity(ctx, &mut |entity: &mut Entity,
})?; registrar: &Registrar,
_clock: &Clock| {
let AccessControlResponse {
ref vendor,
ref spts,
} = access_control(AccessControlRequest {
program_id,
signer_acc_info,
registrar_acc_info,
entity_acc_info,
member_acc_info,
vendor_acc_info,
token_acc_info,
cursor,
registrar,
entity,
spt_acc_infos: spt_acc_infos.as_ref(),
})?;
Member::unpack_mut( Member::unpack_mut(
&mut member_acc_info.try_borrow_mut_data()?, &mut member_acc_info.try_borrow_mut_data()?,
&mut |member: &mut Member| { &mut |member: &mut Member| {
state_transition(StateTransitionRequest { state_transition(StateTransitionRequest {
cursor, cursor,
member, member,
vendor, vendor,
registrar_acc_info, registrar_acc_info,
vendor_acc_info, vendor_acc_info,
vendor_vault_authority_acc_info, vendor_vault_authority_acc_info,
vendor_vault_acc_info, vendor_vault_acc_info,
token_acc_info, token_acc_info,
token_program_acc_info, token_program_acc_info,
spts, spts,
}) })
.map_err(Into::into) .map_err(Into::into)
}, },
)?; )
.map_err(Into::into)
Ok(()) })
} }
fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, RegistryError> { fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, RegistryError> {
@ -76,6 +90,8 @@ fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, Re
let AccessControlRequest { let AccessControlRequest {
program_id, program_id,
cursor, cursor,
registrar,
entity,
signer_acc_info, signer_acc_info,
registrar_acc_info, registrar_acc_info,
entity_acc_info, entity_acc_info,
@ -91,8 +107,6 @@ fn access_control(req: AccessControlRequest) -> Result<AccessControlResponse, Re
} }
// Account validation. // Account validation.
let registrar = access_control::registrar(registrar_acc_info, program_id)?;
let entity = access_control::entity(entity_acc_info, registrar_acc_info, program_id)?;
let member = access_control::member_belongs_to( let member = access_control::member_belongs_to(
member_acc_info, member_acc_info,
registrar_acc_info, registrar_acc_info,
@ -190,16 +204,18 @@ fn state_transition(req: StateTransitionRequest) -> Result<(), RegistryError> {
Ok(()) Ok(())
} }
struct AccessControlRequest<'a, 'b> { struct AccessControlRequest<'a, 'b, 'c> {
program_id: &'a Pubkey, program_id: &'a Pubkey,
cursor: u32, cursor: u32,
registrar: &'c Registrar,
entity: &'c Entity,
signer_acc_info: &'a AccountInfo<'b>, signer_acc_info: &'a AccountInfo<'b>,
entity_acc_info: &'a AccountInfo<'b>, entity_acc_info: &'a AccountInfo<'b>,
member_acc_info: &'a AccountInfo<'b>, member_acc_info: &'a AccountInfo<'b>,
registrar_acc_info: &'a AccountInfo<'b>, registrar_acc_info: &'a AccountInfo<'b>,
vendor_acc_info: &'a AccountInfo<'b>, vendor_acc_info: &'a AccountInfo<'b>,
token_acc_info: &'a AccountInfo<'b>, token_acc_info: &'a AccountInfo<'b>,
spt_acc_infos: Vec<&'a AccountInfo<'b>>, spt_acc_infos: &'c [&'a AccountInfo<'b>],
} }
struct AccessControlResponse { struct AccessControlResponse {

View File

@ -231,7 +231,7 @@ fn state_transition(req: StateTransitionRequest) -> Result<(), RegistryError> {
pending_withdrawal.burned = false; pending_withdrawal.burned = false;
pending_withdrawal.member = *member_acc_info.key; pending_withdrawal.member = *member_acc_info.key;
pending_withdrawal.start_ts = clock.unix_timestamp; pending_withdrawal.start_ts = clock.unix_timestamp;
pending_withdrawal.end_ts = clock.unix_timestamp + registrar.deactivation_timelock; pending_withdrawal.end_ts = clock.unix_timestamp + registrar.withdrawal_timelock;
pending_withdrawal.amount = token_amount; pending_withdrawal.amount = token_amount;
pending_withdrawal.pool = *pool_mint_acc_info.key; pending_withdrawal.pool = *pool_mint_acc_info.key;
pending_withdrawal.balance_id = *balance_id; pending_withdrawal.balance_id = *balance_id;

View File

@ -35,7 +35,7 @@ fn lifecycle() {
} = genesis; } = genesis;
// Initialize the registrar. // Initialize the registrar.
let withdrawal_timelock = 1234; let withdrawal_timelock = 10;
let deactivation_timelock = 10; let deactivation_timelock = 10;
let reward_activation_threshold = 10; let reward_activation_threshold = 10;
let max_stake_per_entity = 100_000_000_000_000; let max_stake_per_entity = 100_000_000_000_000;