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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use anchor_lang::prelude::*;
declare_id!("CFVk3Q9pN3W7qJaZbkmR5Jeb6TXsh51oSLvgEn3Szjd9");
#[program]
pub mod solana_anchor_rando {
use super::*;
pub fn initialize(ctx: Context<Initialize>, authority: Pubkey, oracles: [Pubkey; 2], bump: u8) -> ProgramResult {
msg!("Instruction: Initialize");
ctx.accounts.state.authority = authority;
if oracles.len() != ctx.accounts.state.oracles.len() {
return Err(ErrorCode::IncorrectOracleLength.into())
}
for n in 0..ctx.accounts.state.oracles.len() {
ctx.accounts.state.oracles[n] = oracles[n]
}
Ok(())
}
pub fn request(ctx: Context<MakeRequest>, bump: u8) -> ProgramResult {
msg!("Instruction: Request");
let vault = &mut ctx.accounts.vault;
vault.nonce = bump;
vault.request_reference = ctx.accounts.request_reference.key();
emit!(NewRequestEvent {
request_reference: *ctx.accounts.request_reference.key
});
Ok(())
}
pub fn fill_oracle_result(ctx: Context<FillOracleResult>, oracle_result: [u8; 64], bump: u8) -> ProgramResult {
msg!("Instruction: Fill Oracle Result");
let mut oracle_index = 17;
for i in 0 .. ctx.accounts.state.oracles.len() {
if ctx.accounts.state.oracles[i] == *ctx.accounts.oracle.key {
oracle_index = i;
}
}
if oracle_index == 17 {
return Err(ErrorCode::IncorrectOracleProvided.into())
}
if ctx.accounts.vault.done_flag[oracle_index] == 1 {
return Err(ErrorCode::AlreadyFilled.into())
}
for n in (oracle_index .. 16).step_by(ctx.accounts.state.oracles.len()) {
ctx.accounts.vault.result[n] = oracle_result[n];
}
for n in 0 .. 64 {
ctx.accounts.vault.oracle_results[oracle_index * 64 + n] = oracle_result[n]
}
ctx.accounts.vault.done_flag[oracle_index] = 1;
let sum: u8 = ctx.accounts.vault.done_flag.iter().sum();
if sum == ctx.accounts.vault.done_flag.len() as u8{
ctx.accounts.vault.numeric_result = u128::from_be_bytes(ctx.accounts.vault.result);
}
Ok(())
}
}
#[derive(Accounts)]
#[instruction(authority: Pubkey, oracles: [Pubkey; 2], bump: u8)]
pub struct Initialize<'info> {
#[account(mut)]
pub authority: Signer<'info>,
#[account(init, seeds = [b"state".as_ref()], bump = bump, payer = authority)]
pub state: Account<'info, RandoState>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
#[instruction(bump: u8)]
pub struct MakeRequest<'info> {
#[account(mut)]
pub requester: Signer<'info>,
pub request_reference: AccountInfo<'info>,
#[account(init, seeds = [b"request-reference-seed", request_reference.key.as_ref()], bump = bump, payer = requester)]
pub vault: Account<'info, RandoResult>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
}
#[derive(Accounts)]
#[instruction(oracle_result: [u8; 64], bump: u8)]
pub struct FillOracleResult<'info> {
pub oracle: Signer<'info>,
pub request_reference: AccountInfo<'info>,
#[account(mut, seeds = [b"request-reference-seed", request_reference.key.as_ref()], bump = bump)]
pub vault: Account<'info, RandoResult>,
pub state: Account<'info, RandoState>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
}
#[account]
#[derive(Default)]
pub struct RandoState {
pub authority: Pubkey,
pub oracles: [Pubkey; 2]
}
#[account]
pub struct RandoResult {
pub nonce: u8,
pub request_reference: Pubkey,
pub oracle_results: [u8;128],
pub result: [u8; 16],
pub done_flag: [u8; 2],
pub numeric_result: u128
}
#[event]
pub struct NewRequestEvent {
pub request_reference: Pubkey,
}
impl Default for RandoResult {
fn default() -> Self {
Self {
nonce: 0,
request_reference: Pubkey::new_from_array([0;32]),
oracle_results: [0;128],
result: [0; 16],
done_flag: [0; 2],
numeric_result: 0
}
}
}
#[error]
pub enum ErrorCode {
#[msg("Incorrect Oracle length between state and provided")]
IncorrectOracleLength,
#[msg("Incorrect Oracle Pubkey provided")]
IncorrectOracleProvided,
#[msg("Already filled")]
AlreadyFilled,
}