Skip to content

Commit

Permalink
Nft packs/remove random oracle (#121)
Browse files Browse the repository at this point in the history
* remove off-chain oracle dependence from NFT-packs program

* add ProvingProcess to random_value hash

* change recent_slothash in get_random_value, remove unused imports

Co-authored-by: MetaMykola <[email protected]>
  • Loading branch information
MetaMykola and MetaMykola authored Feb 10, 2022
1 parent 6e904b0 commit 530de7d
Show file tree
Hide file tree
Showing 26 changed files with 30 additions and 307 deletions.
2 changes: 1 addition & 1 deletion nft-packs/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spl-token = { version="3.2.0", features = [ "no-entrypoint" ] }
mpl-metaplex = { path = "../../metaplex/program", features = ["no-entrypoint"] }
mpl-token-metadata = { version="1.1.0", features = [ "no-entrypoint" ] }
mpl-token-vault = { path = "../../token-vault/program", features = [ "no-entrypoint" ] }
randomness-oracle-program = { git = "https://github.com/metaplex/randomness-oracle", features = [ "no-entrypoint" ] }
arrayref = "0.3.6"

[dev-dependencies]
solana-program-test = "1.8.5"
Expand Down
2 changes: 1 addition & 1 deletion nft-packs/program/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Supports creation of "mystery" packages of NFTs that are not revealed until afte
- Request card for redeem
- user calls this instruction to receive index of card which he can redeem
- program burns user's voucher token account
- program is using RandomOracle program to count probability to decide which card user will receive
- program is using hash of slot, timestamp and recent slothash to count probability to decide which card user will receive
- probability is calculating using weighted list from PackConfig account
- index of next card to redeem is written to ProvingProcess account
- ProvingProcess is a PDA account with seeds [pack, "proving", voucher_mint_key]
Expand Down
4 changes: 0 additions & 4 deletions nft-packs/program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ pub enum NFTPacksError {
#[error("Voucher should have supply greater then 0")]
WrongVoucherSupply,

/// Random oracle updated long time ago
#[error("Random oracle updated long time ago")]
RandomOracleOutOfDate,

/// Card ran out of editions
#[error("Card ran out of editions")]
CardDoesntHaveEditions,
Expand Down
13 changes: 3 additions & 10 deletions nft-packs/program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ pub enum NFTPacksInstruction {
/// - write pack_set
/// - signer authority
/// - read store
/// - read random_oracle
/// - read Rent account
/// - read Clock account
/// - read whitelisted_creator. Optional key
Expand Down Expand Up @@ -180,7 +179,7 @@ pub enum NFTPacksInstruction {

/// ClaimPack
///
/// Call this instruction with ProvingProcess and PackCard accounts and program among with random oracle will transfer
/// Call this instruction with ProvingProcess and PackCard accounts and program will transfer
/// MasterEdition to user account or return empty response depends successfully or not user open pack with specific MasterEdition.
///
/// Accounts:
Expand All @@ -198,7 +197,6 @@ pub enum NFTPacksInstruction {
/// - read metadata_mint_acc
/// - read edition_acc
/// - read rent program
/// - read randomness oracle account
/// - read mpl_token_metadata program
/// - read spl_token program
/// - read system program
Expand Down Expand Up @@ -283,7 +281,7 @@ pub enum NFTPacksInstruction {
/// - read pack_voucher
/// - read, write proving_process (PDA, ['proving', pack, user_wallet])
/// - signer user_wallet
/// - read randomness_oracle
/// - read recent_slothashes
/// - read clock
/// - read rent
/// - read system_program
Expand Down Expand Up @@ -320,15 +318,13 @@ pub fn init_pack(
pack_set: &Pubkey,
authority: &Pubkey,
store: &Pubkey,
random_oracle: &Pubkey,
whitelisted_creator: &Pubkey,
args: InitPackSetArgs,
) -> Instruction {
let accounts = vec![
AccountMeta::new(*pack_set, false),
AccountMeta::new_readonly(*authority, true),
AccountMeta::new_readonly(*store, false),
AccountMeta::new_readonly(*random_oracle, false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*whitelisted_creator, false),
Expand Down Expand Up @@ -461,7 +457,6 @@ pub fn claim_pack(
new_mint_authority: &Pubkey,
metadata: &Pubkey,
metadata_mint: &Pubkey,
randomness_oracle: &Pubkey,
index: u32,
) -> Instruction {
let (proving_process, _) =
Expand Down Expand Up @@ -500,7 +495,6 @@ pub fn claim_pack(
AccountMeta::new(*metadata_mint, false),
AccountMeta::new(edition_mark_pda, false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(*randomness_oracle, false),
AccountMeta::new_readonly(mpl_token_metadata::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new_readonly(system_program::id(), false),
Expand Down Expand Up @@ -623,7 +617,6 @@ pub fn request_card_for_redeem(
edition_mint: &Pubkey,
user_wallet: &Pubkey,
user_token_acc: &Option<Pubkey>,
random_oracle: &Pubkey,
index: u32,
) -> Instruction {
let (proving_process, _) =
Expand All @@ -642,7 +635,7 @@ pub fn request_card_for_redeem(
AccountMeta::new_readonly(pack_voucher, false),
AccountMeta::new(proving_process, false),
AccountMeta::new(*user_wallet, true),
AccountMeta::new_readonly(*random_oracle, false),
AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
Expand Down
2 changes: 0 additions & 2 deletions nft-packs/program/src/processor/claim_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,13 @@ pub fn claim_pack(
let metadata_mint_account = next_account_info(account_info_iter)?;
let edition_marker_account = next_account_info(account_info_iter)?;
let rent_account = next_account_info(account_info_iter)?;
let randomness_oracle_account = next_account_info(account_info_iter)?;
let _token_metadata_account = next_account_info(account_info_iter)?;
let token_program_account = next_account_info(account_info_iter)?;
let system_program_account = next_account_info(account_info_iter)?;
let _rent = &Rent::from_account_info(rent_account)?;

// Validate owners
assert_owned_by(pack_set_account, program_id)?;
assert_owned_by(randomness_oracle_account, &randomness_oracle_program::id())?;

assert_signer(&user_wallet_account)?;

Expand Down
9 changes: 0 additions & 9 deletions nft-packs/program/src/processor/init_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ pub fn init_pack(
let pack_set_account = next_account_info(account_info_iter)?;
let authority_account = next_account_info(account_info_iter)?;
let store_account = next_account_info(account_info_iter)?;
let random_oracle_account = next_account_info(account_info_iter)?;
let rent_info = next_account_info(account_info_iter)?;
let rent = &Rent::from_account_info(rent_info)?;
let clock_info = next_account_info(account_info_iter)?;
Expand All @@ -36,7 +35,6 @@ pub fn init_pack(
assert_rent_exempt(rent, pack_set_account)?;
assert_signer(authority_account)?;
assert_owned_by(store_account, &mpl_metaplex::id())?;
assert_owned_by(random_oracle_account, &randomness_oracle_program::id())?;
assert_admin_whitelisted(
store_account,
whitelisted_creator_account,
Expand All @@ -45,12 +43,6 @@ pub fn init_pack(

let mut pack_set = PackSet::unpack_unchecked(&pack_set_account.data.borrow_mut())?;

// make sure that random oracle account is already initialized
if random_oracle_account.data.borrow()[0]
!= randomness_oracle_program::state::AccountType::RandomnessOracle as u8
{
return Err(ProgramError::UninitializedAccount);
}

if pack_set.is_initialized() {
return Err(ProgramError::AccountAlreadyInitialized);
Expand Down Expand Up @@ -93,7 +85,6 @@ pub fn init_pack(
allowed_amount_to_redeem: args.allowed_amount_to_redeem,
redeem_start_date: redeem_start_date,
redeem_end_date: args.redeem_end_date,
random_oracle: *random_oracle_account.key,
});

pack_set.puff_out_data_fields();
Expand Down
17 changes: 12 additions & 5 deletions nft-packs/program/src/processor/request_card_to_redeem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ use solana_program::{
program_option::COption,
program_pack::Pack,
pubkey::Pubkey,
sysvar::{rent::Rent, Sysvar},
sysvar::{
rent::Rent,
Sysvar,
},
};
use spl_token::state::Account;
use arrayref::array_ref;

/// Process RequestCardForRedeem instruction
pub fn request_card_for_redeem(
Expand All @@ -43,7 +47,7 @@ pub fn request_card_for_redeem(
let voucher_account = next_account_info(account_info_iter)?;
let proving_process_account = next_account_info(account_info_iter)?;
let user_wallet_account = next_account_info(account_info_iter)?;
let randomness_oracle_account = next_account_info(account_info_iter)?;
let recent_slothashes_info = next_account_info(account_info_iter)?;
let clock_info = next_account_info(account_info_iter)?;
let clock = Clock::from_account_info(clock_info)?;
let rent_info = next_account_info(account_info_iter)?;
Expand Down Expand Up @@ -77,7 +81,6 @@ pub fn request_card_for_redeem(

let pack_set = PackSet::unpack(&pack_set_account.data.borrow())?;
assert_account_key(store_account, &pack_set.store)?;
assert_account_key(randomness_oracle_account, &pack_set.random_oracle)?;

let proving_process_seeds = &[
ProvingProcess::PREFIX.as_bytes(),
Expand Down Expand Up @@ -166,8 +169,12 @@ pub fn request_card_for_redeem(
return Err(NFTPacksError::UserRedeemedAllCards.into());
}

let random_value =
get_random_oracle_value(randomness_oracle_account, &proving_process, &clock)?;
// get slot hash
let data = recent_slothashes_info.data.borrow();
let most_recent_slothash = array_ref![data, 8, 8];

// get random value
let random_value = get_random_value(most_recent_slothash, &proving_process, &clock)?;
let weight_sum = if pack_set.distribution_type == PackDistributionType::MaxSupply {
pack_set.total_editions
} else {
Expand Down
5 changes: 0 additions & 5 deletions nft-packs/program/src/state/pack_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,6 @@ pub struct PackSet {
pub redeem_start_date: u64,
/// Date when pack set becomes inactive
pub redeem_end_date: Option<u64>,
/// Random oracle
pub random_oracle: Pubkey,
}

impl PackSet {
Expand All @@ -112,7 +110,6 @@ impl PackSet {
self.allowed_amount_to_redeem = params.allowed_amount_to_redeem;
self.redeem_start_date = params.redeem_start_date;
self.redeem_end_date = params.redeem_end_date;
self.random_oracle = params.random_oracle;
}

/// Increase pack cards counter
Expand Down Expand Up @@ -267,8 +264,6 @@ pub struct InitPackSetParams {
pub redeem_start_date: u64,
/// Redeem end date
pub redeem_end_date: Option<u64>,
/// Random oracle
pub random_oracle: Pubkey,
}

impl Sealed for PackSet {}
Expand Down
29 changes: 13 additions & 16 deletions nft-packs/program/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Program utils
use crate::{
error::NFTPacksError,
math::SafeMath,
state::{ProvingProcess, MAX_LAG_SLOTS},
};
use borsh::BorshSerialize;
Expand Down Expand Up @@ -248,27 +246,26 @@ pub fn empty_account_balance(
Ok(())
}

/// get random value from oracle account
pub fn get_random_oracle_value(
randomness_oracle_account: &AccountInfo,
/// get random value
pub fn get_random_value(
recent_slothash: &[u8],
proving_process: &ProvingProcess,
clock: &Clock,
) -> Result<u16, ProgramError> {
let (oracle_random_value, slot) =
randomness_oracle_program::read_value(randomness_oracle_account)?;

if clock.slot.error_sub(slot)? > MAX_LAG_SLOTS {
return Err(NFTPacksError::RandomOracleOutOfDate.into());
}

// Hash random value from the oracle with current slot and proving process data and receive new random u16
// Hash slot, current timestamp and value from last slothash and proving process data and receive new random u16
let mut hasher = DefaultHasher::new();
hasher.write(oracle_random_value.as_ref());
hasher.write(proving_process.try_to_vec()?.as_ref());

// recent slothash
hasher.write(recent_slothash);
// slot
hasher.write_u64(clock.slot);
// timestamp
hasher.write_i64(clock.unix_timestamp);
// ProvingProcess(to make hash different for each instruction in the same slot)
hasher.write(proving_process.try_to_vec()?.as_ref());

let mut random_value: [u8; 2] = [0u8; 2];
random_value.copy_from_slice(&hasher.finish().to_le_bytes()[..2]);

Ok(u16::from_le_bytes(random_value))
}
}
3 changes: 0 additions & 3 deletions nft-packs/program/tests/activate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ async fn setup() -> (
let uri = String::from("some link to storage");
let description = String::from("Pack description");

let mut test_randomness_oracle = TestRandomnessOracle::new();
test_randomness_oracle.init(&mut context).await.unwrap();

let test_pack_set = TestPackSet::new(store_key);
test_pack_set
Expand All @@ -51,7 +49,6 @@ async fn setup() -> (
redeem_start_date: None,
redeem_end_date: None,
},
&test_randomness_oracle.keypair.pubkey(),
)
.await
.unwrap();
Expand Down
4 changes: 0 additions & 4 deletions nft-packs/program/tests/add_card_to_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ async fn setup(
let uri = String::from("some link to storage");
let description = String::from("Pack description");

let mut test_randomness_oracle = TestRandomnessOracle::new();
test_randomness_oracle.init(&mut context).await.unwrap();

let test_pack_set = TestPackSet::new(store_key);
test_pack_set
.init(
Expand All @@ -50,7 +47,6 @@ async fn setup(
redeem_start_date: None,
redeem_end_date: None,
},
&test_randomness_oracle.keypair.pubkey(),
)
.await
.unwrap();
Expand Down
4 changes: 0 additions & 4 deletions nft-packs/program/tests/add_voucher_to_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ async fn setup() -> (
let uri = String::from("some link to storage");
let description = String::from("Pack description");

let mut test_randomness_oracle = TestRandomnessOracle::new();
test_randomness_oracle.init(&mut context).await.unwrap();

let test_pack_set = TestPackSet::new(store_key);
test_pack_set
.init(
Expand All @@ -49,7 +46,6 @@ async fn setup() -> (
redeem_start_date: None,
redeem_end_date: None,
},
&test_randomness_oracle.keypair.pubkey(),
)
.await
.unwrap();
Expand Down
Loading

0 comments on commit 530de7d

Please sign in to comment.