1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::anchor_traits::*;
use crate::prelude::*;
use borsh::BorshSerialize;
use solana_program::pubkey::Pubkey;
use solana_program::sysvar::slot_hashes;
use solana_program::account_info::AccountInfo;
use solana_program::program_error::ProgramError;
use crate::get_sb_program_id;

pub struct RandomnessCommit {}

#[derive(Clone, BorshSerialize, Debug)]
pub struct RandomnessCommitParams {}

impl InstructionData for RandomnessCommitParams {}

impl Discriminator for RandomnessCommitParams {
    const DISCRIMINATOR: [u8; 8] = RandomnessCommit::DISCRIMINATOR;
}

impl Discriminator for RandomnessCommit {
    const DISCRIMINATOR: [u8; 8] = [52, 170, 152, 201, 179, 133, 242, 141];
}

pub struct RandomnessCommitAccounts {
    pub randomness: Pubkey,
    pub queue: Pubkey,
    pub oracle: Pubkey,
    pub recent_slothashes: Pubkey,
    pub authority: Pubkey,
}
impl ToAccountMetas for RandomnessCommitAccounts {
    fn to_account_metas(&self, _: Option<bool>) -> Vec<AccountMeta> {
        vec![
            AccountMeta::new(self.randomness, false),
            AccountMeta::new_readonly(self.queue, false),
            AccountMeta::new(self.oracle, false),
            AccountMeta::new_readonly(slot_hashes::ID, false),
            AccountMeta::new_readonly(self.authority, true),
        ]
    }
}

impl RandomnessCommit {
    pub fn build_ix(
        randomness: Pubkey,
        queue: Pubkey,
        oracle: Pubkey,
        authority: Pubkey,
    ) -> Result<Instruction, OnDemandError> {
        let cluster = std::env::var("CLUSTER").unwrap_or("mainnet".to_string());
        let pid = get_sb_program_id(&cluster);
        Ok(crate::utils::build_ix(
            &pid,
            &RandomnessCommitAccounts {
                randomness,
                queue,
                oracle,
                authority,
                recent_slothashes: slot_hashes::ID,
            },
            &RandomnessCommitParams {},
        ))
    }

    /// Invokes the `randomness_commit` Switchboard CPI call.
    ///
    /// This call commits a new randomness value to the randomness account.
    ///
    /// # Requirements
    ///
    /// - The `authority` must be a signer.
    ///
    /// # Parameters
    ///
    /// - **switchboard**: Switchboard program account.
    /// - **randomness**: Randomness account.
    /// - **queue**: Queue account associated with the randomness account.
    /// - **oracle**: Oracle account assigned for the randomness request.
    /// - **authority**: Authority of the randomness account.
    /// - **recent_slothashes**: Sysvar account to fetch recent slot hashes.
    /// - **seeds**: Seeds for the CPI call.
    ///
    pub fn invoke<'a>(
        switchboard: AccountInfo<'a>,
        randomness: AccountInfo<'a>,
        queue: AccountInfo<'a>,
        oracle: AccountInfo<'a>,
        authority: AccountInfo<'a>,
        recent_slothashes: AccountInfo<'a>,
        seeds: &[&[&[u8]]],
    ) -> Result<(), ProgramError> {
        let accounts = [
            randomness.clone(),
            queue.clone(),
            oracle.clone(),
            recent_slothashes.clone(),
            authority.clone(),
        ];
        let account_metas = RandomnessCommitAccounts {
            randomness: randomness.key.clone(),
            queue: queue.key.clone(),
            oracle: oracle.key.clone(),
            recent_slothashes: recent_slothashes.key.clone(),
            authority: authority.key.clone(),
        }.to_account_metas(None);
        let ix = Instruction {
            program_id: switchboard.key.clone(),
            accounts: account_metas,
            data: ix_discriminator("randomness_commit").to_vec(),
        };
        Ok(invoke_signed(&ix, &accounts, seeds)?)
    }
}

fn ix_discriminator(name: &str) -> [u8; 8] {
    let preimage = format!("global:{}", name);
    let mut sighash = [0u8; 8];
    sighash.copy_from_slice(
        &solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8],
    );
    sighash
}