2019-10-04 14:43:50 -07:00
//! vest program
use crate ::{
vest_instruction ::{ VestError , VestInstruction } ,
vest_state ::VestState ,
} ;
use chrono ::prelude ::* ;
2019-11-22 15:10:53 -08:00
use solana_config_program ::date_instruction ::DateConfig ;
2019-11-20 10:12:43 -08:00
use solana_config_program ::get_config_data ;
2019-10-04 14:43:50 -07:00
use solana_sdk ::{
account ::{ Account , KeyedAccount } ,
instruction ::InstructionError ,
2020-02-05 12:48:30 -08:00
program_utils ::{ limited_deserialize , next_keyed_account } ,
2019-10-04 14:43:50 -07:00
pubkey ::Pubkey ,
} ;
2020-01-22 09:11:56 -08:00
use std ::cell ::RefMut ;
2019-10-04 14:43:50 -07:00
2019-10-10 07:54:18 -07:00
fn verify_date_account (
2020-01-22 17:54:06 -08:00
keyed_account : & KeyedAccount ,
2019-10-04 14:43:50 -07:00
expected_pubkey : & Pubkey ,
) -> Result < Date < Utc > , InstructionError > {
2020-01-22 09:11:56 -08:00
if keyed_account . owner ( ) ? ! = solana_config_program ::id ( ) {
2019-10-04 14:43:50 -07:00
return Err ( InstructionError ::IncorrectProgramId ) ;
}
2019-10-10 07:54:18 -07:00
let account = verify_account ( keyed_account , expected_pubkey ) ? ;
2019-10-04 14:43:50 -07:00
let config_data =
get_config_data ( & account . data ) . map_err ( | _ | InstructionError ::InvalidAccountData ) ? ;
let date_config =
2019-10-10 21:35:10 -07:00
DateConfig ::deserialize ( config_data ) . ok_or ( InstructionError ::InvalidAccountData ) ? ;
2019-10-04 14:43:50 -07:00
2019-10-07 09:42:56 -07:00
Ok ( date_config . date_time . date ( ) )
2019-10-04 14:43:50 -07:00
}
2019-10-10 07:54:18 -07:00
fn verify_account < ' a > (
2020-01-22 17:54:06 -08:00
keyed_account : & ' a KeyedAccount ,
2019-10-04 14:43:50 -07:00
expected_pubkey : & Pubkey ,
2020-01-22 09:11:56 -08:00
) -> Result < RefMut < ' a , Account > , InstructionError > {
2019-10-04 14:43:50 -07:00
if keyed_account . unsigned_key ( ) ! = expected_pubkey {
return Err ( VestError ::Unauthorized . into ( ) ) ;
}
2020-01-22 09:11:56 -08:00
keyed_account . try_account_ref_mut ( )
2019-10-04 14:43:50 -07:00
}
2019-10-10 07:54:18 -07:00
fn verify_signed_account < ' a > (
2020-01-22 17:54:06 -08:00
keyed_account : & ' a KeyedAccount ,
2019-10-04 14:43:50 -07:00
expected_pubkey : & Pubkey ,
2020-01-22 09:11:56 -08:00
) -> Result < RefMut < ' a , Account > , InstructionError > {
2019-10-04 14:43:50 -07:00
if keyed_account . signer_key ( ) . is_none ( ) {
return Err ( InstructionError ::MissingRequiredSignature ) ;
}
2019-10-10 07:54:18 -07:00
verify_account ( keyed_account , expected_pubkey )
2019-10-04 14:43:50 -07:00
}
pub fn process_instruction (
_program_id : & Pubkey ,
2020-01-22 17:54:06 -08:00
keyed_accounts : & [ KeyedAccount ] ,
2019-10-04 14:43:50 -07:00
data : & [ u8 ] ,
) -> Result < ( ) , InstructionError > {
2020-01-22 17:54:06 -08:00
let keyed_accounts_iter = & mut keyed_accounts . iter ( ) ;
2020-01-22 09:11:56 -08:00
let contract_account = & mut next_keyed_account ( keyed_accounts_iter ) ? . try_account_ref_mut ( ) ? ;
2019-10-10 07:54:18 -07:00
2019-10-23 19:56:07 -07:00
let instruction = limited_deserialize ( data ) ? ;
2019-10-04 14:43:50 -07:00
2019-10-10 07:54:18 -07:00
let mut vest_state = if let VestInstruction ::InitializeAccount {
terminator_pubkey ,
payee_pubkey ,
start_date_time ,
date_pubkey ,
total_lamports ,
} = instruction
{
VestState {
2019-10-04 14:43:50 -07:00
terminator_pubkey ,
payee_pubkey ,
start_date_time ,
date_pubkey ,
total_lamports ,
2019-11-20 18:33:17 -08:00
.. VestState ::default ( )
2019-10-04 14:43:50 -07:00
}
2019-10-10 07:54:18 -07:00
} else {
VestState ::deserialize ( & contract_account . data ) ?
} ;
match instruction {
VestInstruction ::InitializeAccount { .. } = > { }
2019-10-10 09:25:23 -07:00
VestInstruction ::SetTerminator ( new_pubkey ) = > {
verify_signed_account (
next_keyed_account ( keyed_accounts_iter ) ? ,
& vest_state . terminator_pubkey ,
) ? ;
vest_state . terminator_pubkey = new_pubkey ;
}
VestInstruction ::SetPayee ( new_pubkey ) = > {
2019-10-10 07:54:18 -07:00
verify_signed_account (
next_keyed_account ( keyed_accounts_iter ) ? ,
& vest_state . payee_pubkey ,
) ? ;
2019-10-10 09:25:23 -07:00
vest_state . payee_pubkey = new_pubkey ;
2019-10-04 14:43:50 -07:00
}
VestInstruction ::RedeemTokens = > {
2019-10-10 07:54:18 -07:00
let current_date = verify_date_account (
next_keyed_account ( keyed_accounts_iter ) ? ,
& vest_state . date_pubkey ,
) ? ;
2020-01-22 09:11:56 -08:00
let mut payee_account = verify_account (
2019-10-10 07:54:18 -07:00
next_keyed_account ( keyed_accounts_iter ) ? ,
& vest_state . payee_pubkey ,
) ? ;
2020-01-22 09:11:56 -08:00
vest_state . redeem_tokens ( contract_account , current_date , & mut payee_account ) ;
2019-10-04 14:43:50 -07:00
}
2019-11-20 18:33:17 -08:00
VestInstruction ::Terminate | VestInstruction ::Renege ( _ ) = > {
let lamports = if let VestInstruction ::Renege ( lamports ) = instruction {
lamports
} else {
contract_account . lamports
} ;
2019-10-10 07:54:18 -07:00
let terminator_account = verify_signed_account (
next_keyed_account ( keyed_accounts_iter ) ? ,
& vest_state . terminator_pubkey ,
) ? ;
2019-10-10 05:30:42 -07:00
let payee_keyed_account = keyed_accounts_iter . next ( ) ;
2020-01-22 09:11:56 -08:00
let mut payee_account = if let Some ( payee_keyed_account ) = payee_keyed_account {
payee_keyed_account . try_account_ref_mut ( ) ?
2019-10-04 14:43:50 -07:00
} else {
terminator_account
} ;
2020-01-22 09:11:56 -08:00
vest_state . renege ( contract_account , & mut payee_account , lamports ) ;
2019-11-20 18:33:17 -08:00
}
VestInstruction ::VestAll = > {
verify_signed_account (
next_keyed_account ( keyed_accounts_iter ) ? ,
& vest_state . terminator_pubkey ,
) ? ;
vest_state . vest_all ( ) ;
2019-10-04 14:43:50 -07:00
}
}
2019-10-10 07:54:18 -07:00
vest_state . serialize ( & mut contract_account . data )
2019-10-04 14:43:50 -07:00
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use crate ::id ;
use crate ::vest_instruction ;
2019-11-22 15:10:53 -08:00
use solana_config_program ::date_instruction ;
2019-10-04 14:43:50 -07:00
use solana_runtime ::bank ::Bank ;
use solana_runtime ::bank_client ::BankClient ;
use solana_sdk ::client ::SyncClient ;
2019-11-08 20:56:57 -08:00
use solana_sdk ::genesis_config ::create_genesis_config ;
2019-10-04 14:43:50 -07:00
use solana_sdk ::hash ::hash ;
use solana_sdk ::message ::Message ;
2020-02-20 13:28:55 -08:00
use solana_sdk ::signature ::{ Keypair , Signature , Signer } ;
2019-10-09 16:27:49 -07:00
use solana_sdk ::transaction ::TransactionError ;
2019-10-10 09:25:23 -07:00
use solana_sdk ::transport ::Result ;
2019-10-04 14:43:50 -07:00
use std ::sync ::Arc ;
fn create_bank ( lamports : u64 ) -> ( Bank , Keypair ) {
2019-11-08 20:56:57 -08:00
let ( genesis_config , mint_keypair ) = create_genesis_config ( lamports ) ;
let mut bank = Bank ::new ( & genesis_config ) ;
2020-04-27 21:05:12 -07:00
bank . add_static_program ( " vest_program " , id ( ) , process_instruction ) ;
2019-10-04 14:43:50 -07:00
( bank , mint_keypair )
}
fn create_bank_client ( lamports : u64 ) -> ( BankClient , Keypair ) {
let ( bank , mint_keypair ) = create_bank ( lamports ) ;
( BankClient ::new ( bank ) , mint_keypair )
}
/// Create a config account and use it as a date oracle.
fn create_date_account (
bank_client : & BankClient ,
date_keypair : & Keypair ,
2019-10-07 09:42:56 -07:00
payer_keypair : & Keypair ,
date : Date < Utc > ,
2019-10-10 09:25:23 -07:00
) -> Result < Signature > {
2019-10-04 14:43:50 -07:00
let date_pubkey = date_keypair . pubkey ( ) ;
let mut instructions =
date_instruction ::create_account ( & payer_keypair . pubkey ( ) , & date_pubkey , 1 ) ;
2019-10-07 09:42:56 -07:00
instructions . push ( date_instruction ::store ( & date_pubkey , date ) ) ;
2019-10-04 14:43:50 -07:00
2020-03-11 14:37:23 -07:00
let message = Message ::new ( & instructions ) ;
2020-02-20 12:13:23 -08:00
bank_client . send_message ( & [ payer_keypair , date_keypair ] , message )
2019-10-04 14:43:50 -07:00
}
fn store_date (
bank_client : & BankClient ,
date_keypair : & Keypair ,
2019-10-07 09:42:56 -07:00
payer_keypair : & Keypair ,
date : Date < Utc > ,
2019-10-10 09:25:23 -07:00
) -> Result < Signature > {
2019-10-04 14:43:50 -07:00
let date_pubkey = date_keypair . pubkey ( ) ;
2019-10-07 09:42:56 -07:00
let instruction = date_instruction ::store ( & date_pubkey , date ) ;
2020-03-11 14:37:23 -07:00
let message = Message ::new_with_payer ( & [ instruction ] , Some ( & payer_keypair . pubkey ( ) ) ) ;
2020-02-20 12:13:23 -08:00
bank_client . send_message ( & [ payer_keypair , date_keypair ] , message )
2019-10-04 14:43:50 -07:00
}
fn create_vest_account (
bank_client : & BankClient ,
2019-11-08 02:27:35 -08:00
contract_keypair : & Keypair ,
2019-10-04 14:43:50 -07:00
payer_keypair : & Keypair ,
2019-10-10 09:25:23 -07:00
terminator_pubkey : & Pubkey ,
2019-10-04 14:43:50 -07:00
payee_pubkey : & Pubkey ,
start_date : Date < Utc > ,
date_pubkey : & Pubkey ,
lamports : u64 ,
2019-10-10 09:25:23 -07:00
) -> Result < Signature > {
2019-10-04 14:43:50 -07:00
let instructions = vest_instruction ::create_account (
& payer_keypair . pubkey ( ) ,
2019-10-10 09:25:23 -07:00
& terminator_pubkey ,
2019-11-08 02:27:35 -08:00
& contract_keypair . pubkey ( ) ,
2019-10-07 09:42:56 -07:00
& payee_pubkey ,
2019-10-04 14:43:50 -07:00
start_date ,
& date_pubkey ,
lamports ,
) ;
2020-03-11 14:37:23 -07:00
let message = Message ::new ( & instructions ) ;
2020-02-20 12:13:23 -08:00
bank_client . send_message ( & [ payer_keypair , contract_keypair ] , message )
2019-10-04 14:43:50 -07:00
}
2019-10-10 09:25:23 -07:00
fn send_set_terminator (
bank_client : & BankClient ,
contract_pubkey : & Pubkey ,
old_keypair : & Keypair ,
new_pubkey : & Pubkey ,
) -> Result < Signature > {
let instruction =
vest_instruction ::set_terminator ( & contract_pubkey , & old_keypair . pubkey ( ) , & new_pubkey ) ;
bank_client . send_instruction ( & old_keypair , instruction )
}
2019-10-04 14:43:50 -07:00
fn send_set_payee (
bank_client : & BankClient ,
contract_pubkey : & Pubkey ,
2019-10-10 09:25:23 -07:00
old_keypair : & Keypair ,
new_pubkey : & Pubkey ,
) -> Result < Signature > {
let instruction =
vest_instruction ::set_payee ( & contract_pubkey , & old_keypair . pubkey ( ) , & new_pubkey ) ;
bank_client . send_instruction ( & old_keypair , instruction )
2019-10-04 14:43:50 -07:00
}
fn send_redeem_tokens (
bank_client : & BankClient ,
2019-10-07 09:42:56 -07:00
contract_pubkey : & Pubkey ,
2019-10-04 14:43:50 -07:00
payer_keypair : & Keypair ,
payee_pubkey : & Pubkey ,
date_pubkey : & Pubkey ,
2019-10-10 09:25:23 -07:00
) -> Result < Signature > {
2019-10-04 14:43:50 -07:00
let instruction =
2019-10-07 09:42:56 -07:00
vest_instruction ::redeem_tokens ( & contract_pubkey , & date_pubkey , & payee_pubkey ) ;
2020-03-11 14:37:23 -07:00
let message = Message ::new_with_payer ( & [ instruction ] , Some ( & payer_keypair . pubkey ( ) ) ) ;
2020-02-20 12:13:23 -08:00
bank_client . send_message ( & [ payer_keypair ] , message )
2019-10-04 14:43:50 -07:00
}
#[ test ]
2019-10-10 07:54:18 -07:00
fn test_verify_account_unauthorized ( ) {
2019-10-04 14:43:50 -07:00
// Ensure client can't sneak in with an untrusted date account.
let date_pubkey = Pubkey ::new_rand ( ) ;
2020-01-22 17:54:06 -08:00
let account = Account ::new_ref ( 1 , 0 , & solana_config_program ::id ( ) ) ;
let keyed_account = KeyedAccount ::new ( & date_pubkey , false , & account ) ;
2019-10-04 14:43:50 -07:00
let mallory_pubkey = Pubkey ::new_rand ( ) ; // <-- Attack! Not the expected account.
assert_eq! (
2020-01-22 17:54:06 -08:00
verify_account ( & keyed_account , & mallory_pubkey ) . unwrap_err ( ) ,
2019-10-04 14:43:50 -07:00
VestError ::Unauthorized . into ( )
) ;
}
#[ test ]
2019-10-10 07:54:18 -07:00
fn test_verify_signed_account_missing_signature ( ) {
2019-10-04 14:43:50 -07:00
// Ensure client can't sneak in with an unsigned account.
let date_pubkey = Pubkey ::new_rand ( ) ;
2020-01-22 17:54:06 -08:00
let account = Account ::new_ref ( 1 , 0 , & solana_config_program ::id ( ) ) ;
let keyed_account = KeyedAccount ::new ( & date_pubkey , false , & account ) ; // <-- Attack! Unsigned transaction.
2019-10-04 14:43:50 -07:00
assert_eq! (
2020-01-22 17:54:06 -08:00
verify_signed_account ( & keyed_account , & date_pubkey ) . unwrap_err ( ) ,
2019-10-04 14:43:50 -07:00
InstructionError ::MissingRequiredSignature . into ( )
) ;
}
#[ test ]
2019-10-10 07:54:18 -07:00
fn test_verify_date_account_incorrect_program_id ( ) {
2019-10-04 14:43:50 -07:00
// Ensure client can't sneak in with a non-Config account.
let date_pubkey = Pubkey ::new_rand ( ) ;
2020-01-22 17:54:06 -08:00
let account = Account ::new_ref ( 1 , 0 , & id ( ) ) ; // <-- Attack! Pass Vest account where Config account is expected.
let keyed_account = KeyedAccount ::new ( & date_pubkey , false , & account ) ;
2019-10-04 14:43:50 -07:00
assert_eq! (
2020-01-22 17:54:06 -08:00
verify_date_account ( & keyed_account , & date_pubkey ) . unwrap_err ( ) ,
2019-10-04 14:43:50 -07:00
InstructionError ::IncorrectProgramId
) ;
}
#[ test ]
2019-10-10 07:54:18 -07:00
fn test_verify_date_account_uninitialized_config ( ) {
2019-10-04 14:43:50 -07:00
// Ensure no panic when `get_config_data()` returns an error.
let date_pubkey = Pubkey ::new_rand ( ) ;
2020-01-22 17:54:06 -08:00
let account = Account ::new_ref ( 1 , 0 , & solana_config_program ::id ( ) ) ; // <-- Attack! Zero space.
let keyed_account = KeyedAccount ::new ( & date_pubkey , false , & account ) ;
2019-10-04 14:43:50 -07:00
assert_eq! (
2020-01-22 17:54:06 -08:00
verify_date_account ( & keyed_account , & date_pubkey ) . unwrap_err ( ) ,
2019-10-04 14:43:50 -07:00
InstructionError ::InvalidAccountData
) ;
}
#[ test ]
2019-10-10 07:54:18 -07:00
fn test_verify_date_account_invalid_date_config ( ) {
2019-10-04 14:43:50 -07:00
// Ensure no panic when `deserialize::<DateConfig>()` returns an error.
let date_pubkey = Pubkey ::new_rand ( ) ;
2020-01-22 17:54:06 -08:00
let account = Account ::new_ref ( 1 , 1 , & solana_config_program ::id ( ) ) ; // Attack! 1 byte, enough to sneak by `get_config_data()`, but not DateConfig deserialize.
let keyed_account = KeyedAccount ::new ( & date_pubkey , false , & account ) ;
2019-10-04 14:43:50 -07:00
assert_eq! (
2020-01-22 17:54:06 -08:00
verify_date_account ( & keyed_account , & date_pubkey ) . unwrap_err ( ) ,
2019-10-04 14:43:50 -07:00
InstructionError ::InvalidAccountData
) ;
}
#[ test ]
2019-10-10 07:54:18 -07:00
fn test_verify_date_account_deserialize ( ) {
2019-10-04 14:43:50 -07:00
// Ensure no panic when `deserialize::<DateConfig>()` returns an error.
let date_pubkey = Pubkey ::new_rand ( ) ;
2020-01-22 17:54:06 -08:00
let account = Account ::new_ref ( 1 , 1 , & solana_config_program ::id ( ) ) ; // Attack! 1 byte, enough to sneak by `get_config_data()`, but not DateConfig deserialize.
let keyed_account = KeyedAccount ::new ( & date_pubkey , false , & account ) ;
2019-10-04 14:43:50 -07:00
assert_eq! (
2020-01-22 17:54:06 -08:00
verify_date_account ( & keyed_account , & date_pubkey ) . unwrap_err ( ) ,
2019-10-04 14:43:50 -07:00
InstructionError ::InvalidAccountData
) ;
}
2019-10-09 16:27:49 -07:00
#[ test ]
fn test_initialize_no_panic ( ) {
let ( bank_client , alice_keypair ) = create_bank_client ( 3 ) ;
2019-11-08 02:27:35 -08:00
let contract_keypair = Keypair ::new ( ) ;
2019-10-09 16:27:49 -07:00
let mut instructions = vest_instruction ::create_account (
& alice_keypair . pubkey ( ) ,
& Pubkey ::new_rand ( ) ,
2019-11-08 02:27:35 -08:00
& contract_keypair . pubkey ( ) ,
2019-10-10 09:25:23 -07:00
& Pubkey ::new_rand ( ) ,
2019-10-09 16:27:49 -07:00
Utc ::now ( ) . date ( ) ,
& Pubkey ::new_rand ( ) ,
1 ,
) ;
instructions [ 1 ] . accounts = vec! [ ] ; // <!-- Attack! Prevent accounts from being passed into processor.
2020-03-11 14:37:23 -07:00
let message = Message ::new ( & instructions ) ;
2019-10-09 16:27:49 -07:00
assert_eq! (
bank_client
2019-11-08 02:27:35 -08:00
. send_message ( & [ & alice_keypair , & contract_keypair ] , message )
2019-10-09 16:27:49 -07:00
. unwrap_err ( )
. unwrap ( ) ,
2019-10-10 05:30:42 -07:00
TransactionError ::InstructionError ( 1 , InstructionError ::NotEnoughAccountKeys )
2019-10-09 16:27:49 -07:00
) ;
}
2019-10-10 09:25:23 -07:00
#[ test ]
fn test_set_payee_and_terminator ( ) {
let ( bank_client , alice_keypair ) = create_bank_client ( 39 ) ;
let alice_pubkey = alice_keypair . pubkey ( ) ;
let date_pubkey = Pubkey ::new_rand ( ) ;
2019-11-08 02:27:35 -08:00
let contract_keypair = Keypair ::new ( ) ;
let contract_pubkey = contract_keypair . pubkey ( ) ;
2019-10-10 09:25:23 -07:00
let bob_keypair = Keypair ::new ( ) ;
let bob_pubkey = bob_keypair . pubkey ( ) ;
let start_date = Utc . ymd ( 2018 , 1 , 1 ) ;
create_vest_account (
& bank_client ,
2019-11-08 02:27:35 -08:00
& contract_keypair ,
2019-10-10 09:25:23 -07:00
& alice_keypair ,
& alice_pubkey ,
& bob_pubkey ,
start_date ,
& date_pubkey ,
36 ,
)
. unwrap ( ) ;
let new_bob_pubkey = Pubkey ::new_rand ( ) ;
// Ensure some rando can't change the payee.
// Transfer bob a token to pay the transaction fee.
let mallory_keypair = Keypair ::new ( ) ;
bank_client
. transfer ( 1 , & alice_keypair , & mallory_keypair . pubkey ( ) )
. unwrap ( ) ;
send_set_payee (
& bank_client ,
& contract_pubkey ,
& mallory_keypair ,
& new_bob_pubkey ,
)
. unwrap_err ( ) ;
// Ensure bob can update which account he wants vested funds transfered to.
bank_client
. transfer ( 1 , & alice_keypair , & bob_pubkey )
. unwrap ( ) ;
send_set_payee (
& bank_client ,
& contract_pubkey ,
& bob_keypair ,
& new_bob_pubkey ,
)
. unwrap ( ) ;
// Ensure the rando can't change the terminator either.
let new_alice_pubkey = Pubkey ::new_rand ( ) ;
send_set_terminator (
& bank_client ,
& contract_pubkey ,
& mallory_keypair ,
& new_alice_pubkey ,
)
. unwrap_err ( ) ;
// Ensure alice can update which pubkey she uses to terminate contracts.
send_set_terminator (
& bank_client ,
& contract_pubkey ,
& alice_keypair ,
& new_alice_pubkey ,
)
. unwrap ( ) ;
}
2019-10-09 16:27:49 -07:00
2019-10-04 14:43:50 -07:00
#[ test ]
fn test_set_payee ( ) {
let ( bank_client , alice_keypair ) = create_bank_client ( 38 ) ;
2019-10-10 09:25:23 -07:00
let alice_pubkey = alice_keypair . pubkey ( ) ;
2019-10-04 14:43:50 -07:00
let date_pubkey = Pubkey ::new_rand ( ) ;
2019-11-08 02:27:35 -08:00
let contract_keypair = Keypair ::new ( ) ;
let contract_pubkey = contract_keypair . pubkey ( ) ;
2019-10-04 14:43:50 -07:00
let bob_keypair = Keypair ::new ( ) ;
let bob_pubkey = bob_keypair . pubkey ( ) ;
let start_date = Utc . ymd ( 2018 , 1 , 1 ) ;
create_vest_account (
& bank_client ,
2019-11-08 02:27:35 -08:00
& contract_keypair ,
2019-10-04 14:43:50 -07:00
& alice_keypair ,
2019-10-10 09:25:23 -07:00
& alice_pubkey ,
2019-10-04 14:43:50 -07:00
& bob_pubkey ,
start_date ,
& date_pubkey ,
36 ,
)
. unwrap ( ) ;
let new_bob_pubkey = Pubkey ::new_rand ( ) ;
// Ensure some rando can't change the payee.
// Transfer bob a token to pay the transaction fee.
let mallory_keypair = Keypair ::new ( ) ;
bank_client
. transfer ( 1 , & alice_keypair , & mallory_keypair . pubkey ( ) )
. unwrap ( ) ;
send_set_payee (
& bank_client ,
& contract_pubkey ,
2019-10-07 09:42:56 -07:00
& mallory_keypair ,
2019-10-04 14:43:50 -07:00
& new_bob_pubkey ,
)
. unwrap_err ( ) ;
2020-04-27 21:05:12 -07:00
// Ensure bob can update which account he wants vested funds transferred to.
2019-10-04 14:43:50 -07:00
bank_client
. transfer ( 1 , & alice_keypair , & bob_pubkey )
. unwrap ( ) ;
send_set_payee (
& bank_client ,
& contract_pubkey ,
2019-10-07 09:42:56 -07:00
& bob_keypair ,
2019-10-04 14:43:50 -07:00
& new_bob_pubkey ,
)
. unwrap ( ) ;
}
#[ test ]
fn test_redeem_tokens ( ) {
let ( bank , alice_keypair ) = create_bank ( 38 ) ;
let bank = Arc ::new ( bank ) ;
let bank_client = BankClient ::new_shared ( & bank ) ;
let alice_pubkey = alice_keypair . pubkey ( ) ;
let date_keypair = Keypair ::new ( ) ;
let date_pubkey = date_keypair . pubkey ( ) ;
let current_date = Utc . ymd ( 2019 , 1 , 1 ) ;
2019-10-07 09:42:56 -07:00
create_date_account ( & bank_client , & date_keypair , & alice_keypair , current_date ) . unwrap ( ) ;
2019-10-04 14:43:50 -07:00
2019-11-08 02:27:35 -08:00
let contract_keypair = Keypair ::new ( ) ;
let contract_pubkey = contract_keypair . pubkey ( ) ;
2019-10-04 14:43:50 -07:00
let bob_pubkey = Pubkey ::new_rand ( ) ;
let start_date = Utc . ymd ( 2018 , 1 , 1 ) ;
create_vest_account (
& bank_client ,
2019-11-08 02:27:35 -08:00
& contract_keypair ,
2019-10-04 14:43:50 -07:00
& alice_keypair ,
2019-10-10 09:25:23 -07:00
& alice_pubkey ,
2019-10-04 14:43:50 -07:00
& bob_pubkey ,
start_date ,
& date_pubkey ,
36 ,
)
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & contract_pubkey ) . unwrap ( ) , 36 ) ;
send_redeem_tokens (
& bank_client ,
2019-10-07 09:42:56 -07:00
& contract_pubkey ,
2019-10-04 14:43:50 -07:00
& alice_keypair ,
& bob_pubkey ,
& date_pubkey ,
)
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & contract_pubkey ) . unwrap ( ) , 24 ) ;
assert_eq! ( bank_client . get_balance ( & bob_pubkey ) . unwrap ( ) , 12 ) ;
// Update the date oracle and redeem more tokens
store_date (
& bank_client ,
& date_keypair ,
2019-10-07 09:42:56 -07:00
& alice_keypair ,
2019-10-04 14:43:50 -07:00
Utc . ymd ( 2019 , 2 , 1 ) ,
)
. unwrap ( ) ;
// Force a new blockhash so that there's not a duplicate signature.
for _ in 0 .. bank . ticks_per_slot ( ) {
bank . register_tick ( & hash ( & [ 1 ] ) ) ;
}
send_redeem_tokens (
& bank_client ,
2019-10-07 09:42:56 -07:00
& contract_pubkey ,
2019-10-04 14:43:50 -07:00
& alice_keypair ,
& bob_pubkey ,
& date_pubkey ,
)
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & contract_pubkey ) . unwrap ( ) , 23 ) ;
assert_eq! ( bank_client . get_balance ( & bob_pubkey ) . unwrap ( ) , 13 ) ;
}
#[ test ]
2019-10-10 21:35:10 -07:00
fn test_terminate_and_refund ( ) {
2019-10-04 14:43:50 -07:00
let ( bank_client , alice_keypair ) = create_bank_client ( 3 ) ;
let alice_pubkey = alice_keypair . pubkey ( ) ;
2019-11-08 02:27:35 -08:00
let contract_keypair = Keypair ::new ( ) ;
let contract_pubkey = contract_keypair . pubkey ( ) ;
2019-10-04 14:43:50 -07:00
let bob_pubkey = Pubkey ::new_rand ( ) ;
let start_date = Utc ::now ( ) . date ( ) ;
let date_keypair = Keypair ::new ( ) ;
let date_pubkey = date_keypair . pubkey ( ) ;
let current_date = Utc . ymd ( 2019 , 1 , 1 ) ;
2019-10-07 09:42:56 -07:00
create_date_account ( & bank_client , & date_keypair , & alice_keypair , current_date ) . unwrap ( ) ;
2019-10-04 14:43:50 -07:00
create_vest_account (
& bank_client ,
2019-11-08 02:27:35 -08:00
& contract_keypair ,
2019-10-04 14:43:50 -07:00
& alice_keypair ,
2019-10-10 09:25:23 -07:00
& alice_pubkey ,
2019-10-04 14:43:50 -07:00
& bob_pubkey ,
start_date ,
& date_pubkey ,
1 ,
)
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & contract_pubkey ) . unwrap ( ) , 1 ) ;
// Now, terminate the transaction. alice gets her funds back
// Note: that tokens up until the oracle date are *not* redeemed automatically.
let instruction =
2019-10-07 09:42:56 -07:00
vest_instruction ::terminate ( & contract_pubkey , & alice_pubkey , & alice_pubkey ) ;
2019-10-04 14:43:50 -07:00
bank_client
. send_instruction ( & alice_keypair , instruction )
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 2 ) ;
assert_eq! (
bank_client . get_account_data ( & contract_pubkey ) . unwrap ( ) ,
None
) ;
assert_eq! ( bank_client . get_account_data ( & bob_pubkey ) . unwrap ( ) , None ) ;
}
2019-10-10 21:35:10 -07:00
#[ test ]
fn test_terminate_and_send_funds ( ) {
let ( bank_client , alice_keypair ) = create_bank_client ( 3 ) ;
let alice_pubkey = alice_keypair . pubkey ( ) ;
2019-11-08 02:27:35 -08:00
let contract_keypair = Keypair ::new ( ) ;
let contract_pubkey = contract_keypair . pubkey ( ) ;
2019-10-10 21:35:10 -07:00
let bob_pubkey = Pubkey ::new_rand ( ) ;
let start_date = Utc ::now ( ) . date ( ) ;
let date_keypair = Keypair ::new ( ) ;
let date_pubkey = date_keypair . pubkey ( ) ;
let current_date = Utc . ymd ( 2019 , 1 , 1 ) ;
create_date_account ( & bank_client , & date_keypair , & alice_keypair , current_date ) . unwrap ( ) ;
create_vest_account (
& bank_client ,
2019-11-08 02:27:35 -08:00
& contract_keypair ,
2019-10-10 21:35:10 -07:00
& alice_keypair ,
& alice_pubkey ,
& bob_pubkey ,
start_date ,
& date_pubkey ,
1 ,
)
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & contract_pubkey ) . unwrap ( ) , 1 ) ;
// Now, terminate the transaction. carol gets the funds.
let carol_pubkey = Pubkey ::new_rand ( ) ;
let instruction =
vest_instruction ::terminate ( & contract_pubkey , & alice_pubkey , & carol_pubkey ) ;
bank_client
. send_instruction ( & alice_keypair , instruction )
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & carol_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! (
bank_client . get_account_data ( & contract_pubkey ) . unwrap ( ) ,
None
) ;
assert_eq! ( bank_client . get_account_data ( & bob_pubkey ) . unwrap ( ) , None ) ;
}
2019-11-20 18:33:17 -08:00
#[ test ]
fn test_renege_and_send_funds ( ) {
let ( bank_client , alice_keypair ) = create_bank_client ( 3 ) ;
let alice_pubkey = alice_keypair . pubkey ( ) ;
let contract_keypair = Keypair ::new ( ) ;
let contract_pubkey = contract_keypair . pubkey ( ) ;
let bob_pubkey = Pubkey ::new_rand ( ) ;
let start_date = Utc ::now ( ) . date ( ) ;
let date_keypair = Keypair ::new ( ) ;
let date_pubkey = date_keypair . pubkey ( ) ;
let current_date = Utc . ymd ( 2019 , 1 , 1 ) ;
create_date_account ( & bank_client , & date_keypair , & alice_keypair , current_date ) . unwrap ( ) ;
create_vest_account (
& bank_client ,
& contract_keypair ,
& alice_keypair ,
& alice_pubkey ,
& bob_pubkey ,
start_date ,
& date_pubkey ,
1 ,
)
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & contract_pubkey ) . unwrap ( ) , 1 ) ;
// Now, renege on a token. carol gets it.
let carol_pubkey = Pubkey ::new_rand ( ) ;
let instruction =
vest_instruction ::renege ( & contract_pubkey , & alice_pubkey , & carol_pubkey , 1 ) ;
bank_client
. send_instruction ( & alice_keypair , instruction )
. unwrap ( ) ;
assert_eq! ( bank_client . get_balance ( & alice_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! ( bank_client . get_balance ( & carol_pubkey ) . unwrap ( ) , 1 ) ;
assert_eq! (
bank_client . get_account_data ( & contract_pubkey ) . unwrap ( ) ,
None
) ;
assert_eq! ( bank_client . get_account_data ( & bob_pubkey ) . unwrap ( ) , None ) ;
}
2019-10-04 14:43:50 -07:00
}