V3 Program SDK Updates (#104)

This commit is contained in:
gallynaut 2023-06-28 12:07:33 -06:00 committed by GitHub
parent 3770ae3c96
commit 4bce6d3a1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 14898 additions and 2483 deletions

View File

@ -109,9 +109,9 @@ jobs:
SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone
7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone
Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone
SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha --clone
sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx --clone
FSD8p7tDkhffAiMgAvMXi9veJW1uSod4H3F3REn7nMNC --clone
GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m --clone
5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz --clone
CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
- name: Run Tests
working-directory: javascript/solana.js
@ -176,9 +176,9 @@ jobs:
SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone
7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone
Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone
SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha --clone
sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx --clone
FSD8p7tDkhffAiMgAvMXi9veJW1uSod4H3F3REn7nMNC --clone
GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m --clone
5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz --clone
CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
- name: Run Tests
working-directory: javascript/solana.js

View File

@ -38,10 +38,10 @@ address = "CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
address = "7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie"
[[test.validator.clone]] # sb devnet attestation programID
address = "SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
address = "sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
[[test.validator.clone]] # sb devnet attestation IDL
address = "GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m"
address = "5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz"
[[test.validator.clone]] # sb SOL feed
address = "GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR"

View File

@ -6,7 +6,7 @@ seeds = false
skip-lint = false
[programs.localnet]
basic_oracle = "9PAxFbRDepv1ziPeUW5KHcpgpgPtxWV4ZzVwqDBqymok"
basic_oracle = "HgVykECRLmtSfquJz7NTBg5H8SfL2ehTFZnzfDJQuxt2"
[provider]
cluster = "Localnet"
@ -18,23 +18,22 @@ test = "pnpm exec ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
[test]
startup_wait = 15000
[[test.validator.clone]] # sb devnet oracle programID
address = "SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
[[test.validator.clone]] # sb devnet oracle IDL
address = "Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk"
[test.validator]
url = "https://api.devnet.solana.com"
# [[test.validator.clone]] # sb devnet oracle programID
# address = "SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
# [[test.validator.clone]] # sb devnet oracle IDL
# address = "Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk"
[[test.validator.clone]] # sb devnet oracle SbState
address = "CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
[[test.validator.clone]] # sb devnet oracle tokenVault
address = "7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie"
[[test.validator.clone]] # sb devnet attestation programID
address = "SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
[[test.validator.clone]] # sb devnet attestation IDL
address = "GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m"
# [[test.validator.clone]] # sb devnet attestation programID
# address = "sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
# [[test.validator.clone]] # sb devnet attestation IDL
# address = "5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz"
[[test.validator.clone]] # sb devnet attestation State
address = "EuCumvrswq5HZC4ME1wh7Q7V6dN8DRetP3eM1gU4RPYp"

File diff suppressed because it is too large Load Diff

View File

@ -18,5 +18,6 @@ default = []
[dependencies]
# anchor-lang = "0.28.0"
switchboard-solana = "0.5.3"
# switchboard-solana = { path = "../../../rust/switchboard-solana" }
switchboard-solana = "0.6.1"
# switchboard-solana = { version = "0.6", path = "../../../rust/switchboard-solana" }
bytemuck = "^1"

View File

@ -0,0 +1,3 @@
#!/bin/bash
curl https://api.binance.com/api/v3/exchangeInfo

View File

@ -15,7 +15,7 @@
"@coral-xyz/anchor": "^0.28.0",
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.73.3",
"@switchboard-xyz/common": "^2.2.0",
"@switchboard-xyz/common": "^2.2.4",
"@switchboard-xyz/oracle": "^2.1.13",
"@switchboard-xyz/solana.js": "workspace:*"
},

View File

@ -5,7 +5,7 @@ target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@ tokio = "^1"
futures = "0.3"
serde = "^1"
serde_json = "^1"
switchboard-utils = "0.5.0"
switchboard-solana = "0.5.3"
# switchboard-solana = { path = "../../../../rust/switchboard-solana" }
switchboard-utils = "0.6"
# switchboard-utils = { version = "0.6", path = "../../../../../sbv2-core/rust/switchboard-utils" }
switchboard-solana = "0.6.1"
# switchboard-solana = { version = "0.6", path = "../../../../rust/switchboard-solana" }

View File

@ -8,16 +8,29 @@ COPY . .
WORKDIR /home/root/switchboard-function/sgx-function
RUN --mount=type=cache,target=/usr/local/cargo/registry,id=${TARGETPLATFORM} --mount=type=cache,target=target,id=${TARGETPLATFORM} \
# RUN --mount=type=cache,target=/usr/local/cargo/registry,id=${TARGETPLATFORM} --mount=type=cache,target=./sgx-function/target,id=${TARGETPLATFORM} \
# cargo build --release && \
# cargo strip && \
# mv /home/root/switchboard-function/sgx-function/target/release/${CARGO_NAME} /sgx
RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=/home/root/switchboard-function/sgx-function/target \
cargo build --release && \
cargo strip && \
mv /home/root/switchboard-function/sgx-function/target/release/${CARGO_NAME} /sgx
mv target/release/basic-oracle-function /sgx/app
FROM switchboardlabs/sgx-function
# Copy the binary
WORKDIR /sgx
COPY --from=builder /sgx/${CARGO_NAME} /sgx/app
COPY --from=builder /sgx/app /sgx
# Get the measurement from the enclave
RUN /get_measurement.sh
RUN /get_measurement.sh
# COPY configs/app.manifest.template .
# COPY configs/boot.sh /boot.sh
RUN gramine-manifest /app.manifest.template > app.manifest
# RUN gramine-sgx-gen-private-key
RUN gramine-sgx-sign --manifest app.manifest --output app.manifest.sgx | tail -2 | tee /measurement.txt
ENTRYPOINT ["bash", "/boot.sh"]

View File

@ -8,7 +8,7 @@ WORKDIR /home/root/solana-sdk
COPY ./rust/switchboard-solana/Cargo.toml \
./rust/switchboard-solana/Cargo.lock \
./rust/switchboard-solana/
COPY ./examples/functions/01_basic_oracle/Cargo.toml \
./examples/functions/01_basic_oracle/Cargo.lock \
./examples/functions/01_basic_oracle/
@ -40,4 +40,5 @@ WORKDIR /sgx
COPY --from=builder /sgx/${CARGO_NAME} /sgx/app
# Get the measurement from the enclave
RUN /get_measurement.sh
RUN /get_measurement.sh
ENTRYPOINT ["bash", "/boot.sh"]

View File

@ -5,6 +5,7 @@ use crate::*;
pub use switchboard_utils::reqwest;
use serde::Deserialize;
use basic_oracle::{TradingSymbol, OracleDataBorsh};
const ONE: i128 = 1000000000;
@ -31,8 +32,8 @@ pub struct IndexData {
pub hr: Ticker,
pub d: Ticker,
}
impl Into<OracleData> for IndexData {
fn into(self) -> OracleData {
impl Into<OracleDataBorsh> for IndexData {
fn into(self) -> OracleDataBorsh {
let oracle_timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
@ -48,7 +49,7 @@ impl Into<OracleData> for IndexData {
let twap_1hr = parse_string_value(self.hr.weightedAvgPrice.as_str());
let twap_24hr = parse_string_value(self.d.weightedAvgPrice.as_str());
OracleData {
OracleDataBorsh {
oracle_timestamp,
price,
volume_1hr,
@ -61,15 +62,16 @@ impl Into<OracleData> for IndexData {
pub struct Binance {
btc_usdt: IndexData,
usdc_usdt: IndexData,
eth_usdt: IndexData,
sol_usdt: IndexData,
usdc_usdt: IndexData,
doge_usdt: IndexData,
}
impl Binance {
// Fetch data from the Binance API
pub async fn fetch() -> std::result::Result<Binance, SwitchboardClientError> {
let symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "USDCUSDT"];
let symbols = ["BTCUSDT", "USDCUSDT", "ETHUSDT", "SOLUSDT", "DOGEUSDT"];
let tickers_1hr = reqwest::get(format!(
"https://api.binance.com/api/v3/ticker?symbols=[{}]&windowSize=1h",
@ -120,34 +122,38 @@ impl Binance {
Ok(Binance {
btc_usdt: data.get(0).unwrap().clone(),
eth_usdt: data.get(1).unwrap().clone(),
sol_usdt: data.get(2).unwrap().clone(),
usdc_usdt: data.get(3).unwrap().clone(),
usdc_usdt: data.get(1).unwrap().clone(),
eth_usdt: data.get(2).unwrap().clone(),
sol_usdt: data.get(3).unwrap().clone(),
doge_usdt: data.get(4).unwrap().clone(),
})
}
pub fn to_ixns(&self, runner: &FunctionRunner) -> Vec<Instruction> {
let btc_usdt: OracleData = self.btc_usdt.clone().into();
// let btc_usdc: OracleData = self.btc_usdc.clone().into();
let eth_usdt: OracleData = self.eth_usdt.clone().into();
let sol_usdt: OracleData = self.sol_usdt.clone().into();
let usdc_usdt: OracleData = self.usdc_usdt.clone().into();
let usdt_usdc: OracleData = OracleData {
oracle_timestamp: usdc_usdt.oracle_timestamp,
price: ONE.checked_div(usdc_usdt.price).unwrap(),
volume_1hr: usdc_usdt.volume_1hr,
volume_24hr: usdc_usdt.volume_24hr,
twap_1hr: ONE.checked_div(usdc_usdt.twap_1hr).unwrap(),
twap_24hr: ONE.checked_div(usdc_usdt.twap_24hr).unwrap(),
};
let rows: Vec<OracleDataWithTradingSymbol> = vec![
OracleDataWithTradingSymbol {
symbol: TradingSymbol::Btc,
data: self.btc_usdt.clone().into(),
},
OracleDataWithTradingSymbol {
symbol: TradingSymbol::Usdc,
data: self.usdc_usdt.clone().into(),
},
OracleDataWithTradingSymbol {
symbol: TradingSymbol::Eth,
data: self.eth_usdt.clone().into(),
},
OracleDataWithTradingSymbol {
symbol: TradingSymbol::Sol,
data: self.sol_usdt.clone().into(),
},
OracleDataWithTradingSymbol {
symbol: TradingSymbol::Doge,
data: self.doge_usdt.clone().into(),
},
];
let params = RefreshPricesParams {
btc: Some(btc_usdt),
eth: Some(eth_usdt),
sol: Some(sol_usdt),
usdt: Some(usdt_usdc),
usdc: Some(usdc_usdt),
};
let params = RefreshPricesParams { rows };
let (program_state_pubkey, _state_bump) =
Pubkey::find_program_address(&[b"BASICORACLE"], &PROGRAM_ID);

View File

@ -4,7 +4,8 @@ pub mod binance;
pub use binance::*;
pub use basic_oracle::{
self, OracleData, RefreshPrices, RefreshPricesParams, SwitchboardDecimal, ID as PROGRAM_ID,
self, OracleData, OracleDataWithTradingSymbol, RefreshPrices, RefreshPricesParams,
SwitchboardDecimal, TradingSymbol, ID as PROGRAM_ID,
};
#[tokio::main(worker_threads = 12)]

View File

@ -20,6 +20,9 @@ pub struct Initialize<'info> {
bump
)]
pub oracle: AccountLoader<'info, MyOracleState>,
pub function: AccountLoader<'info, FunctionAccountData>,
/// CHECK:
pub authority: Signer<'info>,
@ -28,14 +31,14 @@ pub struct Initialize<'info> {
// SYSTEM ACCOUNTS
pub system_program: Program<'info, System>,
/// CHECK:
#[account(address = solana_program::sysvar::rent::ID)]
pub rent: AccountInfo<'info>,
// /// CHECK:
// #[account(address = solana_program::sysvar::rent::ID)]
// pub rent: AccountInfo<'info>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct InitializeParams {
pub mr_enclaves: Vec<[u8; 32]>,
// pub mr_enclaves: Vec<[u8; 32]>,
}
impl Initialize<'_> {
@ -44,9 +47,9 @@ impl Initialize<'_> {
_ctx: &Context<Self>,
params: &InitializeParams,
) -> anchor_lang::Result<()> {
if params.mr_enclaves.len() > 32 {
return Err(error!(BasicOracleError::ArrayOverflow));
}
// if params.mr_enclaves.len() > 32 {
// return Err(error!(BasicOracleError::ArrayOverflow));
// }
Ok(())
}
@ -54,9 +57,7 @@ impl Initialize<'_> {
let program = &mut ctx.accounts.program.load_init()?;
program.bump = *ctx.bumps.get("program").unwrap_or(&0);
program.authority = ctx.accounts.authority.key();
if !params.mr_enclaves.is_empty() {
program.mr_enclaves = parse_mr_enclaves(&params.mr_enclaves)?;
}
program.function = ctx.accounts.function.key();
let oracle = &mut ctx.accounts.oracle.load_init()?;
oracle.bump = *ctx.bumps.get("oracle").unwrap_or(&0);

View File

@ -1,6 +1,5 @@
pub mod initialize;
pub use initialize::*;
pub mod refresh_prices;
pub use refresh_prices::*;
pub mod set_enclaves;
pub use set_enclaves::*;

View File

@ -4,10 +4,11 @@ use crate::*;
pub struct RefreshPrices<'info> {
#[account(
seeds = [PROGRAM_SEED],
bump = program.load()?.bump,
constraint = program.load()?.is_valid_enclave(&quote.load()?.mr_enclave) @ BasicOracleError::InvalidMrEnclave
bump = program_state.load()?.bump,
has_one = function @ BasicOracleError::IncorrectSwitchboardFunction,
)]
pub program: AccountLoader<'info, MyProgramState>,
pub program_state: AccountLoader<'info, MyProgramState>,
#[account(
mut,
seeds = [ORACLE_SEED],
@ -15,28 +16,25 @@ pub struct RefreshPrices<'info> {
)]
pub oracle: AccountLoader<'info, MyOracleState>,
pub function: AccountLoader<'info, FunctionAccountData>,
// We use this to derive and verify the functions enclave state
#[account(
seeds = [QUOTE_SEED, function.key().as_ref()],
bump = quote.load()?.bump,
seeds::program = SWITCHBOARD_ATTESTATION_PROGRAM_ID,
has_one = secured_signer @ BasicOracleError::InvalidTrustedSigner,
constraint =
quote.load()?.mr_enclave != [0u8; 32] @ BasicOracleError::EmptySwitchboardQuote
FunctionAccountData::validate_enclave(
&function.to_account_info(),
&enclave.to_account_info(),
&enclave_signer.to_account_info()
)?
)]
pub quote: AccountLoader<'info, QuoteAccountData>,
pub secured_signer: Signer<'info>,
pub function: AccountLoader<'info, FunctionAccountData>,
pub enclave: AccountLoader<'info, EnclaveAccountData>,
pub enclave_signer: Signer<'info>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct RefreshPricesParams {
pub btc: Option<OracleData>,
pub eth: Option<OracleData>,
pub sol: Option<OracleData>,
pub usdt: Option<OracleData>,
pub usdc: Option<OracleData>,
pub rows: Vec<OracleDataWithTradingSymbol>,
}
impl RefreshPrices<'_> {
@ -50,26 +48,7 @@ impl RefreshPrices<'_> {
pub fn actuate(ctx: &Context<Self>, params: &RefreshPricesParams) -> anchor_lang::Result<()> {
let oracle = &mut ctx.accounts.oracle.load_mut()?;
if let Some(btc) = params.btc {
oracle.btc = btc;
}
if let Some(eth) = params.eth {
oracle.eth = eth;
}
if let Some(sol) = params.sol {
oracle.sol = sol;
}
if let Some(usdt) = params.usdt {
oracle.usdt = usdt;
}
if let Some(usdc) = params.usdc {
oracle.usdc = usdc;
}
oracle.save_rows(&params.rows)?;
Ok(())
}

View File

@ -1,47 +0,0 @@
use crate::*;
#[derive(Accounts)]
#[instruction(params: SetEnclavesParams)] // rpc parameters hint
pub struct SetEnclaves<'info> {
#[account(
mut,
seeds = [PROGRAM_SEED],
bump = program.load()?.bump,
has_one = authority
)]
pub program: AccountLoader<'info, MyProgramState>,
pub authority: Signer<'info>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct SetEnclavesParams {
pub mr_enclaves: Option<Vec<[u8; 32]>>,
}
impl SetEnclaves<'_> {
pub fn validate(
&self,
_ctx: &Context<Self>,
params: &SetEnclavesParams,
) -> anchor_lang::Result<()> {
if let Some(enclaves) = params.mr_enclaves.clone() {
if enclaves.len() > 32 {
return Err(error!(BasicOracleError::ArrayOverflow));
}
}
Ok(())
}
pub fn actuate(ctx: &Context<Self>, params: &SetEnclavesParams) -> anchor_lang::Result<()> {
let program = &mut ctx.accounts.program.load_mut()?;
if let Some(enclaves) = params.mr_enclaves.clone() {
if !enclaves.is_empty() {
program.mr_enclaves = parse_mr_enclaves(&enclaves)?;
}
}
Ok(())
}
}

View File

@ -15,4 +15,10 @@ pub enum BasicOracleError {
InvalidMrEnclave,
#[msg("Switchboard QuoteAccount has an empty MrEnclave (invalid)")]
EmptySwitchboardQuote,
#[msg("Failed to find a valid trading symbol for this price")]
InvalidSymbol,
#[msg("FunctionAccount pubkey did not match program_state.function")]
IncorrectSwitchboardFunction,
#[msg("FunctionAccount pubkey did not match program_state.function")]
InvalidSwitchboardFunction,
}

View File

@ -12,7 +12,7 @@ pub use utils::*;
pub mod actions;
pub use actions::*;
declare_id!("9PAxFbRDepv1ziPeUW5KHcpgpgPtxWV4ZzVwqDBqymok");
declare_id!("6tdxUefBQRpL1CbJhzXgcMtWChKqXj9P9Rz2bvTWiiar");
pub const PROGRAM_SEED: &[u8] = b"BASICORACLE";
@ -30,14 +30,6 @@ pub mod basic_oracle {
Initialize::actuate(&ctx, &params)
}
#[access_control(ctx.accounts.validate(&ctx, &params))]
pub fn set_enclaves(
ctx: Context<SetEnclaves>,
params: SetEnclavesParams,
) -> anchor_lang::Result<()> {
SetEnclaves::actuate(&ctx, &params)
}
#[access_control(ctx.accounts.validate(&ctx, &params))]
pub fn refresh_oracles(
ctx: Context<RefreshPrices>,

View File

@ -1,25 +1,15 @@
use crate::*;
use bytemuck::{Pod, Zeroable};
#[account(zero_copy)]
#[derive(Default, Debug, AnchorSerialize)]
#[account(zero_copy(unsafe))]
pub struct MyProgramState {
pub bump: u8,
pub authority: Pubkey,
/// List of valid measurements that are permitted to push data onto the oracle
pub mr_enclaves: [[u8; 32]; 32],
}
impl MyProgramState {
pub fn is_valid_enclave(&self, quote_enclave: &[u8; 32]) -> bool {
if *quote_enclave == [0u8; 32] {
return false;
}
self.mr_enclaves.contains(quote_enclave)
}
pub function: Pubkey,
}
#[zero_copy]
#[derive(Default, Debug, AnchorDeserialize, AnchorSerialize)]
#[repr(packed)]
#[zero_copy(unsafe)]
pub struct OracleData {
pub oracle_timestamp: i64,
pub price: i128,
@ -29,8 +19,38 @@ pub struct OracleData {
pub twap_24hr: i128,
}
#[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize)]
pub struct OracleDataBorsh {
pub oracle_timestamp: i64,
pub price: i128,
pub volume_1hr: i128,
pub volume_24hr: i128,
pub twap_1hr: i128,
pub twap_24hr: i128,
}
impl From<OracleDataBorsh> for OracleData {
fn from(value: OracleDataBorsh) -> Self {
Self {
oracle_timestamp: value.oracle_timestamp,
price: value.price.clone(),
volume_1hr: value.volume_1hr.clone(),
volume_24hr: value.volume_24hr.clone(),
twap_1hr: value.twap_1hr.clone(),
twap_24hr: value.twap_24hr.clone(),
}
}
}
#[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize)]
pub struct OracleDataWithTradingSymbol {
pub symbol: TradingSymbol,
pub data: OracleDataBorsh,
}
impl OracleData {
pub fn get_fair_price(&self) -> anchor_lang::Result<f64> {
// Check the price was updated in the last 10 seconds
// Do some logic here based on the twap
let price: f64 = SwitchboardDecimal {
@ -44,13 +64,92 @@ impl OracleData {
}
#[repr(packed)]
#[account(zero_copy)]
#[derive(Default, Debug)]
#[account(zero_copy(unsafe))]
pub struct MyOracleState {
pub bump: u8,
pub btc: OracleData,
pub usdc: OracleData,
pub eth: OracleData,
pub sol: OracleData,
pub usdt: OracleData,
pub usdc: OracleData,
pub doge: OracleData,
// can always re-allocate to add more
// pub reserved: [u8; 2400],
}
impl MyOracleState {
pub fn save_rows(
&mut self,
rows: &Vec<OracleDataWithTradingSymbol>,
) -> anchor_lang::Result<()> {
for row in rows.iter() {
match row.symbol {
TradingSymbol::Btc => {
msg!("saving BTC price, {}", { row.data.price });
self.btc = row.data.into();
}
TradingSymbol::Usdc => {
msg!("saving USDC price, {}", { row.data.price });
self.usdc = row.data.into();
}
TradingSymbol::Eth => {
msg!("saving ETH price, {}", { row.data.price });
self.eth = row.data.into();
}
TradingSymbol::Sol => {
msg!("saving SOL price, {}", { row.data.price });
self.sol = row.data.into();
}
TradingSymbol::Doge => {
msg!("saving DOGE price, {}", { row.data.price });
self.doge = row.data.into();
}
_ => {
msg!("no trading symbol found for {:?}", row.symbol);
// TODO: emit an event so we can detect and fix
}
}
}
Ok(())
}
}
#[repr(u8)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
pub enum TradingSymbol {
#[default]
Unknown = 0,
Btc = 1,
Usdc = 2,
Eth = 3,
Sol = 4,
Doge = 5,
}
unsafe impl Pod for TradingSymbol {}
unsafe impl Zeroable for TradingSymbol {}
impl From<TradingSymbol> for u8 {
fn from(value: TradingSymbol) -> Self {
match value {
TradingSymbol::Btc => 1,
TradingSymbol::Usdc => 2,
TradingSymbol::Eth => 3,
TradingSymbol::Sol => 4,
TradingSymbol::Doge => 5,
_ => 0,
}
}
}
impl From<u8> for TradingSymbol {
fn from(value: u8) -> Self {
match value {
1 => TradingSymbol::Btc,
2 => TradingSymbol::Usdc,
3 => TradingSymbol::Eth,
4 => TradingSymbol::Sol,
5 => TradingSymbol::Doge,
_ => TradingSymbol::default(),
}
}
}

View File

@ -10,7 +10,9 @@ import {
MrEnclave,
types,
attestationTypes,
AttestationProgramStateAccount,
} from "@switchboard-xyz/solana.js";
import { sleep } from "@switchboard-xyz/common";
const unixTimestamp = () => Math.floor(Date.now() / 1000);
@ -50,10 +52,12 @@ describe("basic_oracle", () => {
let functionAccount: FunctionAccount;
before(async () => {
const switchboardProgram = await SwitchboardProgram.fromProvider(
program.provider as anchor.AnchorProvider
);
await AttestationProgramStateAccount.getOrCreate(switchboardProgram);
switchboard = await AttestationQueueAccount.bootstrapNewQueue(
await SwitchboardProgram.fromProvider(
program.provider as anchor.AnchorProvider
)
switchboardProgram
);
[functionAccount] = await FunctionAccount.create(
@ -71,11 +75,12 @@ describe("basic_oracle", () => {
it("Is initialized!", async () => {
// Add your test here.
const tx = await program.methods
.initialize({ mrEnclaves: [] })
.initialize({})
.accounts({
program: programStatePubkey,
oracle: oraclePubkey,
authority: payer,
function: functionAccount.publicKey,
})
.rpc()
.catch((err) => {
@ -85,32 +90,24 @@ describe("basic_oracle", () => {
console.log("Your transaction signature", tx);
});
it("Adds an enclave measurement", async () => {
// Add your test here.
const tx = await program.methods
.setEnclaves({ mrEnclaves: [Array.from(MRENCLAVE)] })
.accounts({
program: programStatePubkey,
authority: payer,
})
.rpc()
.catch((err) => {
console.error(err);
throw err;
});
console.log("Your transaction signature", tx);
const programState = await program.account.myProgramState.fetch(
programStatePubkey
);
console.log(
`MrEnclaves:\n\t${programState.mrEnclaves
.filter(
(e) => Buffer.compare(Buffer.from(e), Buffer.from(emptyEnclave)) !== 0
)
.map((e) => `[${e}]`)
.join("\n\t")}`
);
});
// it("Adds an enclave measurement", async () => {
// // Add your test here.
// const tx = await program.methods
// .setEnclaves({ mrEnclaves: [Array.from(MRENCLAVE)] })
// .accounts({
// program: programStatePubkey,
// authority: payer,
// })
// .rpc()
// .catch((err) => {
// console.error(err);
// throw err;
// });
// console.log("Your transaction signature", tx);
// const programState = await program.account.myProgramState.fetch(
// programStatePubkey
// );
// });
it("Oracle refreshes the prices", async () => {
const securedSigner = anchor.web3.Keypair.generate();
@ -133,54 +130,55 @@ describe("basic_oracle", () => {
},
{
function: functionAccount.publicKey,
fnSigner: securedSigner.publicKey,
securedSigner: switchboard.verifier.signer.publicKey,
functionEnclaveSigner: securedSigner.publicKey,
verifierEnclaveSigner: switchboard.verifier.signer.publicKey,
verifierQuote: switchboard.verifier.quoteAccount.publicKey,
attestationQueue: switchboard.attestationQueueAccount.publicKey,
escrow: functionAccount.getEscrow(),
receiver: rewardAddress,
verifierPermission: switchboard.verifier.permissionAccount.publicKey,
fnPermission: functionAccount.getPermissionAccount(
switchboard.attestationQueueAccount.publicKey,
payer
)[0].publicKey,
state:
switchboard.attestationQueueAccount.program.attestationProgramState
.publicKey,
payer: payer,
fnQuote: functionAccount.getQuoteAccount()[0].publicKey,
fnQuote: functionAccount.getEnclaveAccount()[0].publicKey,
tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
systemProgram: anchor.web3.SystemProgram.programId,
}
);
// Add your test here.
const tx = await program.methods
.refreshOracles({
btc: {
oracleTimestamp: new anchor.BN(0),
price: new anchor.BN("25225000000000"), // 25225
volume: new anchor.BN("1337000000000000"), // 1337000
twap24hr: new anchor.BN("25550000000000"), // 25550
},
eth: {
oracleTimestamp: new anchor.BN(0),
price: new anchor.BN("1815000000000"), // 1815
volume: new anchor.BN("556000000000000"), // 556000
twap24hr: new anchor.BN("1913000000000"), // 1913
},
sol: null,
usdt: null,
usdc: null,
doge: null,
near: null,
rows: [
{
symbol: { btc: {} },
data: {
oracleTimestamp: new anchor.BN(unixTimestamp()),
price: new anchor.BN("25225000000000"), // 25225
volume1hr: new anchor.BN("25225000000000"), // 1337000
volume24hr: new anchor.BN("25225000000000"), // 1337000
twap1hr: new anchor.BN("25225000000000"), // 25550
twap24hr: new anchor.BN("25225000000000"), // 25550
},
},
{
symbol: { eth: {} },
data: {
oracleTimestamp: new anchor.BN(unixTimestamp()),
price: new anchor.BN("1750000000000"), // 1750
volume1hr: new anchor.BN("420000000000"), // 420000
volume24hr: new anchor.BN("420000000000"), // 420000
twap1hr: new anchor.BN("1750000000000"), // 1750
twap24hr: new anchor.BN("1750000000000"), // 1750
},
},
],
})
.accounts({
program: programStatePubkey,
programState: programStatePubkey,
oracle: oraclePubkey,
function: functionAccount.publicKey,
quote: functionAccount.getQuoteAccount()[0].publicKey,
securedSigner: securedSigner.publicKey,
enclave: functionAccount.getEnclaveAccount()[0].publicKey,
enclaveSigner: securedSigner.publicKey,
})
.preInstructions([functionVerifyIxn])
.signers([switchboard.verifier.signer, securedSigner])
@ -192,13 +190,17 @@ describe("basic_oracle", () => {
console.log("Your transaction signature", tx);
await sleep(5000);
const oracleState = await program.account.myOracleState.fetch(oraclePubkey);
console.log(`BTC`);
console.log(oracleState);
console.log(`BTC\n`);
printData(oracleState.btc);
console.log(`ETH`);
console.log(`ETH\n`);
printData(oracleState.eth);
console.log(`SOL`);
console.log(`SOL\n`);
printData(oracleState.sol);
});
});
@ -212,12 +214,15 @@ function normalizeDecimals(value: anchor.BN) {
function printData(obj: {
oracleTimestamp: anchor.BN;
price: anchor.BN;
volume: anchor.BN;
volume1hr: anchor.BN;
volume24hr: anchor.BN;
twap1hr: anchor.BN;
twap24hr: anchor.BN;
}) {
console.log(
`\tprice: $${normalizeDecimals(obj.price)}\n\tvolume: ${normalizeDecimals(
obj.volume
)}\n\t24Hr Twap: $${normalizeDecimals(obj.twap24hr)}`
);
console.log(`\tprice: ${normalizeDecimals(obj.price)}`);
console.log(`\ttimestamp: ${obj.oracleTimestamp.toNumber()}`);
console.log(`\t1Hr Volume: ${normalizeDecimals(obj.volume1hr)}`);
console.log(`\t24Hr Volume: ${normalizeDecimals(obj.volume24hr)}`);
console.log(`\t1Hr Twap: ${normalizeDecimals(obj.twap1hr)}`);
console.log(`\t24Hr Twap: ${normalizeDecimals(obj.twap24hr)}`);
}

View File

@ -35,7 +35,7 @@ address = "CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
address = "7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie"
[[test.validator.clone]] # sb devnet attestation programID
address = "SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
address = "sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
[[test.validator.clone]] # sb devnet attestation IDL
address = "GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m"
address = "5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz"

View File

@ -0,0 +1,9 @@
{
"extension": ["ts"],
"node-option": [
"experimental-specifier-resolution=node",
"loader=ts-node/esm"
],
"spec": ["test/**/*.spec.ts"],
"timeout": "60000"
}

File diff suppressed because it is too large Load Diff

View File

@ -521,7 +521,7 @@
{
"name": "quote",
"isMut": false,
"isSigner": false
"isSigner": true
},
{
"name": "rewardWallet",
@ -1451,7 +1451,7 @@
{
"name": "quote",
"isMut": false,
"isSigner": false
"isSigner": true
},
{
"name": "programState",
@ -2551,97 +2551,6 @@
}
],
"accounts": [
{
"name": "QuoteAccountData",
"type": {
"kind": "struct",
"fields": [
{
"name": "delegatedSecuredSigner",
"type": "publicKey"
},
{
"name": "bump",
"type": "u8"
},
{
"name": "quoteRegistry",
"docs": [
"TODO: Add description"
],
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "registryKey",
"docs": [
"Key to lookup the buffer data on IPFS or an alternative decentralized storage solution."
],
"type": {
"array": [
"u8",
64
]
}
},
{
"name": "attestationQueue",
"docs": [
"Queue used for attestation to verify a MRENCLAVE measurement."
],
"type": "publicKey"
},
{
"name": "mrEnclave",
"docs": [
"The quotes MRENCLAVE measurement dictating the contents of the secure enclave."
],
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "verificationStatus",
"type": "u8"
},
{
"name": "verificationTimestamp",
"type": "i64"
},
{
"name": "validUntil",
"type": "i64"
},
{
"name": "isOnQueue",
"type": "bool"
},
{
"name": "lastHeartbeat",
"docs": [
"The last time the quote heartbeated."
],
"type": "i64"
},
{
"name": "ebuf",
"type": {
"array": [
"u8",
1024
]
}
}
]
}
},
{
"name": "SbState",
"type": {
@ -5775,6 +5684,132 @@
]
}
},
{
"name": "EnclaveAccountData",
"type": {
"kind": "struct",
"fields": [
{
"name": "enclaveSigner",
"docs": [
"The address of the signer generated within an enclave."
],
"type": "publicKey"
},
{
"name": "authority",
"docs": [
"The authority of the EnclaveAccount which is permitted to make account changes."
],
"type": "publicKey"
},
{
"name": "attestationQueue",
"docs": [
"Queue used for attestation to verify a MRENCLAVE measurement."
],
"type": "publicKey"
},
{
"name": "mrEnclave",
"docs": [
"The quotes MRENCLAVE measurement dictating the contents of the secure enclave."
],
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "verificationStatus",
"docs": [
"The VerificationStatus of the quote."
],
"type": "u8"
},
{
"name": "verificationTimestamp",
"docs": [
"The unix timestamp when the quote was last verified."
],
"type": "i64"
},
{
"name": "validUntil",
"docs": [
"The unix timestamp when the quotes verification status expires."
],
"type": "i64"
},
{
"name": "createdAt",
"docs": [
"The unix timestamp when the quote was created."
],
"type": "i64"
},
{
"name": "quoteRegistry",
"docs": [
"The off-chain registry where the verifiers quote can be located."
],
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "registryKey",
"docs": [
"Key to lookup the buffer data on IPFS or an alternative decentralized storage solution."
],
"type": {
"array": [
"u8",
64
]
}
},
{
"name": "isOnQueue",
"docs": [
"Whether the quote is located on the AttestationQueues buffer."
],
"type": "bool"
},
{
"name": "lastHeartbeat",
"docs": [
"The last time the quote heartbeated on-chain."
],
"type": "i64"
},
{
"name": "bump",
"docs": [
"The PDA bump. Only set for FunctionAccount quotes."
],
"type": "u8"
},
{
"name": "ebuf",
"docs": [
"Reserved."
],
"type": {
"array": [
"u8",
1024
]
}
}
]
}
},
{
"name": "Hash",
"type": {
@ -6769,6 +6804,9 @@
"type": {
"kind": "enum",
"variants": [
{
"name": "None"
},
{
"name": "VerificationPending"
},
@ -8171,6 +8209,11 @@
"code": 6102,
"name": "GenericError",
"msg": ""
},
{
"code": 6103,
"name": "InvalidAuthorityState",
"msg": ""
}
]
}

View File

@ -1,6 +1,6 @@
{
"name": "@switchboard-xyz/solana.js",
"version": "2.3.0-beta.7",
"version": "2.3.0-beta.9",
"author": "",
"license": "MIT",
"description": "A Typescript client to interact with Switchboard on Solana.",
@ -146,14 +146,14 @@
"keypair:create": "shx find ~/.config/solana/id.json || solana-keygen new -s --no-bip39-passphrase --outfile ~/.config/solana/id.json",
"localnet:down": "kill -9 $(pgrep command solana-test-validator) || exit 0",
"localnet": "tsx ./scripts/localnet.ts",
"local:validator": "shx mkdir -p .anchor/test-ledger || true; solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --url https://api.devnet.solana.com --rpc-port 8899 --clone SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f `# programId` --clone 7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF `# programDataAddress` --clone Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk `# idlAddress` --clone SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha `# sgxProgramId` --clone FSD8p7tDkhffAiMgAvMXi9veJW1uSod4H3F3REn7nMNC `# sgxProgramDataAddress` --clone GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m `# sgxIdlAddress` --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd `# programState` --clone 7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie `# switchboardVault`",
"local:validator:mainnet": "solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --rpc-port 8899 --url https://api.mainnet-beta.solana.com --clone SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone 7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha --clone FSD8p7tDkhffAiMgAvMXi9veJW1uSod4H3F3REn7nMNC --clone GjWPcr9QrdHk8At821qcZPM9NPpCDGivaTCMQG5nWj2m --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd --clone J7nSEX8ADf3pVVicd6yKy2Skvg8iLePEmkLUisAAaioD",
"local:validator": "shx mkdir -p .anchor/test-ledger || true; solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --url https://api.devnet.solana.com --rpc-port 8899 --clone SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f `# programId` --clone 7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF `# programDataAddress` --clone Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk `# idlAddress` --clone sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx `# sgxProgramId` --clone FSD8p7tDkhffAiMgAvMXi9veJW1uSod4H3F3REn7nMNC `# sgxProgramDataAddress` --clone 5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz `# sgxIdlAddress` --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd `# programState` --clone 7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie `# switchboardVault`",
"local:validator:mainnet": "solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --rpc-port 8899 --url https://api.mainnet-beta.solana.com --clone SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone 7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx --clone FSD8p7tDkhffAiMgAvMXi9veJW1uSod4H3F3REn7nMNC --clone 5ExuoQR69trmKQfB95fDsUGsUrrChbGq9PFgt8qouncz --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd --clone J7nSEX8ADf3pVVicd6yKy2Skvg8iLePEmkLUisAAaioD",
"generate": "tsx ./scripts/generate-client.ts",
"build:old": "shx rm -rf lib || true; tsc -p tsconfig.cjs.json && tsc",
"build": "node esbuild.js",
"watch": "tsc -p tsconfig.cjs.json --watch",
"test": "node ./node_modules/mocha/bin/mocha --loader=ts-node/esm --extension ts --timeout 60000 --exit",
"test:localnet": "SOLANA_LOCALNET=1 node ./node_modules/mocha/bin/mocha --loader=ts-node/esm --extension ts --timeout 60000 --exit",
"test:localnet": "SOLANA_LOCALNET=1 node ./node_modules/mocha/bin/mocha --exit",
"test:localnet:mainnet": "SWITCHBOARD_PROGRAM_ID=SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f SOLANA_LOCALNET=1 SOLANA_CLUSTER=mainnet-beta node ./node_modules/mocha/bin/mocha --loader=ts-node/esm --extension ts --timeout 60000 --exit",
"prepack": "npm run lint && npm run build",
"lint": "gts lint ./src",
@ -161,13 +161,13 @@
"fix": "gts fix ./src ./test"
},
"dependencies": {
"@coral-xyz/anchor": "^0.27.0",
"@coral-xyz/borsh": "^0.27.0",
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.73.0",
"@switchboard-xyz/common": "^2.1.46",
"@coral-xyz/anchor": "^0.28.0",
"@coral-xyz/borsh": "^0.28.0",
"@solana/spl-token": "^0.3.8",
"@solana/web3.js": "^1.77.3",
"@switchboard-xyz/common": "^2.2.4",
"cron-validator": "^1.3.1",
"dotenv": "^16.0.3",
"dotenv": "^16.3.1",
"lodash": "^4.17.21"
},
"devDependencies": {
@ -176,7 +176,7 @@
"@types/chai": "^4.3.4",
"@types/lodash": "^4.14.191",
"@types/mocha": "^10.0.0",
"@types/node": "^18.11.18",
"@types/node": "^20.3.1",
"@types/shelljs": "^0.8.12",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"chai": "^4.3.7",
@ -191,7 +191,7 @@
"ts-node": "^10.9.1",
"tsx": "^3.12.7",
"typedoc": "^0.23.23",
"typescript": "^4.9.4"
"typescript": "^5.1.3"
},
"pre-commit": [
"build"

View File

@ -128,7 +128,7 @@ async function main() {
}
),
runCommandAsync(
`anchor idl fetch -o ${attestationDevnetIdlPath} SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha --provider.cluster devnet`,
`anchor idl fetch -o ${attestationDevnetIdlPath} sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx --provider.cluster devnet`,
{
encoding: "utf-8",
}
@ -149,7 +149,7 @@ async function main() {
{ encoding: "utf-8" }
),
runCommandAsync(
`npx anchor-client-gen --program-id SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha ${switchboardAttestationIdlPath} ${attestationGeneratedPath}`,
`npx anchor-client-gen --program-id sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx ${switchboardAttestationIdlPath} ${attestationGeneratedPath}`,
{ encoding: "utf-8" }
),
]);
@ -160,7 +160,7 @@ async function main() {
{ encoding: "utf-8" }
),
runCommandAsync(
`npx anchor-client-gen --program-id SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha ${attestationDevnetIdlPath} ${attestationGeneratedPath}`,
`npx anchor-client-gen --program-id sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx ${attestationDevnetIdlPath} ${attestationGeneratedPath}`,
{ encoding: "utf-8" }
),
]);
@ -221,8 +221,6 @@ async function main() {
execSync(`git restore ${file}`, { encoding: "utf-8" });
}
// delete the extra QuoteAccountData
await fs.rm(path.join(v2GeneratedPath, "accounts", "QuoteAccountData.ts"));
// delete the extra VerificationStatus
await fs.rm(path.join(v2GeneratedPath, "types", "VerificationStatus.ts"));
@ -263,18 +261,6 @@ const processFile = async (file: string) => {
);
}
if (file.includes("index.ts")) {
if (file === path.join(v2GeneratedPath, "accounts", "index.ts")) {
updatedFileString = updatedFileString.replace(
`export { QuoteAccountData } from "./QuoteAccountData"
export type {
QuoteAccountDataFields,
QuoteAccountDataJSON,
} from "./QuoteAccountData"
`,
``
);
}
// add the .js extension to all local import/export paths
return updatedFileString.replace(
/((import|export)((\s\w+)?([^'"]*))from\s['"])([^'"]+)(['"])/gm,

View File

@ -30,7 +30,7 @@ const SWITCHBOARD_PROGRAM_ID = new PublicKey(
);
const SWITCHBOARD_ATTESTATION_PROGRAM_ID = new PublicKey(
"SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
"sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
);
const jsSdkRoot = path.join(__dirname, "..");
@ -129,7 +129,7 @@ async function main() {
devSwitchboard,
defaultPubkeyPath,
"switchboard_attestation_program",
"SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
"sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
),
]);
} else {
@ -268,7 +268,7 @@ async function programDeploy(
{
cwd: switchboardDir,
encoding: "utf8",
// stdio: 'pipe',
stdio: "pipe",
shell: "/bin/zsh",
}
);
@ -289,10 +289,13 @@ async function programDeploy(
{
cwd: switchboardDir,
encoding: "utf8",
// stdio: 'pipe',
stdio: "pipe",
shell: "/bin/zsh",
}
);
).catch((e) => {
console.error(e);
throw e;
});
}
async function runCommandAsync(command, options) {

View File

@ -55,6 +55,7 @@ import {
Cluster,
ConfirmOptions,
Connection,
GetProgramAccountsResponse,
Keypair,
PublicKey,
SendOptions,
@ -84,7 +85,7 @@ export const SB_V2_PID = new PublicKey(
* Switchboard's Attestation Program ID
*/
export const SB_ATTESTATION_PID = new PublicKey(
"SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
"sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
);
/**
@ -740,7 +741,7 @@ export class SwitchboardProgram {
},
],
})
.then((values: Array<AccountInfoResponse | undefined>) => {
.then((values: GetProgramAccountsResponse) => {
return values.filter(Boolean) as Array<AccountInfoResponse>;
});
@ -780,7 +781,7 @@ export class SwitchboardProgram {
slidingResult: Map<string, SlidingResultAccountData>;
vrfs: Map<string, VrfAccountData>;
}> {
const accountInfos: Array<AccountInfoResponse> =
const accountInfos: GetProgramAccountsResponse =
await this.connection.getProgramAccounts(this.programId);
// buffer - [42, 55, 46, 46, 45, 52, 78, 78]

View File

@ -1682,7 +1682,7 @@ export class AggregatorAccount extends Account<AggregatorAccountData> {
public quoteKeypairFromSeed(seed: PublicKey): Keypair {
const hash = createHash("sha256");
hash.update(Buffer.from("QuoteAccountData"));
hash.update(Buffer.from("EnclaveAccountData"));
hash.update(seed.toBuffer());
const kp = Keypair.fromSeed(hash.digest());
return kp;

View File

@ -41,7 +41,7 @@ export interface AttestationPermissionSetParams {
queueAuthority?: Keypair;
queue: PublicKey;
node: PublicKey;
enclave: PublicKey;
}
/**
* Account type dictating the level of permissions between a granter and a grantee.
@ -205,7 +205,7 @@ export class AttestationPermissionAccount extends Account<types.AttestationPermi
? params.queueAuthority.publicKey
: payer,
attestationQueue: params.queue,
node: params.node,
enclave: params.enclave,
}
),
],

View File

@ -16,9 +16,9 @@ import {
/**
* Account type representing Switchboard global program state.
*
* Data: {@linkcode types.State}
* Data: {@linkcode types.AttestationProgramState}
*/
export class AttestationProgramStateAccount extends Account<types.State> {
export class AttestationProgramStateAccount extends Account<types.AttestationProgramState> {
static accountName = "State";
public static size = 1128;
@ -26,15 +26,16 @@ export class AttestationProgramStateAccount extends Account<types.State> {
/**
* @return account size of the global {@linkcode AttestationProgramStateAccount}.
*/
public readonly size = this.program.account.sbState.size;
public readonly size =
this.program.attestationAccount.attestationProgramState.size;
/**
* Return a program state account state initialized to the default values.
*/
public static default(): types.State {
public static default(): types.AttestationProgramState {
const buffer = Buffer.alloc(AttestationProgramStateAccount.size, 0);
types.State.discriminator.copy(buffer, 0);
return types.State.decode(buffer);
types.AttestationProgramState.discriminator.copy(buffer, 0);
return types.AttestationProgramState.decode(buffer);
}
/**
@ -42,22 +43,22 @@ export class AttestationProgramStateAccount extends Account<types.State> {
*/
public static createMock(
programId: PublicKey,
data: Partial<types.State>,
data: Partial<types.AttestationProgramState>,
options?: {
lamports?: number;
rentEpoch?: number;
}
): AccountInfo<Buffer> {
const fields: types.StateFields = {
const fields: types.AttestationProgramStateFields = {
...AttestationProgramStateAccount.default(),
...data,
// any cleanup actions here
};
const state = new types.State(fields);
const state = new types.AttestationProgramState(fields);
const buffer = Buffer.alloc(AttestationProgramStateAccount.size, 0);
types.State.discriminator.copy(buffer, 0);
types.State.layout.encode(state, buffer, 8);
types.AttestationProgramState.discriminator.copy(buffer, 0);
types.AttestationProgramState.layout.encode(state, buffer, 8);
return {
executable: false,
@ -72,7 +73,7 @@ export class AttestationProgramStateAccount extends Account<types.State> {
public static async load(
program: SwitchboardProgram,
publicKey: PublicKey | string
): Promise<[AttestationProgramStateAccount, types.State]> {
): Promise<[AttestationProgramStateAccount, types.AttestationProgramState]> {
const account = new AttestationProgramStateAccount(
program,
typeof publicKey === "string" ? new PublicKey(publicKey) : publicKey
@ -82,10 +83,13 @@ export class AttestationProgramStateAccount extends Account<types.State> {
}
/**
* Retrieve and decode the {@linkcode types.State} stored in this account.
* Retrieve and decode the {@linkcode types.AttestationProgramState} stored in this account.
*/
public async loadData(): Promise<types.State> {
const data = await types.State.fetch(this.program, this.publicKey);
public async loadData(): Promise<types.AttestationProgramState> {
const data = await types.AttestationProgramState.fetch(
this.program,
this.publicKey
);
if (data === null)
throw new errors.AccountNotFoundError(
"Attestation Program State",

View File

@ -14,7 +14,7 @@ import {
AttestationPermissionAccount,
AttestationPermissionSetParams,
} from "./attestationPermissionAccount.js";
import { QuoteAccount, QuoteAccountInitParams } from "./quoteAccount.js";
import { EnclaveAccount, EnclaveAccountInitParams } from "./enclaveAccount.js";
import {
Keypair,
@ -87,7 +87,7 @@ export interface AttestationQueueRemoveMrEnclaveParams {
}
export type CreateQueueQuoteParams = Omit<
QuoteAccountInitParams,
EnclaveAccountInitParams,
"queueAccount"
> &
Partial<AttestationPermissionSetParams> & {
@ -109,13 +109,13 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
static accountName = "AttestationQueueAccountData";
/**
* Get the size of an {@linkcode QueueAccount} on-chain.
* Get the size of an {@linkcode types.AttestationQueueAccountData} on-chain.
*/
public readonly size =
this.program.attestationAccount.attestationQueueAccountData.size;
/**
* Retrieve and decode the {@linkcode types.PermissionAccountData} stored in this account.
* Retrieve and decode the {@linkcode types.AttestationQueueAccountData} stored in this account.
*/
public async loadData(): Promise<types.AttestationQueueAccountData> {
this.program.verifyAttestation();
@ -197,7 +197,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
payer: PublicKey,
params: CreateQueueQuoteParams,
options?: TransactionObjectOptions
): Promise<[QuoteAccount, TransactionObject]> {
): Promise<[EnclaveAccount, TransactionObject]> {
this.program.verifyAttestation();
const authority = params.authority ?? payer;
@ -205,7 +205,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
const queueAuthority =
params.queueAuthorityPubkey ?? (await this.loadData()).authority;
const [quoteAccount, quoteInit] = await QuoteAccount.createInstruction(
const [enclaveAccount, quoteInit] = await EnclaveAccount.createInstruction(
this.program,
payer,
{ ...params, queueAccount: this, authority },
@ -213,7 +213,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
);
if (!params.createPermissions && !params.enable) {
return [quoteAccount, quoteInit];
return [enclaveAccount, quoteInit];
}
const [permissionAccount, permissionInit] =
@ -222,7 +222,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
payer,
{
granter: this.publicKey,
grantee: quoteAccount.publicKey,
grantee: enclaveAccount.publicKey,
authority: queueAuthority,
},
options
@ -234,18 +234,18 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
permission:
new types.SwitchboardAttestationPermission.PermitNodeheartbeat(),
queue: this.publicKey,
node: quoteAccount.publicKey,
enclave: enclaveAccount.publicKey,
});
permissionInit.combine(permissionSet);
}
return [quoteAccount, quoteInit.combine(permissionInit)];
return [enclaveAccount, quoteInit.combine(permissionInit)];
}
public async createQuote(
params: CreateQueueQuoteParams,
options?: SendTransactionObjectOptions
): Promise<[QuoteAccount, TransactionSignature]> {
): Promise<[EnclaveAccount, TransactionSignature]> {
const [account, txnObject] = await this.createQuoteInstruction(
this.program.walletPubkey,
params,
@ -449,7 +449,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
permission: verifierQuotePermissions1.publicKey,
authority: authority.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
node: verifierQuoteKeypair1.publicKey,
enclave: verifierQuoteKeypair1.publicKey,
}
)
);
@ -468,7 +468,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
{
quote: verifierQuoteKeypair1.publicKey,
authority: authority.publicKey,
securedSigner: verifierQuoteSigner1.publicKey,
enclaveSigner: verifierQuoteSigner1.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
}
)
@ -481,7 +481,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
{ params: {} },
{
quote: verifierQuoteKeypair1.publicKey,
securedSigner: verifierQuoteSigner1.publicKey,
enclaveSigner: verifierQuoteSigner1.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
queueAuthority: authority.publicKey,
gcNode: verifierQuoteKeypair1.publicKey,
@ -508,7 +508,7 @@ export class AttestationQueueAccount extends Account<types.AttestationQueueAccou
attestationQueueAccount,
signatures,
verifier: {
quoteAccount: new QuoteAccount(
quoteAccount: new EnclaveAccount(
program,
verifierQuoteKeypair1.publicKey
),
@ -529,7 +529,7 @@ export type CreateBootstrappedQueueParams =
export type BootstrappedAttestationQueue = {
attestationQueueAccount: AttestationQueueAccount;
verifier: {
quoteAccount: QuoteAccount;
quoteAccount: EnclaveAccount;
permissionAccount: AttestationPermissionAccount;
signer: Keypair;
};

View File

@ -1,4 +1,3 @@
import { Account } from "../accounts/account.js";
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
@ -10,6 +9,7 @@ import {
import { RawBuffer } from "../types.js";
import { parseMrEnclave, parseRawBuffer } from "../utils.js";
import { Account } from "./account.js";
import {
AttestationPermissionAccount,
AttestationQueueAccount,
@ -27,9 +27,9 @@ import {
export const QUOTE_SEED: string = "QuoteAccountData";
/**
* Parameters for initializing an {@linkcode QuoteAccount}
* Parameters for initializing an {@linkcode EnclaveAccount}
*/
export interface QuoteAccountInitParams {
export interface EnclaveAccountInitParams {
/**
* Key to lookup the buffer data on IPFS or an alternative decentralized storage solution.
*/
@ -55,7 +55,7 @@ export interface QuoteAccountInitParams {
/**
* Parameters for an {@linkcode types.quoteHeartbeat} instruction.
*/
export interface QuoteHeartbeatSyncParams {
export interface EnclaveHeartbeatSyncParams {
gcOracle: PublicKey;
attestationQueue: PublicKey;
permission: [AttestationPermissionAccount, number];
@ -65,17 +65,17 @@ export interface QuoteHeartbeatSyncParams {
/**
* Parameters for an {@linkcode types.quoteHeartbeat} instruction.
*/
export type QuoteHeartbeatParams = Partial<QuoteHeartbeatSyncParams> & {
securedSigner: Keypair;
export type EnclaveHeartbeatParams = Partial<EnclaveHeartbeatSyncParams> & {
enclaveSigner: Keypair;
} & Partial<{
quote: types.QuoteAccountData;
quote: types.EnclaveAccountData;
queue: types.AttestationQueueAccountData;
}>;
/**
* Parameters for an {@linkcode types.quoteVerify} instruction.
*/
export interface QuoteVerifyParams {
export interface EnclaveVerifyParams {
/**
* @TODO: Docs for timestamp
*/
@ -95,50 +95,50 @@ export interface QuoteVerifyParams {
/**
* Parameters for an {@linkcode types.quoteRotate} instruction.
*/
export interface QuoteRotateParams {
export interface EnclaveRotateParams {
authority?: Keypair;
securedSigner: Keypair;
enclaveSigner: Keypair;
registryKey: string | Buffer | Uint8Array;
}
/**
* Account type representing a Switchboard Attestation quote.
*
* Data: {@linkcode types.QuoteAccountData}
* Data: {@linkcode types.EnclaveAccountData}
*/
export class QuoteAccount extends Account<types.QuoteAccountData> {
static accountName = "QuoteAccountData";
export class EnclaveAccount extends Account<types.EnclaveAccountData> {
static accountName = "EnclaveAccountData";
/**
* Load an existing {@linkcode QuoteAccount} with its current on-chain state
* Load an existing {@linkcode EnclaveAccount} with its current on-chain state
*/
public static async load(
program: SwitchboardProgram,
address: PublicKey | string
): Promise<[QuoteAccount, types.QuoteAccountData]> {
): Promise<[EnclaveAccount, types.EnclaveAccountData]> {
program.verifyAttestation();
const quoteAccount = new QuoteAccount(program, address);
const state = await quoteAccount.loadData();
return [quoteAccount, state];
const enclaveAccount = new EnclaveAccount(program, address);
const state = await enclaveAccount.loadData();
return [enclaveAccount, state];
}
/**
* Finds the {@linkcode QuoteAccount} from the seed from which it was generated.
* Finds the {@linkcode EnclaveAccount} from the seed from which it was generated.
*
* Only applicable for QuoteAccounts tied to a {@linkcode FunctionAccount}. Quotes can also be generated from a keypair.
* Only applicable for EnclaveAccounts tied to a {@linkcode FunctionAccount}. Enclaves can also be generated from a keypair.
*
* @return QuoteAccount and PDA bump tuple.
* @return EnclaveAccount and PDA bump tuple.
*/
public static fromSeed(
program: SwitchboardProgram,
functionPubkey: PublicKey
): [QuoteAccount, number] {
): [EnclaveAccount, number] {
const [publicKey, bump] = PublicKey.findProgramAddressSync(
[Buffer.from(QUOTE_SEED), functionPubkey.toBytes()],
program.attestationProgramId
);
return [new QuoteAccount(program, publicKey), bump];
return [new EnclaveAccount(program, publicKey), bump];
}
/**
@ -147,9 +147,9 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
public static async createInstruction(
program: SwitchboardProgram,
payer: PublicKey,
params: QuoteAccountInitParams,
params: EnclaveAccountInitParams,
options?: TransactionObjectOptions
): Promise<[QuoteAccount, TransactionObject]> {
): Promise<[EnclaveAccount, TransactionObject]> {
program.verifyAttestation();
const quoteKeypair = params.keypair ?? Keypair.generate();
@ -174,16 +174,16 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
}
);
return [
new QuoteAccount(program, quoteKeypair.publicKey),
new EnclaveAccount(program, quoteKeypair.publicKey),
new TransactionObject(payer, [instruction], [quoteKeypair], options),
];
}
public static async create(
program: SwitchboardProgram,
params: QuoteAccountInitParams,
params: EnclaveAccountInitParams,
options?: SendTransactionObjectOptions
): Promise<[QuoteAccount, TransactionSignature]> {
): Promise<[EnclaveAccount, TransactionSignature]> {
const [account, txnObject] = await this.createInstruction(
program,
program.walletPubkey,
@ -208,7 +208,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
}
static getVerificationStatus(
state: types.QuoteAccountData
state: types.EnclaveAccountData
): types.VerificationStatusKind {
switch (state.verificationStatus) {
case types.VerificationStatus.None.discriminator:
@ -229,21 +229,22 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
}
/**
* Get the size of an {@linkcode QuoteAccount} on-chain.
* Get the size of an {@linkcode EnclaveAccount} on-chain.
*/
public readonly size = this.program.attestationAccount.quoteAccountData.size;
public readonly size =
this.program.attestationAccount.enclaveAccountData.size;
/**
* Retrieve and decode the {@linkcode types.QuoteAccountData} stored in this account.
* Retrieve and decode the {@linkcode types.EnclaveAccountData} stored in this account.
*/
public async loadData(): Promise<types.QuoteAccountData> {
public async loadData(): Promise<types.EnclaveAccountData> {
this.program.verifyAttestation();
const data = await types.QuoteAccountData.fetch(
const data = await types.EnclaveAccountData.fetch(
this.program,
this.publicKey
);
if (data) return data;
throw new errors.AccountNotFoundError("Quote", this.publicKey);
throw new errors.AccountNotFoundError("Enclave", this.publicKey);
}
public heartbeatInstruction(params: {
@ -251,7 +252,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
attestationQueue: PublicKey;
permission: [AttestationPermissionAccount, number];
queueAuthority: PublicKey;
securedSigner: PublicKey;
enclaveSigner: PublicKey;
}): TransactionInstruction {
this.program.verifyAttestation();
@ -261,7 +262,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
{ params: {} },
{
quote: this.publicKey,
securedSigner: params.securedSigner,
enclaveSigner: params.enclaveSigner,
attestationQueue: params.attestationQueue,
queueAuthority: params.queueAuthority,
gcNode: params.gcOracle,
@ -272,7 +273,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
}
public async heartbeat(
params: QuoteHeartbeatParams,
params: EnclaveHeartbeatParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
const quote = params.quote ?? (await this.loadData());
@ -301,13 +302,13 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
),
gcOracle: lastPubkey,
attestationQueue: quote.attestationQueue,
securedSigner: params.securedSigner.publicKey,
enclaveSigner: params.enclaveSigner.publicKey,
});
const heartbeatTxn = new TransactionObject(
this.program.walletPubkey,
[heartbeatIxn],
[params.securedSigner],
[params.enclaveSigner],
options
);
@ -317,7 +318,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
public async rotateInstruction(
payer: PublicKey,
params: QuoteRotateParams,
params: EnclaveRotateParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
@ -339,7 +340,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
{
quote: this.publicKey,
authority: authority,
securedSigner: params.securedSigner.publicKey,
enclaveSigner: params.enclaveSigner.publicKey,
attestationQueue: quoteData.attestationQueue,
}
);
@ -348,15 +349,15 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
payer,
[rotateIxn],
params.authority
? [params.authority, params.securedSigner]
: [params.securedSigner],
? [params.authority, params.enclaveSigner]
: [params.enclaveSigner],
options
);
return rotateTxn;
}
public async rotate(
params: QuoteRotateParams,
params: EnclaveRotateParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.rotateInstruction(
@ -368,7 +369,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
public async verifyInstruction(
payer: PublicKey,
params: QuoteVerifyParams,
params: EnclaveVerifyParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
@ -398,8 +399,8 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
},
{
quote: this.publicKey,
quoteSigner: quoteData.securedSigner,
securedSigner: params.verifierSecuredSigner.publicKey,
quoteSigner: quoteData.enclaveSigner,
enclaveSigner: params.verifierSecuredSigner.publicKey,
verifier: params.verifier,
attestationQueue: quoteData.attestationQueue,
}
@ -413,7 +414,7 @@ export class QuoteAccount extends Account<types.QuoteAccountData> {
}
public async verify(
params: QuoteVerifyParams,
params: EnclaveVerifyParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.verifyInstruction(

View File

@ -16,7 +16,9 @@ import { parseCronSchedule, parseMrEnclave } from "../utils.js";
import {
AttestationPermissionAccount,
AttestationQueueAccount,
QuoteAccount,
EnclaveAccount,
FunctionRequestAccount,
FunctionRequestAccountInitParams,
} from "./index.js";
import * as anchor from "@coral-xyz/anchor";
@ -128,8 +130,8 @@ export interface FunctionVerifyParams {
nextAllowedTimestamp: anchor.BN;
isFailure: boolean;
mrEnclave: Uint8Array;
verifier: QuoteAccount;
fnSigner: PublicKey;
verifier: EnclaveAccount;
functionEnclaveSigner: PublicKey;
}
/**
@ -140,6 +142,11 @@ export interface FunctionTriggerParams {
authority?: Keypair;
}
export type CreateFunctionRequestParams = Omit<
FunctionRequestAccountInitParams,
"functionAccount"
> & { user?: Keypair };
/**
/**
@ -230,11 +237,8 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
program,
functionKeypair.publicKey
);
const [permissionAccount] = functionAccount.getPermissionAccount(
attestationQueueAccount.publicKey,
attestationQueue.authority
);
const [quoteAccount] = functionAccount.getQuoteAccount();
const [enclaveAccount] = functionAccount.getEnclaveAccount();
const escrow = functionAccount.getEscrow();
const instruction = types.functionInit(
@ -243,23 +247,26 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
params: {
name: new Uint8Array(Buffer.from(params.name ?? "", "utf8")),
metadata: new Uint8Array(Buffer.from(params.metadata ?? "", "utf8")),
schedule: new Uint8Array(Buffer.from(cronSchedule, "utf8")),
container: new Uint8Array(Buffer.from(params.container, "utf8")),
version: new Uint8Array(Buffer.from(params.version, "utf8")),
containerRegistry: new Uint8Array(
Buffer.from(params.containerRegistry ?? "", "utf8")
),
version: new Uint8Array(Buffer.from(params.version, "utf8")),
schedule: new Uint8Array(Buffer.from(cronSchedule, "utf8")),
mrEnclave: Array.from(parseMrEnclave(params.mrEnclave)),
recentSlot: recentSlot,
requestsDisabled: false,
requestsRequireAuthorization: false,
requestsDefaultSlotsUntilExpiration: new BN(1000),
requestsFee: new BN(0),
},
},
{
function: functionAccount.publicKey,
addressLookupTable: addressLookupTable,
authority: authority,
quote: quoteAccount.publicKey,
quote: enclaveAccount.publicKey,
attestationQueue: attestationQueueAccount.publicKey,
permission: permissionAccount.publicKey,
escrow,
state: program.attestationProgramState.publicKey,
mint: program.mint.address,
@ -298,26 +305,47 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
return [account, txSignature];
}
public getPermissionAccount(
queuePubkey: PublicKey,
queueAuthority: PublicKey
): [AttestationPermissionAccount, number] {
return AttestationPermissionAccount.fromSeed(
this.program,
queueAuthority,
queuePubkey,
this.publicKey
);
}
public getQuoteAccount(): [QuoteAccount, number] {
return QuoteAccount.fromSeed(this.program, this.publicKey);
public getEnclaveAccount(): [EnclaveAccount, number] {
return EnclaveAccount.fromSeed(this.program, this.publicKey);
}
public getEscrow(): PublicKey {
return this.program.mint.getAssociatedAddress(this.publicKey);
}
public async createRequestInstruction(
payer: PublicKey,
params: CreateFunctionRequestParams,
options?: TransactionObjectOptions
): Promise<[FunctionRequestAccount, TransactionObject]> {
// const functionState = await this.loadData();
const [requestAccount, txnObject] =
await FunctionRequestAccount.createInstruction(
this.program,
payer,
{
...params,
functionAccount: this,
},
options
);
return [requestAccount, txnObject];
}
public async createRequest(
params: CreateFunctionRequestParams,
options?: SendTransactionObjectOptions
): Promise<[FunctionRequestAccount, TransactionSignature]> {
const [account, txnObject] = await this.createRequestInstruction(
this.program.walletPubkey,
params,
options
);
const txSignature = await this.program.signAndSend(txnObject, options);
return [account, txSignature];
}
public async setConfigInstruction(
payer: PublicKey,
params: FunctionSetConfigParams,
@ -352,10 +380,16 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
containerRegistry: toOptionalBytes(params.containerRegistry),
version: toOptionalBytes(params.version),
schedule: toOptionalBytes(params.schedule),
mrEnclaves: [],
requestsDisabled: false,
requestsRequireAuthorization: false,
requestsDefaultSlotsUntilExpiration: new BN(1000),
requestsFee: new BN(0),
},
},
{
function: this.publicKey,
quote: this.getEnclaveAccount()[0].publicKey,
authority: functionData.authority,
}
);
@ -363,7 +397,8 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
return new TransactionObject(
payer,
[setConfigIxn],
params?.authority ? [params.authority] : []
params?.authority ? [params.authority] : [],
options
);
}
@ -583,12 +618,7 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
);
const attestationQueue = await attestationQueueAccount.loadData();
const fnPermissionAccount = this.getPermissionAccount(
attestationQueueAccount.publicKey,
attestationQueue.authority
)[0];
const fnQuoteAccount = this.getQuoteAccount()[0];
const fnEnclaveAccount = this.getEnclaveAccount()[0];
const verifierPermissionAccount = AttestationPermissionAccount.fromSeed(
this.program,
@ -618,19 +648,16 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
},
{
function: this.publicKey,
fnSigner: params.fnSigner,
fnQuote: fnQuoteAccount.publicKey,
functionEnclaveSigner: params.functionEnclaveSigner,
fnQuote: fnEnclaveAccount.publicKey,
verifierQuote: params.verifier.publicKey,
attestationQueue: functionData.attestationQueue,
escrow: this.getEscrow(),
receiver: receiver,
verifierPermission: verifierPermissionAccount.publicKey,
fnPermission: fnPermissionAccount.publicKey,
state: this.program.attestationProgramState.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
payer,
systemProgram: SystemProgram.programId,
securedSigner: PublicKey.default, // TODO: update with correct account
verifierEnclaveSigner: PublicKey.default, // TODO: update with correct account
}
);
return new TransactionObject(payer, [instruction], [], options);
@ -674,6 +701,7 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
{
function: this.publicKey,
authority: functionData.authority,
attestationQueue: functionData.attestationQueue,
}
);
@ -697,7 +725,7 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
public static decodeAddressLookup(lookupTable: AddressLookupTableAccount) {
const addresses = lookupTable.state.addresses;
if (addresses.length !== 16) {
if (addresses.length !== 15) {
throw new Error(`Failed to decode address lookup table`);
}
@ -761,9 +789,8 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
const statePubkey = addresses[10]!;
const attestationQueuePubkey = addresses[11]!;
const functionPubkey = addresses[12]!;
const escrowPubkey = addresses[13]!;
const fnPermission = addresses[14]!;
const fnQuote = addresses[15]!;
const fnQuote = addresses[13]!;
const escrowPubkey = addresses[14]!;
return {
systemProgram,
@ -779,9 +806,8 @@ export class FunctionAccount extends Account<types.FunctionAccountData> {
statePubkey,
attestationQueuePubkey,
functionPubkey,
escrowPubkey,
fnPermission,
fnQuote,
escrowPubkey,
};
}
}

View File

@ -0,0 +1,343 @@
import { Account } from "../accounts/account.js";
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
TransactionObject,
TransactionObjectOptions,
} from "../TransactionObject.js";
import { RawBuffer } from "../types.js";
import { parseMrEnclave } from "../utils.js";
import { FunctionAccount } from "./index.js";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import {
Keypair,
PublicKey,
SystemProgram,
TransactionInstruction,
TransactionSignature,
} from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common";
/**
* Parameters for initializing a {@linkcode FunctionRequestAccount}
*/
export interface FunctionRequestAccountInitParams {
functionAccount: FunctionAccount;
maxContainerParamsLen?: number;
containerParams?: Buffer;
garbageCollectionSlot?: number;
/**
* A keypair to be used to address this account.
*
* @default Keypair.generate()
*/
keypair?: Keypair;
authority?: PublicKey;
}
/**
* Parameters for setting a {@linkcode FunctionRequestAccount} config
*/
export interface FunctionRequestSetConfigParams {
containerParams: Buffer;
appendContainerParams?: boolean;
authority?: Keypair;
}
/**
* Parameters for triggering a {@linkcode FunctionRequestAccount} config
*/
export interface FunctionRequestTriggerParams {
bounty?: number | BN;
slotsUntilExpiration?: BN;
authority?: Keypair;
}
export interface FunctionRequestVerifyParams {
observedTime?: number;
isFailure?: boolean;
mrEnclave: RawBuffer;
requestSlot: number | BN;
containerParamsHash: RawBuffer;
// accounts
functionEnclaveSigner: PublicKey;
function: PublicKey;
verifierQuote: PublicKey;
verifierEnclaveSigner: PublicKey;
verifierPermission: PublicKey;
attestationQueue: PublicKey;
receiver: PublicKey;
}
/**
* Account type representing a Switchboard Function.
*
* Data: {@linkcode types.FunctionRequestAccountData}
*/
export class FunctionRequestAccount extends Account<types.FunctionRequestAccountData> {
static accountName = "FunctionRequestAccountData";
/**
* Get the size of an {@linkcode FunctionRequestAccount} on-chain.
*/
public readonly size =
this.program.attestationAccount.functionAccountData.size;
/**
* Retrieve and decode the {@linkcode types.FunctionRequestAccountData} stored in this account.
*/
public async loadData(): Promise<types.FunctionRequestAccountData> {
const data = await types.FunctionRequestAccountData.fetch(
this.program,
this.publicKey
);
if (data) return data;
throw new errors.AccountNotFoundError("Function", this.publicKey);
}
public static async load(
program: SwitchboardProgram,
address: PublicKey | string
): Promise<[FunctionRequestAccount, types.FunctionRequestAccountData]> {
program.verifyAttestation();
const functionAccount = new FunctionRequestAccount(program, address);
const state = await functionAccount.loadData();
return [functionAccount, state];
}
public static async createInstruction(
program: SwitchboardProgram,
payer: PublicKey,
params: FunctionRequestAccountInitParams,
options?: TransactionObjectOptions
): Promise<[FunctionRequestAccount, TransactionObject]> {
// TODO: Calculate the max size of data we can support up front then split into multiple txns
program.verifyAttestation();
// TODO: Add way to make this a PDA
const requestKeypair = params.keypair ?? Keypair.generate();
program.verifyNewKeypair(requestKeypair);
const escrow = program.mint.getAssociatedAddress(requestKeypair.publicKey);
const functionState = await params.functionAccount.loadData();
const instruction = types.functionRequestInit(
program,
{
params: {
maxContainerParamsLen: null,
containerParams: new Uint8Array(
params.containerParams ?? Buffer.from("")
),
garbageCollectionSlot: params.garbageCollectionSlot
? new BN(params.garbageCollectionSlot)
: null,
},
},
{
request: requestKeypair.publicKey,
function: params.functionAccount.publicKey,
functionAuthority: functionState.authority,
attestationQueue: functionState.attestationQueue,
escrow,
mint: program.mint.address,
state: program.attestationProgramState.publicKey,
payer,
authority: params.authority ?? payer,
systemProgram: SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
}
);
return [
new FunctionRequestAccount(program, requestKeypair.publicKey),
new TransactionObject(payer, [instruction], [requestKeypair], options),
];
}
public static async create(
program: SwitchboardProgram,
params: FunctionRequestAccountInitParams,
options?: SendTransactionObjectOptions
): Promise<[FunctionRequestAccount, TransactionSignature]> {
const [account, txnObject] = await this.createInstruction(
program,
program.walletPubkey,
params,
options
);
const txSignature = await program.signAndSend(txnObject, options);
return [account, txSignature];
}
public getEscrow(): PublicKey {
return this.program.mint.getAssociatedAddress(this.publicKey);
}
public async getBalance(): Promise<number> {
const balance = await this.program.mint.getAssociatedBalance(
this.publicKey
);
if (balance === null) {
throw new errors.AccountNotFoundError(
`Function escrow`,
this.getEscrow()
);
}
return balance;
}
public async getBalanceBN(): Promise<BN> {
const balance = await this.getBalance();
return this.program.mint.toTokenAmountBN(balance);
}
public async setConfigInstruction(
payer: PublicKey,
params: FunctionRequestSetConfigParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
const requestState = await this.loadData();
const setConfigIxn = types.functionRequestSetConfig(
this.program,
{
params: {
containerParams: new Uint8Array(params.containerParams),
appendContainerParams: params.appendContainerParams ?? false,
},
},
{
request: this.publicKey,
authority: requestState.authority,
}
);
return new TransactionObject(
payer,
[setConfigIxn],
params?.authority ? [params.authority] : []
);
}
public async setConfig(
params?: FunctionRequestSetConfigParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.setConfigInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public async triggerInstruction(
payer: PublicKey,
params?: FunctionRequestTriggerParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
const requestState = await this.loadData();
const functionAccount = new FunctionAccount(
this.program,
requestState.function
);
const functionState = await functionAccount.loadData();
const setConfigIxn = types.functionRequestTrigger(
this.program,
{
params: {
bounty: params?.bounty
? typeof params.bounty === "number"
? new BN(params.bounty)
: params.bounty
: null,
slotsUntilExpiration: params?.slotsUntilExpiration ?? null,
},
},
{
request: this.publicKey,
authority: requestState.authority,
escrow: requestState.escrow,
function: requestState.function,
state: this.program.attestationProgramState.publicKey,
attestationQueue: functionState.attestationQueue,
payer,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
}
);
return new TransactionObject(
payer,
[setConfigIxn],
params?.authority ? [params.authority] : [],
options
);
}
public async trigger(
params?: FunctionRequestTriggerParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.triggerInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public verifyIxn(
params: FunctionRequestVerifyParams
): TransactionInstruction {
const ixn = types.functionRequestVerify(
this.program,
{
params: {
observedTime: new BN(
params.observedTime
? params.observedTime
: Math.floor(Date.now() / 1000)
),
isFailure: params.isFailure ?? false,
mrEnclave: Array.from(parseMrEnclave(params.mrEnclave)),
requestSlot:
typeof params.requestSlot === "number"
? new BN(params.requestSlot)
: params.requestSlot,
containerParamsHash: Array.from(
parseMrEnclave(params.containerParamsHash)
),
},
},
{
request: this.publicKey,
functionEnclaveSigner: params.functionEnclaveSigner,
escrow: this.program.mint.getAssociatedAddress(this.publicKey),
function: params.function,
functionEscrow: this.program.mint.getAssociatedAddress(params.function),
verifierQuote: params.verifierQuote,
verifierEnclaveSigner: params.verifierEnclaveSigner,
verifierPermission: params.verifierPermission,
state: this.program.attestationProgramState.publicKey,
attestationQueue: params.attestationQueue,
receiver: params.receiver,
tokenProgram: TOKEN_PROGRAM_ID,
}
);
return ixn;
}
}

View File

@ -7,7 +7,9 @@ export * from "./attestationQueueAccount.js";
export * from "./bufferRelayAccount.js";
export * from "./crankAccount.js";
export * from "./crankDataBuffer.js";
export * from "./enclaveAccount.js";
export * from "./functionAccount.js";
export * from "./functionRequestAccount.js";
export * from "./jobAccount.js";
export * from "./leaseAccount.js";
export * from "./oracleAccount.js";
@ -15,7 +17,6 @@ export * from "./permissionAccount.js";
export * from "./programStateAccount.js";
export * from "./queueAccount.js";
export * from "./queueDataBuffer.js";
export * from "./quoteAccount.js";
export * from "./vrfAccount.js";
export * from "./vrfLiteAccount.js";
export * from "./vrfPoolAccount.js";

View File

@ -5,22 +5,22 @@ import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-es
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface StateFields {
export interface AttestationProgramStateFields {
bump: number;
ebuf: Array<number>;
}
export interface StateJSON {
export interface AttestationProgramStateJSON {
bump: number;
ebuf: Array<number>;
}
export class State {
export class AttestationProgramState {
readonly bump: number;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
216, 146, 107, 94, 104, 75, 182, 177,
42, 145, 190, 11, 203, 77, 146, 231,
]);
static readonly layout = borsh.struct([
@ -28,7 +28,7 @@ export class State {
borsh.array(borsh.u8(), 2048, "ebuf"),
]);
constructor(fields: StateFields) {
constructor(fields: AttestationProgramStateFields) {
this.bump = fields.bump;
this.ebuf = fields.ebuf;
}
@ -36,7 +36,7 @@ export class State {
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<State | null> {
): Promise<AttestationProgramState | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
@ -52,7 +52,7 @@ export class State {
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<State | null>> {
): Promise<Array<AttestationProgramState | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
@ -67,28 +67,28 @@ export class State {
});
}
static decode(data: Buffer): State {
if (!data.slice(0, 8).equals(State.discriminator)) {
static decode(data: Buffer): AttestationProgramState {
if (!data.slice(0, 8).equals(AttestationProgramState.discriminator)) {
throw new Error("invalid account discriminator");
}
const dec = State.layout.decode(data.slice(8));
const dec = AttestationProgramState.layout.decode(data.slice(8));
return new State({
return new AttestationProgramState({
bump: dec.bump,
ebuf: dec.ebuf,
});
}
toJSON(): StateJSON {
toJSON(): AttestationProgramStateJSON {
return {
bump: this.bump,
ebuf: this.ebuf,
};
}
static fromJSON(obj: StateJSON): State {
return new State({
static fromJSON(obj: AttestationProgramStateJSON): AttestationProgramState {
return new AttestationProgramState({
bump: obj.bump,
ebuf: obj.ebuf,
});

View File

@ -6,56 +6,116 @@ import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface AttestationQueueAccountDataFields {
/** The address of the authority which is permitted to add/remove allowed enclave measurements. */
authority: PublicKey;
/** Allowed enclave measurements. */
mrEnclaves: Array<Array<number>>;
/** The number of allowed enclave measurements. */
mrEnclavesLen: number;
/**
* The addresses of the quote verifiers who have a valid
* verification status and have heartbeated on-chain recently.
*/
data: Array<PublicKey>;
/** The length of valid quote verifiers for the given attestation queue. */
dataLen: number;
/** Allow authority to force add a node after X seconds with no heartbeat. */
allowAuthorityOverrideAfter: BN;
/**
* Even if a heartbeating machine quote verifies with proper measurement,
* require authority signoff.
*/
requireAuthorityHeartbeatPermission: boolean;
/** Require FunctionAccounts to have PermitQueueUsage before they are executed. */
requireUsagePermissions: boolean;
/** The maximum allowable time until a EnclaveAccount needs to be re-verified on-chain. */
maxQuoteVerificationAge: BN;
/** The reward paid to quote verifiers for attesting on-chain. */
reward: number;
/** The unix timestamp when the last quote verifier heartbeated on-chain. */
lastHeartbeat: BN;
nodeTimeout: BN;
/** Incrementer used to track the current quote verifier permitted to run any available functions. */
currIdx: number;
/** Incrementer used to garbage collect and remove stale quote verifiers. */
gcIdx: number;
/** Reserved. */
ebuf: Array<number>;
}
export interface AttestationQueueAccountDataJSON {
/** The address of the authority which is permitted to add/remove allowed enclave measurements. */
authority: string;
/** Allowed enclave measurements. */
mrEnclaves: Array<Array<number>>;
/** The number of allowed enclave measurements. */
mrEnclavesLen: number;
/**
* The addresses of the quote verifiers who have a valid
* verification status and have heartbeated on-chain recently.
*/
data: Array<string>;
/** The length of valid quote verifiers for the given attestation queue. */
dataLen: number;
/** Allow authority to force add a node after X seconds with no heartbeat. */
allowAuthorityOverrideAfter: string;
/**
* Even if a heartbeating machine quote verifies with proper measurement,
* require authority signoff.
*/
requireAuthorityHeartbeatPermission: boolean;
/** Require FunctionAccounts to have PermitQueueUsage before they are executed. */
requireUsagePermissions: boolean;
/** The maximum allowable time until a EnclaveAccount needs to be re-verified on-chain. */
maxQuoteVerificationAge: string;
/** The reward paid to quote verifiers for attesting on-chain. */
reward: number;
/** The unix timestamp when the last quote verifier heartbeated on-chain. */
lastHeartbeat: string;
nodeTimeout: string;
/** Incrementer used to track the current quote verifier permitted to run any available functions. */
currIdx: number;
/** Incrementer used to garbage collect and remove stale quote verifiers. */
gcIdx: number;
/** Reserved. */
ebuf: Array<number>;
}
export class AttestationQueueAccountData {
/** The address of the authority which is permitted to add/remove allowed enclave measurements. */
readonly authority: PublicKey;
/** Allowed enclave measurements. */
readonly mrEnclaves: Array<Array<number>>;
/** The number of allowed enclave measurements. */
readonly mrEnclavesLen: number;
/**
* The addresses of the quote verifiers who have a valid
* verification status and have heartbeated on-chain recently.
*/
readonly data: Array<PublicKey>;
/** The length of valid quote verifiers for the given attestation queue. */
readonly dataLen: number;
/** Allow authority to force add a node after X seconds with no heartbeat. */
readonly allowAuthorityOverrideAfter: BN;
/**
* Even if a heartbeating machine quote verifies with proper measurement,
* require authority signoff.
*/
readonly requireAuthorityHeartbeatPermission: boolean;
/** Require FunctionAccounts to have PermitQueueUsage before they are executed. */
readonly requireUsagePermissions: boolean;
/** The maximum allowable time until a EnclaveAccount needs to be re-verified on-chain. */
readonly maxQuoteVerificationAge: BN;
/** The reward paid to quote verifiers for attesting on-chain. */
readonly reward: number;
/** The unix timestamp when the last quote verifier heartbeated on-chain. */
readonly lastHeartbeat: BN;
readonly nodeTimeout: BN;
/** Incrementer used to track the current quote verifier permitted to run any available functions. */
readonly currIdx: number;
/** Incrementer used to garbage collect and remove stale quote verifiers. */
readonly gcIdx: number;
/** Reserved. */
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([

View File

@ -5,113 +5,140 @@ import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-es
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface QuoteAccountDataFields {
securedSigner: PublicKey;
bump: number;
/** TODO: Add description */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
export interface EnclaveAccountDataFields {
/** The address of the signer generated within an enclave. */
enclaveSigner: PublicKey;
/** The authority of the EnclaveAccount which is permitted to make account changes. */
authority: PublicKey;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
attestationQueue: PublicKey;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
mrEnclave: Array<number>;
/** The VerificationStatus of the quote. */
verificationStatus: number;
/** The unix timestamp when the quote was last verified. */
verificationTimestamp: BN;
/** The unix timestamp when the quotes verification status expires. */
validUntil: BN;
isOnQueue: boolean;
/** The last time the quote heartbeated. */
lastHeartbeat: BN;
authority: PublicKey;
/** The unix timestamp when the quote was created. */
createdAt: BN;
ebuf: Array<number>;
}
export interface QuoteAccountDataJSON {
securedSigner: string;
bump: number;
/** TODO: Add description */
/** The off-chain registry where the verifiers quote can be located. */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
/** Whether the quote is located on the AttestationQueues buffer. */
isOnQueue: boolean;
/** The last time the quote heartbeated on-chain. */
lastHeartbeat: BN;
/** The PDA bump. Only set for FunctionAccount quotes. */
bump: number;
/** Reserved. */
ebuf: Array<number>;
}
export interface EnclaveAccountDataJSON {
/** The address of the signer generated within an enclave. */
enclaveSigner: string;
/** The authority of the EnclaveAccount which is permitted to make account changes. */
authority: string;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
attestationQueue: string;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
mrEnclave: Array<number>;
/** The VerificationStatus of the quote. */
verificationStatus: number;
/** The unix timestamp when the quote was last verified. */
verificationTimestamp: string;
/** The unix timestamp when the quotes verification status expires. */
validUntil: string;
isOnQueue: boolean;
/** The last time the quote heartbeated. */
lastHeartbeat: string;
authority: string;
/** The unix timestamp when the quote was created. */
createdAt: string;
/** The off-chain registry where the verifiers quote can be located. */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
/** Whether the quote is located on the AttestationQueues buffer. */
isOnQueue: boolean;
/** The last time the quote heartbeated on-chain. */
lastHeartbeat: string;
/** The PDA bump. Only set for FunctionAccount quotes. */
bump: number;
/** Reserved. */
ebuf: Array<number>;
}
export class QuoteAccountData {
readonly securedSigner: PublicKey;
readonly bump: number;
/** TODO: Add description */
readonly quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
readonly registryKey: Array<number>;
export class EnclaveAccountData {
/** The address of the signer generated within an enclave. */
readonly enclaveSigner: PublicKey;
/** The authority of the EnclaveAccount which is permitted to make account changes. */
readonly authority: PublicKey;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
readonly attestationQueue: PublicKey;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
readonly mrEnclave: Array<number>;
/** The VerificationStatus of the quote. */
readonly verificationStatus: number;
/** The unix timestamp when the quote was last verified. */
readonly verificationTimestamp: BN;
/** The unix timestamp when the quotes verification status expires. */
readonly validUntil: BN;
readonly isOnQueue: boolean;
/** The last time the quote heartbeated. */
readonly lastHeartbeat: BN;
readonly authority: PublicKey;
/** The unix timestamp when the quote was created. */
readonly createdAt: BN;
/** The off-chain registry where the verifiers quote can be located. */
readonly quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
readonly registryKey: Array<number>;
/** Whether the quote is located on the AttestationQueues buffer. */
readonly isOnQueue: boolean;
/** The last time the quote heartbeated on-chain. */
readonly lastHeartbeat: BN;
/** The PDA bump. Only set for FunctionAccount quotes. */
readonly bump: number;
/** Reserved. */
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
205, 205, 167, 232, 0, 74, 44, 160,
90, 162, 39, 88, 77, 157, 156, 165,
]);
static readonly layout = borsh.struct([
borsh.publicKey("securedSigner"),
borsh.u8("bump"),
borsh.array(borsh.u8(), 32, "quoteRegistry"),
borsh.array(borsh.u8(), 64, "registryKey"),
borsh.publicKey("enclaveSigner"),
borsh.publicKey("authority"),
borsh.publicKey("attestationQueue"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
borsh.u8("verificationStatus"),
borsh.i64("verificationTimestamp"),
borsh.i64("validUntil"),
borsh.i64("createdAt"),
borsh.array(borsh.u8(), 32, "quoteRegistry"),
borsh.array(borsh.u8(), 64, "registryKey"),
borsh.bool("isOnQueue"),
borsh.i64("lastHeartbeat"),
borsh.publicKey("authority"),
borsh.i64("createdAt"),
borsh.array(borsh.u8(), 992, "ebuf"),
borsh.u8("bump"),
borsh.array(borsh.u8(), 1024, "ebuf"),
]);
constructor(fields: QuoteAccountDataFields) {
this.securedSigner = fields.securedSigner;
this.bump = fields.bump;
this.quoteRegistry = fields.quoteRegistry;
this.registryKey = fields.registryKey;
constructor(fields: EnclaveAccountDataFields) {
this.enclaveSigner = fields.enclaveSigner;
this.authority = fields.authority;
this.attestationQueue = fields.attestationQueue;
this.mrEnclave = fields.mrEnclave;
this.verificationStatus = fields.verificationStatus;
this.verificationTimestamp = fields.verificationTimestamp;
this.validUntil = fields.validUntil;
this.createdAt = fields.createdAt;
this.quoteRegistry = fields.quoteRegistry;
this.registryKey = fields.registryKey;
this.isOnQueue = fields.isOnQueue;
this.lastHeartbeat = fields.lastHeartbeat;
this.authority = fields.authority;
this.createdAt = fields.createdAt;
this.bump = fields.bump;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<QuoteAccountData | null> {
): Promise<EnclaveAccountData | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
@ -127,7 +154,7 @@ export class QuoteAccountData {
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<QuoteAccountData | null>> {
): Promise<Array<EnclaveAccountData | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
@ -142,65 +169,65 @@ export class QuoteAccountData {
});
}
static decode(data: Buffer): QuoteAccountData {
if (!data.slice(0, 8).equals(QuoteAccountData.discriminator)) {
static decode(data: Buffer): EnclaveAccountData {
if (!data.slice(0, 8).equals(EnclaveAccountData.discriminator)) {
throw new Error("invalid account discriminator");
}
const dec = QuoteAccountData.layout.decode(data.slice(8));
const dec = EnclaveAccountData.layout.decode(data.slice(8));
return new QuoteAccountData({
securedSigner: dec.securedSigner,
bump: dec.bump,
quoteRegistry: dec.quoteRegistry,
registryKey: dec.registryKey,
return new EnclaveAccountData({
enclaveSigner: dec.enclaveSigner,
authority: dec.authority,
attestationQueue: dec.attestationQueue,
mrEnclave: dec.mrEnclave,
verificationStatus: dec.verificationStatus,
verificationTimestamp: dec.verificationTimestamp,
validUntil: dec.validUntil,
createdAt: dec.createdAt,
quoteRegistry: dec.quoteRegistry,
registryKey: dec.registryKey,
isOnQueue: dec.isOnQueue,
lastHeartbeat: dec.lastHeartbeat,
authority: dec.authority,
createdAt: dec.createdAt,
bump: dec.bump,
ebuf: dec.ebuf,
});
}
toJSON(): QuoteAccountDataJSON {
toJSON(): EnclaveAccountDataJSON {
return {
securedSigner: this.securedSigner.toString(),
bump: this.bump,
quoteRegistry: this.quoteRegistry,
registryKey: this.registryKey,
enclaveSigner: this.enclaveSigner.toString(),
authority: this.authority.toString(),
attestationQueue: this.attestationQueue.toString(),
mrEnclave: this.mrEnclave,
verificationStatus: this.verificationStatus,
verificationTimestamp: this.verificationTimestamp.toString(),
validUntil: this.validUntil.toString(),
createdAt: this.createdAt.toString(),
quoteRegistry: this.quoteRegistry,
registryKey: this.registryKey,
isOnQueue: this.isOnQueue,
lastHeartbeat: this.lastHeartbeat.toString(),
authority: this.authority.toString(),
createdAt: this.createdAt.toString(),
bump: this.bump,
ebuf: this.ebuf,
};
}
static fromJSON(obj: QuoteAccountDataJSON): QuoteAccountData {
return new QuoteAccountData({
securedSigner: new PublicKey(obj.securedSigner),
bump: obj.bump,
quoteRegistry: obj.quoteRegistry,
registryKey: obj.registryKey,
static fromJSON(obj: EnclaveAccountDataJSON): EnclaveAccountData {
return new EnclaveAccountData({
enclaveSigner: new PublicKey(obj.enclaveSigner),
authority: new PublicKey(obj.authority),
attestationQueue: new PublicKey(obj.attestationQueue),
mrEnclave: obj.mrEnclave,
verificationStatus: obj.verificationStatus,
verificationTimestamp: new BN(obj.verificationTimestamp),
validUntil: new BN(obj.validUntil),
createdAt: new BN(obj.createdAt),
quoteRegistry: obj.quoteRegistry,
registryKey: obj.registryKey,
isOnQueue: obj.isOnQueue,
lastHeartbeat: new BN(obj.lastHeartbeat),
authority: new PublicKey(obj.authority),
createdAt: new BN(obj.createdAt),
bump: obj.bump,
ebuf: obj.ebuf,
});
}

View File

@ -6,68 +6,194 @@ import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionAccountDataFields {
name: Array<number>;
metadata: Array<number>;
authority: PublicKey;
/** */
containerRegistry: Array<number>;
container: Array<number>;
version: Array<number>;
/** */
attestationQueue: PublicKey;
queueIdx: number;
lastExecutionTimestamp: BN;
nextAllowedTimestamp: BN;
schedule: Array<number>;
escrow: PublicKey;
/** Whether the function is invoked on a schedule or by request */
isScheduled: number;
/** Whether the function has been manually triggered with the function_trigger instruction */
isTriggered: number;
/** The function permissions granted by the attestation_queue.authority */
permissions: number;
status: types.FunctionStatusKind;
/** The name of the function for easier identification. */
name: Array<number>;
/** The metadata of the function for easier identification. */
metadata: Array<number>;
/** The unix timestamp when the function was created. */
createdAt: BN;
isTriggered: boolean;
/** The unix timestamp when the function config (container, registry, version, or schedule) was changed. */
updatedAt: BN;
/** The off-chain registry to fetch the function container from. */
containerRegistry: Array<number>;
/** The identifier of the container in the given container_registry. */
container: Array<number>;
/** The version tag of the container to pull. */
version: Array<number>;
/** The authority of the function which is authorized to make account changes. */
authority: PublicKey;
/** The wrapped SOL escrow of the function to pay for scheduled requests. */
escrow: PublicKey;
/** The address_lookup_table of the function used to increase the number of accounts we can fit into a function result. */
addressLookupTable: PublicKey;
/** The address of the AttestationQueueAccountData that will be processing function requests and verifying the function measurements. */
attestationQueue: PublicKey;
/** An incrementer used to rotate through an AttestationQueue's verifiers. */
queueIdx: number;
/** The cron schedule to run the function on. */
schedule: Array<number>;
/** The unix timestamp when the function was last run. */
lastExecutionTimestamp: BN;
/** The unix timestamp when the function is allowed to run next. */
nextAllowedTimestamp: BN;
/** The number of times to trigger the function upon the next invocation. */
triggerCount: BN;
/** UNUSED. The unix timestamp when the current permissions expire. */
permissionExpiration: BN;
/** Number of requests created for this function. Used to prevent closing when there are live requests. */
numRequests: BN;
/** Whether custom requests have been disabled for this function. */
requestsDisabled: boolean;
/**
* Whether new requests need to be authorized by the FunctionAccount authority before being initialized.
* Useful if you want to use CPIs to control request account creation.
*/
requestsRequireAuthorization: boolean;
/**
* The number of slots after a request has been verified before allowing a non-authority account to close the account.
* Useful if you want to submit multiple txns in your custom function and need the account to be kept alive for multiple slots.
*/
requestsDefaultSlotsUntilExpiration: BN;
/** The lamports paid to the FunctionAccount escrow on each successful update request. */
requestsFee: BN;
/** An array of permitted mr_enclave measurements for the function. */
mrEnclaves: Array<Array<number>>;
/** Reserved. */
ebuf: Array<number>;
}
export interface FunctionAccountDataJSON {
name: Array<number>;
metadata: Array<number>;
authority: string;
/** */
containerRegistry: Array<number>;
container: Array<number>;
version: Array<number>;
/** */
attestationQueue: string;
queueIdx: number;
lastExecutionTimestamp: string;
nextAllowedTimestamp: string;
schedule: Array<number>;
escrow: string;
/** Whether the function is invoked on a schedule or by request */
isScheduled: number;
/** Whether the function has been manually triggered with the function_trigger instruction */
isTriggered: number;
/** The function permissions granted by the attestation_queue.authority */
permissions: number;
status: types.FunctionStatusJSON;
/** The name of the function for easier identification. */
name: Array<number>;
/** The metadata of the function for easier identification. */
metadata: Array<number>;
/** The unix timestamp when the function was created. */
createdAt: string;
isTriggered: boolean;
/** The unix timestamp when the function config (container, registry, version, or schedule) was changed. */
updatedAt: string;
/** The off-chain registry to fetch the function container from. */
containerRegistry: Array<number>;
/** The identifier of the container in the given container_registry. */
container: Array<number>;
/** The version tag of the container to pull. */
version: Array<number>;
/** The authority of the function which is authorized to make account changes. */
authority: string;
/** The wrapped SOL escrow of the function to pay for scheduled requests. */
escrow: string;
/** The address_lookup_table of the function used to increase the number of accounts we can fit into a function result. */
addressLookupTable: string;
/** The address of the AttestationQueueAccountData that will be processing function requests and verifying the function measurements. */
attestationQueue: string;
/** An incrementer used to rotate through an AttestationQueue's verifiers. */
queueIdx: number;
/** The cron schedule to run the function on. */
schedule: Array<number>;
/** The unix timestamp when the function was last run. */
lastExecutionTimestamp: string;
/** The unix timestamp when the function is allowed to run next. */
nextAllowedTimestamp: string;
/** The number of times to trigger the function upon the next invocation. */
triggerCount: string;
/** UNUSED. The unix timestamp when the current permissions expire. */
permissionExpiration: string;
/** Number of requests created for this function. Used to prevent closing when there are live requests. */
numRequests: string;
/** Whether custom requests have been disabled for this function. */
requestsDisabled: boolean;
/**
* Whether new requests need to be authorized by the FunctionAccount authority before being initialized.
* Useful if you want to use CPIs to control request account creation.
*/
requestsRequireAuthorization: boolean;
/**
* The number of slots after a request has been verified before allowing a non-authority account to close the account.
* Useful if you want to submit multiple txns in your custom function and need the account to be kept alive for multiple slots.
*/
requestsDefaultSlotsUntilExpiration: string;
/** The lamports paid to the FunctionAccount escrow on each successful update request. */
requestsFee: string;
/** An array of permitted mr_enclave measurements for the function. */
mrEnclaves: Array<Array<number>>;
/** Reserved. */
ebuf: Array<number>;
}
export class FunctionAccountData {
readonly name: Array<number>;
readonly metadata: Array<number>;
readonly authority: PublicKey;
/** */
readonly containerRegistry: Array<number>;
readonly container: Array<number>;
readonly version: Array<number>;
/** */
readonly attestationQueue: PublicKey;
readonly queueIdx: number;
readonly lastExecutionTimestamp: BN;
readonly nextAllowedTimestamp: BN;
readonly schedule: Array<number>;
readonly escrow: PublicKey;
/** Whether the function is invoked on a schedule or by request */
readonly isScheduled: number;
/** Whether the function has been manually triggered with the function_trigger instruction */
readonly isTriggered: number;
/** The function permissions granted by the attestation_queue.authority */
readonly permissions: number;
readonly status: types.FunctionStatusKind;
/** The name of the function for easier identification. */
readonly name: Array<number>;
/** The metadata of the function for easier identification. */
readonly metadata: Array<number>;
/** The unix timestamp when the function was created. */
readonly createdAt: BN;
readonly isTriggered: boolean;
/** The unix timestamp when the function config (container, registry, version, or schedule) was changed. */
readonly updatedAt: BN;
/** The off-chain registry to fetch the function container from. */
readonly containerRegistry: Array<number>;
/** The identifier of the container in the given container_registry. */
readonly container: Array<number>;
/** The version tag of the container to pull. */
readonly version: Array<number>;
/** The authority of the function which is authorized to make account changes. */
readonly authority: PublicKey;
/** The wrapped SOL escrow of the function to pay for scheduled requests. */
readonly escrow: PublicKey;
/** The address_lookup_table of the function used to increase the number of accounts we can fit into a function result. */
readonly addressLookupTable: PublicKey;
/** The address of the AttestationQueueAccountData that will be processing function requests and verifying the function measurements. */
readonly attestationQueue: PublicKey;
/** An incrementer used to rotate through an AttestationQueue's verifiers. */
readonly queueIdx: number;
/** The cron schedule to run the function on. */
readonly schedule: Array<number>;
/** The unix timestamp when the function was last run. */
readonly lastExecutionTimestamp: BN;
/** The unix timestamp when the function is allowed to run next. */
readonly nextAllowedTimestamp: BN;
/** The number of times to trigger the function upon the next invocation. */
readonly triggerCount: BN;
/** UNUSED. The unix timestamp when the current permissions expire. */
readonly permissionExpiration: BN;
/** Number of requests created for this function. Used to prevent closing when there are live requests. */
readonly numRequests: BN;
/** Whether custom requests have been disabled for this function. */
readonly requestsDisabled: boolean;
/**
* Whether new requests need to be authorized by the FunctionAccount authority before being initialized.
* Useful if you want to use CPIs to control request account creation.
*/
readonly requestsRequireAuthorization: boolean;
/**
* The number of slots after a request has been verified before allowing a non-authority account to close the account.
* Useful if you want to submit multiple txns in your custom function and need the account to be kept alive for multiple slots.
*/
readonly requestsDefaultSlotsUntilExpiration: BN;
/** The lamports paid to the FunctionAccount escrow on each successful update request. */
readonly requestsFee: BN;
/** An array of permitted mr_enclave measurements for the function. */
readonly mrEnclaves: Array<Array<number>>;
/** Reserved. */
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
@ -75,42 +201,65 @@ export class FunctionAccountData {
]);
static readonly layout = borsh.struct([
borsh.u8("isScheduled"),
borsh.u8("isTriggered"),
borsh.u32("permissions"),
types.FunctionStatus.layout("status"),
borsh.array(borsh.u8(), 64, "name"),
borsh.array(borsh.u8(), 256, "metadata"),
borsh.publicKey("authority"),
borsh.i64("createdAt"),
borsh.i64("updatedAt"),
borsh.array(borsh.u8(), 64, "containerRegistry"),
borsh.array(borsh.u8(), 64, "container"),
borsh.array(borsh.u8(), 32, "version"),
borsh.publicKey("authority"),
borsh.publicKey("escrow"),
borsh.publicKey("addressLookupTable"),
borsh.publicKey("attestationQueue"),
borsh.u32("queueIdx"),
borsh.array(borsh.u8(), 64, "schedule"),
borsh.i64("lastExecutionTimestamp"),
borsh.i64("nextAllowedTimestamp"),
borsh.array(borsh.u8(), 64, "schedule"),
borsh.publicKey("escrow"),
types.FunctionStatus.layout("status"),
borsh.i64("createdAt"),
borsh.bool("isTriggered"),
borsh.publicKey("addressLookupTable"),
borsh.array(borsh.u8(), 991, "ebuf"),
borsh.u64("triggerCount"),
borsh.i64("permissionExpiration"),
borsh.u64("numRequests"),
borsh.bool("requestsDisabled"),
borsh.bool("requestsRequireAuthorization"),
borsh.u64("requestsDefaultSlotsUntilExpiration"),
borsh.u64("requestsFee"),
borsh.array(borsh.array(borsh.u8(), 32), 32, "mrEnclaves"),
borsh.array(borsh.u8(), 1024, "ebuf"),
]);
constructor(fields: FunctionAccountDataFields) {
this.isScheduled = fields.isScheduled;
this.isTriggered = fields.isTriggered;
this.permissions = fields.permissions;
this.status = fields.status;
this.name = fields.name;
this.metadata = fields.metadata;
this.authority = fields.authority;
this.createdAt = fields.createdAt;
this.updatedAt = fields.updatedAt;
this.containerRegistry = fields.containerRegistry;
this.container = fields.container;
this.version = fields.version;
this.authority = fields.authority;
this.escrow = fields.escrow;
this.addressLookupTable = fields.addressLookupTable;
this.attestationQueue = fields.attestationQueue;
this.queueIdx = fields.queueIdx;
this.schedule = fields.schedule;
this.lastExecutionTimestamp = fields.lastExecutionTimestamp;
this.nextAllowedTimestamp = fields.nextAllowedTimestamp;
this.schedule = fields.schedule;
this.escrow = fields.escrow;
this.status = fields.status;
this.createdAt = fields.createdAt;
this.isTriggered = fields.isTriggered;
this.addressLookupTable = fields.addressLookupTable;
this.triggerCount = fields.triggerCount;
this.permissionExpiration = fields.permissionExpiration;
this.numRequests = fields.numRequests;
this.requestsDisabled = fields.requestsDisabled;
this.requestsRequireAuthorization = fields.requestsRequireAuthorization;
this.requestsDefaultSlotsUntilExpiration =
fields.requestsDefaultSlotsUntilExpiration;
this.requestsFee = fields.requestsFee;
this.mrEnclaves = fields.mrEnclaves;
this.ebuf = fields.ebuf;
}
@ -156,66 +305,103 @@ export class FunctionAccountData {
const dec = FunctionAccountData.layout.decode(data.slice(8));
return new FunctionAccountData({
isScheduled: dec.isScheduled,
isTriggered: dec.isTriggered,
permissions: dec.permissions,
status: types.FunctionStatus.fromDecoded(dec.status),
name: dec.name,
metadata: dec.metadata,
authority: dec.authority,
createdAt: dec.createdAt,
updatedAt: dec.updatedAt,
containerRegistry: dec.containerRegistry,
container: dec.container,
version: dec.version,
authority: dec.authority,
escrow: dec.escrow,
addressLookupTable: dec.addressLookupTable,
attestationQueue: dec.attestationQueue,
queueIdx: dec.queueIdx,
schedule: dec.schedule,
lastExecutionTimestamp: dec.lastExecutionTimestamp,
nextAllowedTimestamp: dec.nextAllowedTimestamp,
schedule: dec.schedule,
escrow: dec.escrow,
status: types.FunctionStatus.fromDecoded(dec.status),
createdAt: dec.createdAt,
isTriggered: dec.isTriggered,
addressLookupTable: dec.addressLookupTable,
triggerCount: dec.triggerCount,
permissionExpiration: dec.permissionExpiration,
numRequests: dec.numRequests,
requestsDisabled: dec.requestsDisabled,
requestsRequireAuthorization: dec.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
dec.requestsDefaultSlotsUntilExpiration,
requestsFee: dec.requestsFee,
mrEnclaves: dec.mrEnclaves,
ebuf: dec.ebuf,
});
}
toJSON(): FunctionAccountDataJSON {
return {
isScheduled: this.isScheduled,
isTriggered: this.isTriggered,
permissions: this.permissions,
status: this.status.toJSON(),
name: this.name,
metadata: this.metadata,
authority: this.authority.toString(),
createdAt: this.createdAt.toString(),
updatedAt: this.updatedAt.toString(),
containerRegistry: this.containerRegistry,
container: this.container,
version: this.version,
authority: this.authority.toString(),
escrow: this.escrow.toString(),
addressLookupTable: this.addressLookupTable.toString(),
attestationQueue: this.attestationQueue.toString(),
queueIdx: this.queueIdx,
schedule: this.schedule,
lastExecutionTimestamp: this.lastExecutionTimestamp.toString(),
nextAllowedTimestamp: this.nextAllowedTimestamp.toString(),
schedule: this.schedule,
escrow: this.escrow.toString(),
status: this.status.toJSON(),
createdAt: this.createdAt.toString(),
isTriggered: this.isTriggered,
addressLookupTable: this.addressLookupTable.toString(),
triggerCount: this.triggerCount.toString(),
permissionExpiration: this.permissionExpiration.toString(),
numRequests: this.numRequests.toString(),
requestsDisabled: this.requestsDisabled,
requestsRequireAuthorization: this.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
this.requestsDefaultSlotsUntilExpiration.toString(),
requestsFee: this.requestsFee.toString(),
mrEnclaves: this.mrEnclaves,
ebuf: this.ebuf,
};
}
static fromJSON(obj: FunctionAccountDataJSON): FunctionAccountData {
return new FunctionAccountData({
isScheduled: obj.isScheduled,
isTriggered: obj.isTriggered,
permissions: obj.permissions,
status: types.FunctionStatus.fromJSON(obj.status),
name: obj.name,
metadata: obj.metadata,
authority: new PublicKey(obj.authority),
createdAt: new BN(obj.createdAt),
updatedAt: new BN(obj.updatedAt),
containerRegistry: obj.containerRegistry,
container: obj.container,
version: obj.version,
authority: new PublicKey(obj.authority),
escrow: new PublicKey(obj.escrow),
addressLookupTable: new PublicKey(obj.addressLookupTable),
attestationQueue: new PublicKey(obj.attestationQueue),
queueIdx: obj.queueIdx,
schedule: obj.schedule,
lastExecutionTimestamp: new BN(obj.lastExecutionTimestamp),
nextAllowedTimestamp: new BN(obj.nextAllowedTimestamp),
schedule: obj.schedule,
escrow: new PublicKey(obj.escrow),
status: types.FunctionStatus.fromJSON(obj.status),
createdAt: new BN(obj.createdAt),
isTriggered: obj.isTriggered,
addressLookupTable: new PublicKey(obj.addressLookupTable),
triggerCount: new BN(obj.triggerCount),
permissionExpiration: new BN(obj.permissionExpiration),
numRequests: new BN(obj.numRequests),
requestsDisabled: obj.requestsDisabled,
requestsRequireAuthorization: obj.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration: new BN(
obj.requestsDefaultSlotsUntilExpiration
),
requestsFee: new BN(obj.requestsFee),
mrEnclaves: obj.mrEnclaves,
ebuf: obj.ebuf,
});
}

View File

@ -0,0 +1,265 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestAccountDataFields {
/** Whether the request is ready to be processed. */
isTriggered: number;
/** The status of the current request. */
status: types.RequestStatusKind;
/** Signer allowed to cancel the request. */
authority: PublicKey;
/** The default destination for rent exemption when the account is closed. */
payer: PublicKey;
/** The function that can process this request */
function: PublicKey;
/** The tokenAccount escrow */
escrow: PublicKey;
/** The current active request. */
activeRequest: types.FunctionRequestTriggerRoundFields;
/** The previous request. */
previousRequest: types.FunctionRequestTriggerRoundFields;
/** The maximum number of bytes to pass to the container params. */
maxContainerParamsLen: number;
/**
* Hash of the serialized container_params to prevent RPC tampering.
* Should be verified within your function to ensure you are using the correct parameters.
*/
containerParamsHash: Array<number>;
/** The stringified container params to pass to the function. */
containerParams: Uint8Array;
/** The unix timestamp when the function was created. */
createdAt: BN;
/** The slot when the account can be garbage collected and closed by anyone for a portion of the rent. */
garbageCollectionSlot: BN | null;
/** Reserved. */
ebuf: Array<number>;
}
export interface FunctionRequestAccountDataJSON {
/** Whether the request is ready to be processed. */
isTriggered: number;
/** The status of the current request. */
status: types.RequestStatusJSON;
/** Signer allowed to cancel the request. */
authority: string;
/** The default destination for rent exemption when the account is closed. */
payer: string;
/** The function that can process this request */
function: string;
/** The tokenAccount escrow */
escrow: string;
/** The current active request. */
activeRequest: types.FunctionRequestTriggerRoundJSON;
/** The previous request. */
previousRequest: types.FunctionRequestTriggerRoundJSON;
/** The maximum number of bytes to pass to the container params. */
maxContainerParamsLen: number;
/**
* Hash of the serialized container_params to prevent RPC tampering.
* Should be verified within your function to ensure you are using the correct parameters.
*/
containerParamsHash: Array<number>;
/** The stringified container params to pass to the function. */
containerParams: Array<number>;
/** The unix timestamp when the function was created. */
createdAt: string;
/** The slot when the account can be garbage collected and closed by anyone for a portion of the rent. */
garbageCollectionSlot: string | null;
/** Reserved. */
ebuf: Array<number>;
}
export class FunctionRequestAccountData {
/** Whether the request is ready to be processed. */
readonly isTriggered: number;
/** The status of the current request. */
readonly status: types.RequestStatusKind;
/** Signer allowed to cancel the request. */
readonly authority: PublicKey;
/** The default destination for rent exemption when the account is closed. */
readonly payer: PublicKey;
/** The function that can process this request */
readonly function: PublicKey;
/** The tokenAccount escrow */
readonly escrow: PublicKey;
/** The current active request. */
readonly activeRequest: types.FunctionRequestTriggerRound;
/** The previous request. */
readonly previousRequest: types.FunctionRequestTriggerRound;
/** The maximum number of bytes to pass to the container params. */
readonly maxContainerParamsLen: number;
/**
* Hash of the serialized container_params to prevent RPC tampering.
* Should be verified within your function to ensure you are using the correct parameters.
*/
readonly containerParamsHash: Array<number>;
/** The stringified container params to pass to the function. */
readonly containerParams: Uint8Array;
/** The unix timestamp when the function was created. */
readonly createdAt: BN;
/** The slot when the account can be garbage collected and closed by anyone for a portion of the rent. */
readonly garbageCollectionSlot: BN | null;
/** Reserved. */
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
8, 14, 177, 85, 144, 65, 148, 246,
]);
static readonly layout = borsh.struct([
borsh.u8("isTriggered"),
types.RequestStatus.layout("status"),
borsh.publicKey("authority"),
borsh.publicKey("payer"),
borsh.publicKey("function"),
borsh.publicKey("escrow"),
types.FunctionRequestTriggerRound.layout("activeRequest"),
types.FunctionRequestTriggerRound.layout("previousRequest"),
borsh.u32("maxContainerParamsLen"),
borsh.array(borsh.u8(), 32, "containerParamsHash"),
borsh.vecU8("containerParams"),
borsh.i64("createdAt"),
borsh.option(borsh.u64(), "garbageCollectionSlot"),
borsh.array(borsh.u8(), 256, "ebuf"),
]);
constructor(fields: FunctionRequestAccountDataFields) {
this.isTriggered = fields.isTriggered;
this.status = fields.status;
this.authority = fields.authority;
this.payer = fields.payer;
this.function = fields.function;
this.escrow = fields.escrow;
this.activeRequest = new types.FunctionRequestTriggerRound({
...fields.activeRequest,
});
this.previousRequest = new types.FunctionRequestTriggerRound({
...fields.previousRequest,
});
this.maxContainerParamsLen = fields.maxContainerParamsLen;
this.containerParamsHash = fields.containerParamsHash;
this.containerParams = fields.containerParams;
this.createdAt = fields.createdAt;
this.garbageCollectionSlot = fields.garbageCollectionSlot;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<FunctionRequestAccountData | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
}
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<FunctionRequestAccountData | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
});
}
static decode(data: Buffer): FunctionRequestAccountData {
if (!data.slice(0, 8).equals(FunctionRequestAccountData.discriminator)) {
throw new Error("invalid account discriminator");
}
const dec = FunctionRequestAccountData.layout.decode(data.slice(8));
return new FunctionRequestAccountData({
isTriggered: dec.isTriggered,
status: types.RequestStatus.fromDecoded(dec.status),
authority: dec.authority,
payer: dec.payer,
function: dec.function,
escrow: dec.escrow,
activeRequest: types.FunctionRequestTriggerRound.fromDecoded(
dec.activeRequest
),
previousRequest: types.FunctionRequestTriggerRound.fromDecoded(
dec.previousRequest
),
maxContainerParamsLen: dec.maxContainerParamsLen,
containerParamsHash: dec.containerParamsHash,
containerParams: new Uint8Array(
dec.containerParams.buffer,
dec.containerParams.byteOffset,
dec.containerParams.length
),
createdAt: dec.createdAt,
garbageCollectionSlot: dec.garbageCollectionSlot,
ebuf: dec.ebuf,
});
}
toJSON(): FunctionRequestAccountDataJSON {
return {
isTriggered: this.isTriggered,
status: this.status.toJSON(),
authority: this.authority.toString(),
payer: this.payer.toString(),
function: this.function.toString(),
escrow: this.escrow.toString(),
activeRequest: this.activeRequest.toJSON(),
previousRequest: this.previousRequest.toJSON(),
maxContainerParamsLen: this.maxContainerParamsLen,
containerParamsHash: this.containerParamsHash,
containerParams: Array.from(this.containerParams.values()),
createdAt: this.createdAt.toString(),
garbageCollectionSlot:
(this.garbageCollectionSlot && this.garbageCollectionSlot.toString()) ||
null,
ebuf: this.ebuf,
};
}
static fromJSON(
obj: FunctionRequestAccountDataJSON
): FunctionRequestAccountData {
return new FunctionRequestAccountData({
isTriggered: obj.isTriggered,
status: types.RequestStatus.fromJSON(obj.status),
authority: new PublicKey(obj.authority),
payer: new PublicKey(obj.payer),
function: new PublicKey(obj.function),
escrow: new PublicKey(obj.escrow),
activeRequest: types.FunctionRequestTriggerRound.fromJSON(
obj.activeRequest
),
previousRequest: types.FunctionRequestTriggerRound.fromJSON(
obj.previousRequest
),
maxContainerParamsLen: obj.maxContainerParamsLen,
containerParamsHash: obj.containerParamsHash,
containerParams: Uint8Array.from(obj.containerParams),
createdAt: new BN(obj.createdAt),
garbageCollectionSlot:
(obj.garbageCollectionSlot && new BN(obj.garbageCollectionSlot)) ||
null,
ebuf: obj.ebuf,
});
}
}

View File

@ -3,20 +3,28 @@ export type {
AttestationPermissionAccountDataJSON,
} from "./AttestationPermissionAccountData.js";
export { AttestationPermissionAccountData } from "./AttestationPermissionAccountData.js";
export type {
AttestationProgramStateFields,
AttestationProgramStateJSON,
} from "./AttestationProgramState.js";
export { AttestationProgramState } from "./AttestationProgramState.js";
export type {
AttestationQueueAccountDataFields,
AttestationQueueAccountDataJSON,
} from "./AttestationQueueAccountData.js";
export { AttestationQueueAccountData } from "./AttestationQueueAccountData.js";
export type {
EnclaveAccountDataFields,
EnclaveAccountDataJSON,
} from "./EnclaveAccountData.js";
export { EnclaveAccountData } from "./EnclaveAccountData.js";
export type {
FunctionAccountDataFields,
FunctionAccountDataJSON,
} from "./FunctionAccountData.js";
export { FunctionAccountData } from "./FunctionAccountData.js";
export type {
QuoteAccountDataFields,
QuoteAccountDataJSON,
} from "./QuoteAccountData.js";
export { QuoteAccountData } from "./QuoteAccountData.js";
export type { StateFields, StateJSON } from "./State.js";
export { State } from "./State.js";
FunctionRequestAccountDataFields,
FunctionRequestAccountDataJSON,
} from "./FunctionRequestAccountData.js";
export { FunctionRequestAccountData } from "./FunctionRequestAccountData.js";

View File

@ -1,12 +1,14 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
export type CustomError =
| GenericError
| InvalidQuoteError
| QuoteExpiredError
| InvalidNodeError
| InsufficientQueueError
| QueueFullError
| InvalidSignerError
| InvalidQuote
| QuoteExpired
| InvalidNode
| InsufficientQueue
| QueueFull
| InvalidEnclaveSigner
| InvalidSigner
| MrEnclavesEmpty
| MrEnclaveAlreadyExists
| MrEnclaveDoesntExist
| MrEnclaveAtCapacity
@ -15,17 +17,30 @@ export type CustomError =
| InvalidTimestamp
| InvalidMrEnclave
| InvalidReportData
| InsufficientLoadAmountError
| IncorrectObservedTimeError
| InsufficientLoadAmount
| IncorrectObservedTime
| InvalidQuoteMode
| InvalidVerifierIdx
| InvalidSelfVerifyRequest
| IncorrectMrEnclave
| InvalidResponder
| InvalidAddressLookupAddress
| InvalidQueueError
| InvalidQueue
| IllegalVerifier
| InvalidAuthorityError;
| InvalidEscrow
| InvalidAuthority
| IllegalExecuteAttempt
| RequestExpired
| InsufficientFunds
| MissingFunctionEscrow
| InvalidRequest
| FunctionNotReady
| UserRequestsDisabled
| MissingFunctionAuthority
| FunctionCloseNotReady
| RequestAlreadyInitialized
| AccountCloseNotPermitted
| AccountCloseNotReady;
export class GenericError extends Error {
static readonly code = 6000;
@ -37,253 +52,459 @@ export class GenericError extends Error {
}
}
export class InvalidQuoteError extends Error {
export class InvalidQuote extends Error {
static readonly code = 6001;
readonly code = 6001;
readonly name = "InvalidQuoteError";
readonly name = "InvalidQuote";
constructor(readonly logs?: string[]) {
super("6001: ");
}
}
export class QuoteExpiredError extends Error {
export class QuoteExpired extends Error {
static readonly code = 6002;
readonly code = 6002;
readonly name = "QuoteExpiredError";
readonly name = "QuoteExpired";
readonly msg = "The EnclaveAccount has expired and needs to be reverified";
constructor(readonly logs?: string[]) {
super("6002: ");
super("6002: The EnclaveAccount has expired and needs to be reverified");
}
}
export class InvalidNodeError extends Error {
export class InvalidNode extends Error {
static readonly code = 6003;
readonly code = 6003;
readonly name = "InvalidNodeError";
readonly name = "InvalidNode";
constructor(readonly logs?: string[]) {
super("6003: ");
}
}
export class InsufficientQueueError extends Error {
export class InsufficientQueue extends Error {
static readonly code = 6004;
readonly code = 6004;
readonly name = "InsufficientQueueError";
readonly name = "InsufficientQueue";
constructor(readonly logs?: string[]) {
super("6004: ");
}
}
export class QueueFullError extends Error {
export class QueueFull extends Error {
static readonly code = 6005;
readonly code = 6005;
readonly name = "QueueFullError";
readonly name = "QueueFull";
readonly msg = "The provided queue is full and cannot support new verifiers";
constructor(readonly logs?: string[]) {
super("6005: ");
super("6005: The provided queue is full and cannot support new verifiers");
}
}
export class InvalidSignerError extends Error {
export class InvalidEnclaveSigner extends Error {
static readonly code = 6006;
readonly code = 6006;
readonly name = "InvalidSignerError";
readonly name = "InvalidEnclaveSigner";
readonly msg =
"The provided enclave_signer does not match the expected enclave_signer on the EnclaveAccount";
constructor(readonly logs?: string[]) {
super("6006: ");
super(
"6006: The provided enclave_signer does not match the expected enclave_signer on the EnclaveAccount"
);
}
}
export class MrEnclaveAlreadyExists extends Error {
export class InvalidSigner extends Error {
static readonly code = 6007;
readonly code = 6007;
readonly name = "MrEnclaveAlreadyExists";
readonly name = "InvalidSigner";
constructor(readonly logs?: string[]) {
super("6007: ");
}
}
export class MrEnclaveDoesntExist extends Error {
export class MrEnclavesEmpty extends Error {
static readonly code = 6008;
readonly code = 6008;
readonly name = "MrEnclaveDoesntExist";
readonly name = "MrEnclavesEmpty";
readonly msg = "This account has zero mr_enclaves defined";
constructor(readonly logs?: string[]) {
super("6008: ");
super("6008: This account has zero mr_enclaves defined");
}
}
export class MrEnclaveAlreadyExists extends Error {
static readonly code = 6009;
readonly code = 6009;
readonly name = "MrEnclaveAlreadyExists";
readonly msg = "The MrEnclave value already exists in the array";
constructor(readonly logs?: string[]) {
super("6009: The MrEnclave value already exists in the array");
}
}
export class MrEnclaveDoesntExist extends Error {
static readonly code = 6010;
readonly code = 6010;
readonly name = "MrEnclaveDoesntExist";
readonly msg = "The MrEnclave value was not found in the whitelist";
constructor(readonly logs?: string[]) {
super("6010: The MrEnclave value was not found in the whitelist");
}
}
export class MrEnclaveAtCapacity extends Error {
static readonly code = 6009;
readonly code = 6009;
static readonly code = 6011;
readonly code = 6011;
readonly name = "MrEnclaveAtCapacity";
readonly msg =
"This account has a full mr_enclaves array. Remove some measurements to make room for new ones";
constructor(readonly logs?: string[]) {
super("6009: ");
super(
"6011: This account has a full mr_enclaves array. Remove some measurements to make room for new ones"
);
}
}
export class PermissionDenied extends Error {
static readonly code = 6010;
readonly code = 6010;
static readonly code = 6012;
readonly code = 6012;
readonly name = "PermissionDenied";
readonly msg =
"The PermissionAccount is missing the required flags for this action. Check the queues config to see which permissions are required";
constructor(readonly logs?: string[]) {
super("6010: ");
super(
"6012: The PermissionAccount is missing the required flags for this action. Check the queues config to see which permissions are required"
);
}
}
export class InvalidConstraint extends Error {
static readonly code = 6011;
readonly code = 6011;
readonly name = "InvalidConstraint";
constructor(readonly logs?: string[]) {
super("6011: ");
}
}
export class InvalidTimestamp extends Error {
static readonly code = 6012;
readonly code = 6012;
readonly name = "InvalidTimestamp";
constructor(readonly logs?: string[]) {
super("6012: ");
}
}
export class InvalidMrEnclave extends Error {
static readonly code = 6013;
readonly code = 6013;
readonly name = "InvalidMrEnclave";
readonly name = "InvalidConstraint";
constructor(readonly logs?: string[]) {
super("6013: ");
}
}
export class InvalidReportData extends Error {
export class InvalidTimestamp extends Error {
static readonly code = 6014;
readonly code = 6014;
readonly name = "InvalidReportData";
readonly name = "InvalidTimestamp";
constructor(readonly logs?: string[]) {
super("6014: ");
}
}
export class InsufficientLoadAmountError extends Error {
export class InvalidMrEnclave extends Error {
static readonly code = 6015;
readonly code = 6015;
readonly name = "InsufficientLoadAmountError";
readonly name = "InvalidMrEnclave";
constructor(readonly logs?: string[]) {
super("6015: ");
}
}
export class IncorrectObservedTimeError extends Error {
export class InvalidReportData extends Error {
static readonly code = 6016;
readonly code = 6016;
readonly name = "IncorrectObservedTimeError";
readonly name = "InvalidReportData";
constructor(readonly logs?: string[]) {
super("6016: ");
}
}
export class InvalidQuoteMode extends Error {
export class InsufficientLoadAmount extends Error {
static readonly code = 6017;
readonly code = 6017;
readonly name = "InvalidQuoteMode";
readonly name = "InsufficientLoadAmount";
constructor(readonly logs?: string[]) {
super("6017: ");
}
}
export class InvalidVerifierIdx extends Error {
export class IncorrectObservedTime extends Error {
static readonly code = 6018;
readonly code = 6018;
readonly name = "InvalidVerifierIdx";
readonly name = "IncorrectObservedTime";
constructor(readonly logs?: string[]) {
super("6018: ");
}
}
export class InvalidSelfVerifyRequest extends Error {
export class InvalidQuoteMode extends Error {
static readonly code = 6019;
readonly code = 6019;
readonly name = "InvalidSelfVerifyRequest";
readonly name = "InvalidQuoteMode";
constructor(readonly logs?: string[]) {
super("6019: ");
}
}
export class IncorrectMrEnclave extends Error {
export class InvalidVerifierIdx extends Error {
static readonly code = 6020;
readonly code = 6020;
readonly name = "IncorrectMrEnclave";
readonly name = "InvalidVerifierIdx";
constructor(readonly logs?: string[]) {
super("6020: ");
}
}
export class InvalidResponder extends Error {
export class InvalidSelfVerifyRequest extends Error {
static readonly code = 6021;
readonly code = 6021;
readonly name = "InvalidResponder";
readonly name = "InvalidSelfVerifyRequest";
constructor(readonly logs?: string[]) {
super("6021: ");
}
}
export class InvalidAddressLookupAddress extends Error {
export class IncorrectMrEnclave extends Error {
static readonly code = 6022;
readonly code = 6022;
readonly name = "InvalidAddressLookupAddress";
readonly name = "IncorrectMrEnclave";
constructor(readonly logs?: string[]) {
super("6022: ");
}
}
export class InvalidQueueError extends Error {
export class InvalidResponder extends Error {
static readonly code = 6023;
readonly code = 6023;
readonly name = "InvalidQueueError";
readonly name = "InvalidResponder";
constructor(readonly logs?: string[]) {
super("6023: ");
}
}
export class IllegalVerifier extends Error {
export class InvalidAddressLookupAddress extends Error {
static readonly code = 6024;
readonly code = 6024;
readonly name = "IllegalVerifier";
readonly name = "InvalidAddressLookupAddress";
readonly msg =
"The provided address_lookup_address did not match the expected address on-chain";
constructor(readonly logs?: string[]) {
super("6024: ");
super(
"6024: The provided address_lookup_address did not match the expected address on-chain"
);
}
}
export class InvalidAuthorityError extends Error {
export class InvalidQueue extends Error {
static readonly code = 6025;
readonly code = 6025;
readonly name = "InvalidAuthorityError";
readonly name = "InvalidQueue";
readonly msg =
"The provided attestation queue address did not match the expected address on-chain";
constructor(readonly logs?: string[]) {
super("6025: ");
super(
"6025: The provided attestation queue address did not match the expected address on-chain"
);
}
}
export class IllegalVerifier extends Error {
static readonly code = 6026;
readonly code = 6026;
readonly name = "IllegalVerifier";
constructor(readonly logs?: string[]) {
super("6026: ");
}
}
export class InvalidEscrow extends Error {
static readonly code = 6027;
readonly code = 6027;
readonly name = "InvalidEscrow";
constructor(readonly logs?: string[]) {
super("6027: ");
}
}
export class InvalidAuthority extends Error {
static readonly code = 6028;
readonly code = 6028;
readonly name = "InvalidAuthority";
readonly msg =
"The provided authority account does not match the expected value on-chain";
constructor(readonly logs?: string[]) {
super(
"6028: The provided authority account does not match the expected value on-chain"
);
}
}
export class IllegalExecuteAttempt extends Error {
static readonly code = 6029;
readonly code = 6029;
readonly name = "IllegalExecuteAttempt";
constructor(readonly logs?: string[]) {
super("6029: ");
}
}
export class RequestExpired extends Error {
static readonly code = 6030;
readonly code = 6030;
readonly name = "RequestExpired";
readonly msg = "The requests expirationSlot has expired";
constructor(readonly logs?: string[]) {
super("6030: The requests expirationSlot has expired");
}
}
export class InsufficientFunds extends Error {
static readonly code = 6031;
readonly code = 6031;
readonly name = "InsufficientFunds";
readonly msg = "The escrow has insufficient funds for this action";
constructor(readonly logs?: string[]) {
super("6031: The escrow has insufficient funds for this action");
}
}
export class MissingFunctionEscrow extends Error {
static readonly code = 6032;
readonly code = 6032;
readonly name = "MissingFunctionEscrow";
readonly msg =
"The FunctionAccount escrow is required if function.requests_fee is greater than zero";
constructor(readonly logs?: string[]) {
super(
"6032: The FunctionAccount escrow is required if function.requests_fee is greater than zero"
);
}
}
export class InvalidRequest extends Error {
static readonly code = 6033;
readonly code = 6033;
readonly name = "InvalidRequest";
readonly msg =
"The provided requestSlot did not match the expected requestSlot on-chain. The request may have already been processed";
constructor(readonly logs?: string[]) {
super(
"6033: The provided requestSlot did not match the expected requestSlot on-chain. The request may have already been processed"
);
}
}
export class FunctionNotReady extends Error {
static readonly code = 6034;
readonly code = 6034;
readonly name = "FunctionNotReady";
readonly msg = "The FunctionAccount status is not active (1)";
constructor(readonly logs?: string[]) {
super("6034: The FunctionAccount status is not active (1)");
}
}
export class UserRequestsDisabled extends Error {
static readonly code = 6035;
readonly code = 6035;
readonly name = "UserRequestsDisabled";
readonly msg =
"The FunctionAccount has set requests_disabled to true and disabled this action";
constructor(readonly logs?: string[]) {
super(
"6035: The FunctionAccount has set requests_disabled to true and disabled this action"
);
}
}
export class MissingFunctionAuthority extends Error {
static readonly code = 6036;
readonly code = 6036;
readonly name = "MissingFunctionAuthority";
readonly msg =
"The FunctionAccount authority is required to sign if function.requests_require_authorization is enabled";
constructor(readonly logs?: string[]) {
super(
"6036: The FunctionAccount authority is required to sign if function.requests_require_authorization is enabled"
);
}
}
export class FunctionCloseNotReady extends Error {
static readonly code = 6037;
readonly code = 6037;
readonly name = "FunctionCloseNotReady";
readonly msg =
"The FunctionAccount must have no requests before it can be closed";
constructor(readonly logs?: string[]) {
super(
"6037: The FunctionAccount must have no requests before it can be closed"
);
}
}
export class RequestAlreadyInitialized extends Error {
static readonly code = 6038;
readonly code = 6038;
readonly name = "RequestAlreadyInitialized";
readonly msg =
"Attempting to initialize an already created FunctionRequestAccount";
constructor(readonly logs?: string[]) {
super(
"6038: Attempting to initialize an already created FunctionRequestAccount"
);
}
}
export class AccountCloseNotPermitted extends Error {
static readonly code = 6039;
readonly code = 6039;
readonly name = "AccountCloseNotPermitted";
constructor(readonly logs?: string[]) {
super("6039: ");
}
}
export class AccountCloseNotReady extends Error {
static readonly code = 6040;
readonly code = 6040;
readonly name = "AccountCloseNotReady";
constructor(readonly logs?: string[]) {
super("6040: ");
}
}
@ -292,55 +513,85 @@ export function fromCode(code: number, logs?: string[]): CustomError | null {
case 6000:
return new GenericError(logs);
case 6001:
return new InvalidQuoteError(logs);
return new InvalidQuote(logs);
case 6002:
return new QuoteExpiredError(logs);
return new QuoteExpired(logs);
case 6003:
return new InvalidNodeError(logs);
return new InvalidNode(logs);
case 6004:
return new InsufficientQueueError(logs);
return new InsufficientQueue(logs);
case 6005:
return new QueueFullError(logs);
return new QueueFull(logs);
case 6006:
return new InvalidSignerError(logs);
return new InvalidEnclaveSigner(logs);
case 6007:
return new MrEnclaveAlreadyExists(logs);
return new InvalidSigner(logs);
case 6008:
return new MrEnclaveDoesntExist(logs);
return new MrEnclavesEmpty(logs);
case 6009:
return new MrEnclaveAtCapacity(logs);
return new MrEnclaveAlreadyExists(logs);
case 6010:
return new PermissionDenied(logs);
return new MrEnclaveDoesntExist(logs);
case 6011:
return new InvalidConstraint(logs);
return new MrEnclaveAtCapacity(logs);
case 6012:
return new InvalidTimestamp(logs);
return new PermissionDenied(logs);
case 6013:
return new InvalidMrEnclave(logs);
return new InvalidConstraint(logs);
case 6014:
return new InvalidReportData(logs);
return new InvalidTimestamp(logs);
case 6015:
return new InsufficientLoadAmountError(logs);
return new InvalidMrEnclave(logs);
case 6016:
return new IncorrectObservedTimeError(logs);
return new InvalidReportData(logs);
case 6017:
return new InvalidQuoteMode(logs);
return new InsufficientLoadAmount(logs);
case 6018:
return new InvalidVerifierIdx(logs);
return new IncorrectObservedTime(logs);
case 6019:
return new InvalidSelfVerifyRequest(logs);
return new InvalidQuoteMode(logs);
case 6020:
return new IncorrectMrEnclave(logs);
return new InvalidVerifierIdx(logs);
case 6021:
return new InvalidResponder(logs);
return new InvalidSelfVerifyRequest(logs);
case 6022:
return new InvalidAddressLookupAddress(logs);
return new IncorrectMrEnclave(logs);
case 6023:
return new InvalidQueueError(logs);
return new InvalidResponder(logs);
case 6024:
return new IllegalVerifier(logs);
return new InvalidAddressLookupAddress(logs);
case 6025:
return new InvalidAuthorityError(logs);
return new InvalidQueue(logs);
case 6026:
return new IllegalVerifier(logs);
case 6027:
return new InvalidEscrow(logs);
case 6028:
return new InvalidAuthority(logs);
case 6029:
return new IllegalExecuteAttempt(logs);
case 6030:
return new RequestExpired(logs);
case 6031:
return new InsufficientFunds(logs);
case 6032:
return new MissingFunctionEscrow(logs);
case 6033:
return new InvalidRequest(logs);
case 6034:
return new FunctionNotReady(logs);
case 6035:
return new UserRequestsDisabled(logs);
case 6036:
return new MissingFunctionAuthority(logs);
case 6037:
return new FunctionCloseNotReady(logs);
case 6038:
return new RequestAlreadyInitialized(logs);
case 6039:
return new AccountCloseNotPermitted(logs);
case 6040:
return new AccountCloseNotReady(logs);
}
return null;

View File

@ -17,7 +17,7 @@ export interface AttestationPermissionSetAccounts {
permission: PublicKey;
authority: PublicKey;
attestationQueue: PublicKey;
node: PublicKey;
enclave: PublicKey;
}
export const layout = borsh.struct([
@ -33,7 +33,7 @@ export function attestationPermissionSet(
{ pubkey: accounts.permission, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.node, isSigner: false, isWritable: false },
{ pubkey: accounts.enclave, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([56, 253, 255, 201, 100, 153, 10, 76]);
const buffer = Buffer.alloc(1000);

View File

@ -0,0 +1,69 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionCloseArgs {
params: types.FunctionCloseParamsFields;
}
export interface FunctionCloseAccounts {
function: PublicKey;
authority: PublicKey;
escrow: PublicKey;
addressLookupTable: PublicKey;
solDest: PublicKey;
escrowDest: PublicKey;
state: PublicKey;
tokenProgram: PublicKey;
systemProgram: PublicKey;
addressLookupProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionCloseParams.layout("params"),
]);
export function functionClose(
program: SwitchboardProgram,
args: FunctionCloseArgs,
accounts: FunctionCloseAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.addressLookupTable, isSigner: false, isWritable: true },
{ pubkey: accounts.solDest, isSigner: false, isWritable: false },
{ pubkey: accounts.escrowDest, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.addressLookupProgram,
isSigner: false,
isWritable: false,
},
];
const identifier = Buffer.from([94, 164, 174, 42, 156, 29, 244, 236]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionCloseParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -37,7 +37,7 @@ export function functionFund(
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.funder, isSigner: false, isWritable: true },
{ pubkey: accounts.funderAuthority, isSigner: true, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.associatedTokenProgram,

View File

@ -19,7 +19,6 @@ export interface FunctionInitAccounts {
authority: PublicKey;
quote: PublicKey;
attestationQueue: PublicKey;
permission: PublicKey;
payer: PublicKey;
escrow: PublicKey;
state: PublicKey;
@ -43,10 +42,9 @@ export function functionInit(
{ pubkey: accounts.authority, isSigner: false, isWritable: false },
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.permission, isSigner: false, isWritable: true },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.mint, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{

View File

@ -0,0 +1,63 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestCloseArgs {
params: types.FunctionRequestCloseParamsFields;
}
export interface FunctionRequestCloseAccounts {
request: PublicKey;
authority: PublicKey;
escrow: PublicKey;
function: PublicKey;
solDest: PublicKey;
escrowDest: PublicKey;
state: PublicKey;
tokenProgram: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionRequestCloseParams.layout("params"),
]);
export function functionRequestClose(
program: SwitchboardProgram,
args: FunctionRequestCloseArgs,
accounts: FunctionRequestCloseAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.request, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: false, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.solDest, isSigner: false, isWritable: false },
{ pubkey: accounts.escrowDest, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([5, 221, 34, 111, 136, 82, 119, 101]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionRequestCloseParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,73 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestInitArgs {
params: types.FunctionRequestInitParamsFields;
}
export interface FunctionRequestInitAccounts {
request: PublicKey;
authority: PublicKey;
function: PublicKey;
functionAuthority: PublicKey;
escrow: PublicKey;
mint: PublicKey;
state: PublicKey;
attestationQueue: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
tokenProgram: PublicKey;
associatedTokenProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionRequestInitParams.layout("params"),
]);
export function functionRequestInit(
program: SwitchboardProgram,
args: FunctionRequestInitArgs,
accounts: FunctionRequestInitAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.request, isSigner: true, isWritable: true },
{ pubkey: accounts.authority, isSigner: false, isWritable: false },
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.functionAuthority, isSigner: false, isWritable: true },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.mint, isSigner: false, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.associatedTokenProgram,
isSigner: false,
isWritable: false,
},
];
const identifier = Buffer.from([118, 8, 251, 119, 88, 174, 81, 239]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionRequestInitParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,71 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestInitAndTriggerArgs {
params: types.FunctionRequestInitAndTriggerParamsFields;
}
export interface FunctionRequestInitAndTriggerAccounts {
request: PublicKey;
function: PublicKey;
escrow: PublicKey;
mint: PublicKey;
state: PublicKey;
attestationQueue: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
tokenProgram: PublicKey;
associatedTokenProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionRequestInitAndTriggerParams.layout("params"),
]);
export function functionRequestInitAndTrigger(
program: SwitchboardProgram,
args: FunctionRequestInitAndTriggerArgs,
accounts: FunctionRequestInitAndTriggerAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.request, isSigner: true, isWritable: true },
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.mint, isSigner: false, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.associatedTokenProgram,
isSigner: false,
isWritable: false,
},
];
const identifier = Buffer.from([86, 151, 134, 172, 35, 218, 207, 154]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionRequestInitAndTriggerParams.toEncodable(
args.params
),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,49 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestSetConfigArgs {
params: types.FunctionRequestSetConfigParamsFields;
}
export interface FunctionRequestSetConfigAccounts {
request: PublicKey;
authority: PublicKey;
}
export const layout = borsh.struct([
types.FunctionRequestSetConfigParams.layout("params"),
]);
export function functionRequestSetConfig(
program: SwitchboardProgram,
args: FunctionRequestSetConfigArgs,
accounts: FunctionRequestSetConfigAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.request, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
];
const identifier = Buffer.from([16, 81, 197, 58, 129, 125, 91, 233]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionRequestSetConfigParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,63 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestTriggerArgs {
params: types.FunctionRequestTriggerParamsFields;
}
export interface FunctionRequestTriggerAccounts {
request: PublicKey;
authority: PublicKey;
escrow: PublicKey;
function: PublicKey;
state: PublicKey;
attestationQueue: PublicKey;
payer: PublicKey;
tokenProgram: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionRequestTriggerParams.layout("params"),
]);
export function functionRequestTrigger(
program: SwitchboardProgram,
args: FunctionRequestTriggerArgs,
accounts: FunctionRequestTriggerAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.request, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([74, 35, 78, 67, 196, 102, 78, 153]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionRequestTriggerParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,77 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestVerifyArgs {
params: types.FunctionRequestVerifyParamsFields;
}
export interface FunctionRequestVerifyAccounts {
request: PublicKey;
functionEnclaveSigner: PublicKey;
escrow: PublicKey;
function: PublicKey;
functionEscrow: PublicKey;
verifierQuote: PublicKey;
verifierEnclaveSigner: PublicKey;
verifierPermission: PublicKey;
state: PublicKey;
attestationQueue: PublicKey;
receiver: PublicKey;
tokenProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionRequestVerifyParams.layout("params"),
]);
export function functionRequestVerify(
program: SwitchboardProgram,
args: FunctionRequestVerifyArgs,
accounts: FunctionRequestVerifyAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.request, isSigner: false, isWritable: true },
{
pubkey: accounts.functionEnclaveSigner,
isSigner: true,
isWritable: false,
},
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.functionEscrow, isSigner: false, isWritable: true },
{ pubkey: accounts.verifierQuote, isSigner: false, isWritable: false },
{
pubkey: accounts.verifierEnclaveSigner,
isSigner: true,
isWritable: false,
},
{ pubkey: accounts.verifierPermission, isSigner: false, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.receiver, isSigner: false, isWritable: true },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([179, 6, 88, 97, 232, 112, 143, 253]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionRequestVerifyParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -15,6 +15,7 @@ export interface FunctionSetConfigArgs {
export interface FunctionSetConfigAccounts {
function: PublicKey;
quote: PublicKey;
authority: PublicKey;
}
@ -29,6 +30,7 @@ export function functionSetConfig(
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
];
const identifier = Buffer.from([232, 132, 21, 251, 253, 189, 96, 94]);

View File

@ -16,6 +16,7 @@ export interface FunctionTriggerArgs {
export interface FunctionTriggerAccounts {
function: PublicKey;
authority: PublicKey;
attestationQueue: PublicKey;
}
export const layout = borsh.struct([
@ -30,6 +31,7 @@ export function functionTrigger(
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([45, 224, 218, 184, 248, 83, 239, 200]);
const buffer = Buffer.alloc(1000);

View File

@ -15,19 +15,16 @@ export interface FunctionVerifyArgs {
export interface FunctionVerifyAccounts {
function: PublicKey;
fnSigner: PublicKey;
functionEnclaveSigner: PublicKey;
fnQuote: PublicKey;
verifierQuote: PublicKey;
securedSigner: PublicKey;
attestationQueue: PublicKey;
verifierEnclaveSigner: PublicKey;
verifierPermission: PublicKey;
escrow: PublicKey;
receiver: PublicKey;
verifierPermission: PublicKey;
fnPermission: PublicKey;
state: PublicKey;
attestationQueue: PublicKey;
tokenProgram: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
@ -41,19 +38,24 @@ export function functionVerify(
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.fnSigner, isSigner: true, isWritable: false },
{
pubkey: accounts.functionEnclaveSigner,
isSigner: true,
isWritable: false,
},
{ pubkey: accounts.fnQuote, isSigner: false, isWritable: true },
{ pubkey: accounts.verifierQuote, isSigner: false, isWritable: false },
{ pubkey: accounts.securedSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{
pubkey: accounts.verifierEnclaveSigner,
isSigner: true,
isWritable: false,
},
{ pubkey: accounts.verifierPermission, isSigner: false, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.receiver, isSigner: false, isWritable: true },
{ pubkey: accounts.verifierPermission, isSigner: false, isWritable: false },
{ pubkey: accounts.fnPermission, isSigner: false, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([210, 108, 154, 138, 198, 14, 53, 191]);
const buffer = Buffer.alloc(1000);

View File

@ -38,7 +38,7 @@ export function functionWithdraw(
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.receiver, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([6, 182, 241, 39, 40, 111, 65, 195]);

View File

@ -23,10 +23,45 @@ export type {
AttestationQueueRemoveMrEnclaveArgs,
} from "./attestationQueueRemoveMrEnclave.js";
export { attestationQueueRemoveMrEnclave } from "./attestationQueueRemoveMrEnclave.js";
export type {
FunctionCloseAccounts,
FunctionCloseArgs,
} from "./functionClose.js";
export { functionClose } from "./functionClose.js";
export type { FunctionFundAccounts, FunctionFundArgs } from "./functionFund.js";
export { functionFund } from "./functionFund.js";
export type { FunctionInitAccounts, FunctionInitArgs } from "./functionInit.js";
export { functionInit } from "./functionInit.js";
export type {
FunctionRequestCloseAccounts,
FunctionRequestCloseArgs,
} from "./functionRequestClose.js";
export { functionRequestClose } from "./functionRequestClose.js";
export type {
FunctionRequestInitAccounts,
FunctionRequestInitArgs,
} from "./functionRequestInit.js";
export { functionRequestInit } from "./functionRequestInit.js";
export type {
FunctionRequestInitAndTriggerAccounts,
FunctionRequestInitAndTriggerArgs,
} from "./functionRequestInitAndTrigger.js";
export { functionRequestInitAndTrigger } from "./functionRequestInitAndTrigger.js";
export type {
FunctionRequestSetConfigAccounts,
FunctionRequestSetConfigArgs,
} from "./functionRequestSetConfig.js";
export { functionRequestSetConfig } from "./functionRequestSetConfig.js";
export type {
FunctionRequestTriggerAccounts,
FunctionRequestTriggerArgs,
} from "./functionRequestTrigger.js";
export { functionRequestTrigger } from "./functionRequestTrigger.js";
export type {
FunctionRequestVerifyAccounts,
FunctionRequestVerifyArgs,
} from "./functionRequestVerify.js";
export { functionRequestVerify } from "./functionRequestVerify.js";
export type {
FunctionSetConfigAccounts,
FunctionSetConfigArgs,

View File

@ -15,7 +15,7 @@ export interface QuoteHeartbeatArgs {
export interface QuoteHeartbeatAccounts {
quote: PublicKey;
securedSigner: PublicKey;
enclaveSigner: PublicKey;
attestationQueue: PublicKey;
queueAuthority: PublicKey;
gcNode: PublicKey;
@ -33,7 +33,7 @@ export function quoteHeartbeat(
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.securedSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.enclaveSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: true },
{ pubkey: accounts.queueAuthority, isSigner: false, isWritable: false },
{ pubkey: accounts.gcNode, isSigner: false, isWritable: true },

View File

@ -16,7 +16,7 @@ export interface QuoteRotateArgs {
export interface QuoteRotateAccounts {
quote: PublicKey;
authority: PublicKey;
securedSigner: PublicKey;
enclaveSigner: PublicKey;
attestationQueue: PublicKey;
}
@ -30,7 +30,7 @@ export function quoteRotate(
const keys: Array<AccountMeta> = [
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.securedSigner, isSigner: false, isWritable: false },
{ pubkey: accounts.enclaveSigner, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: true },
];
const identifier = Buffer.from([153, 94, 246, 7, 7, 124, 62, 7]);

View File

@ -17,7 +17,7 @@ export interface QuoteVerifyAccounts {
quote: PublicKey;
quoteSigner: PublicKey;
verifier: PublicKey;
securedSigner: PublicKey;
enclaveSigner: PublicKey;
attestationQueue: PublicKey;
}
@ -32,7 +32,7 @@ export function quoteVerify(
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.quoteSigner, isSigner: false, isWritable: false },
{ pubkey: accounts.verifier, isSigner: false, isWritable: false },
{ pubkey: accounts.securedSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.enclaveSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([158, 203, 69, 10, 212, 218, 45, 184]);

View File

@ -2,7 +2,7 @@ import { PublicKey } from "@solana/web3.js";
// Program ID passed with the cli --program-id flag when running the code generator. Do not edit, it will get overwritten.
export const PROGRAM_ID_CLI = new PublicKey(
"SBAPyGPyvYEXTiTEfVrktmpvm3Bae3VoZmjYZ6694Ha"
"sbattyXrzedoNATfc4L31wC9Mhxsi1BmFhTiN8gDshx"
);
// This constant will not get overwritten on subsequent code generations and it's safe to modify it's value.

View File

@ -0,0 +1,39 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionCloseParamsFields {}
export interface FunctionCloseParamsJSON {}
export class FunctionCloseParams {
constructor(fields: FunctionCloseParamsFields) {}
static layout(property?: string) {
return borsh.struct([], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionCloseParams({});
}
static toEncodable(fields: FunctionCloseParamsFields) {
return {};
}
toJSON(): FunctionCloseParamsJSON {
return {};
}
static fromJSON(obj: FunctionCloseParamsJSON): FunctionCloseParams {
return new FunctionCloseParams({});
}
toEncodable() {
return FunctionCloseParams.toEncodable(this);
}
}

View File

@ -14,6 +14,10 @@ export interface FunctionInitParamsFields {
schedule: Uint8Array;
mrEnclave: Array<number>;
recentSlot: BN;
requestsDisabled: boolean;
requestsRequireAuthorization: boolean;
requestsDefaultSlotsUntilExpiration: BN;
requestsFee: BN;
}
export interface FunctionInitParamsJSON {
@ -25,6 +29,10 @@ export interface FunctionInitParamsJSON {
schedule: Array<number>;
mrEnclave: Array<number>;
recentSlot: string;
requestsDisabled: boolean;
requestsRequireAuthorization: boolean;
requestsDefaultSlotsUntilExpiration: string;
requestsFee: string;
}
export class FunctionInitParams {
@ -36,6 +44,10 @@ export class FunctionInitParams {
readonly schedule: Uint8Array;
readonly mrEnclave: Array<number>;
readonly recentSlot: BN;
readonly requestsDisabled: boolean;
readonly requestsRequireAuthorization: boolean;
readonly requestsDefaultSlotsUntilExpiration: BN;
readonly requestsFee: BN;
constructor(fields: FunctionInitParamsFields) {
this.name = fields.name;
@ -46,6 +58,11 @@ export class FunctionInitParams {
this.schedule = fields.schedule;
this.mrEnclave = fields.mrEnclave;
this.recentSlot = fields.recentSlot;
this.requestsDisabled = fields.requestsDisabled;
this.requestsRequireAuthorization = fields.requestsRequireAuthorization;
this.requestsDefaultSlotsUntilExpiration =
fields.requestsDefaultSlotsUntilExpiration;
this.requestsFee = fields.requestsFee;
}
static layout(property?: string) {
@ -59,6 +76,10 @@ export class FunctionInitParams {
borsh.vecU8("schedule"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
borsh.u64("recentSlot"),
borsh.bool("requestsDisabled"),
borsh.bool("requestsRequireAuthorization"),
borsh.u64("requestsDefaultSlotsUntilExpiration"),
borsh.u64("requestsFee"),
],
property
);
@ -99,6 +120,11 @@ export class FunctionInitParams {
),
mrEnclave: obj.mrEnclave,
recentSlot: obj.recentSlot,
requestsDisabled: obj.requestsDisabled,
requestsRequireAuthorization: obj.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
obj.requestsDefaultSlotsUntilExpiration,
requestsFee: obj.requestsFee,
});
}
@ -136,6 +162,11 @@ export class FunctionInitParams {
),
mrEnclave: fields.mrEnclave,
recentSlot: fields.recentSlot,
requestsDisabled: fields.requestsDisabled,
requestsRequireAuthorization: fields.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
fields.requestsDefaultSlotsUntilExpiration,
requestsFee: fields.requestsFee,
};
}
@ -149,6 +180,11 @@ export class FunctionInitParams {
schedule: Array.from(this.schedule.values()),
mrEnclave: this.mrEnclave,
recentSlot: this.recentSlot.toString(),
requestsDisabled: this.requestsDisabled,
requestsRequireAuthorization: this.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
this.requestsDefaultSlotsUntilExpiration.toString(),
requestsFee: this.requestsFee.toString(),
};
}
@ -162,6 +198,12 @@ export class FunctionInitParams {
schedule: Uint8Array.from(obj.schedule),
mrEnclave: obj.mrEnclave,
recentSlot: new BN(obj.recentSlot),
requestsDisabled: obj.requestsDisabled,
requestsRequireAuthorization: obj.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration: new BN(
obj.requestsDefaultSlotsUntilExpiration
),
requestsFee: new BN(obj.requestsFee),
});
}

View File

@ -0,0 +1,41 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestCloseParamsFields {}
export interface FunctionRequestCloseParamsJSON {}
export class FunctionRequestCloseParams {
constructor(fields: FunctionRequestCloseParamsFields) {}
static layout(property?: string) {
return borsh.struct([], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestCloseParams({});
}
static toEncodable(fields: FunctionRequestCloseParamsFields) {
return {};
}
toJSON(): FunctionRequestCloseParamsJSON {
return {};
}
static fromJSON(
obj: FunctionRequestCloseParamsJSON
): FunctionRequestCloseParams {
return new FunctionRequestCloseParams({});
}
toEncodable() {
return FunctionRequestCloseParams.toEncodable(this);
}
}

View File

@ -0,0 +1,122 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestInitAndTriggerParamsFields {
bounty: BN | null;
slotsUntilExpiration: BN | null;
maxContainerParamsLen: number | null;
containerParams: Uint8Array | null;
garbageCollectionSlot: BN | null;
}
export interface FunctionRequestInitAndTriggerParamsJSON {
bounty: string | null;
slotsUntilExpiration: string | null;
maxContainerParamsLen: number | null;
containerParams: Array<number> | null;
garbageCollectionSlot: string | null;
}
export class FunctionRequestInitAndTriggerParams {
readonly bounty: BN | null;
readonly slotsUntilExpiration: BN | null;
readonly maxContainerParamsLen: number | null;
readonly containerParams: Uint8Array | null;
readonly garbageCollectionSlot: BN | null;
constructor(fields: FunctionRequestInitAndTriggerParamsFields) {
this.bounty = fields.bounty;
this.slotsUntilExpiration = fields.slotsUntilExpiration;
this.maxContainerParamsLen = fields.maxContainerParamsLen;
this.containerParams = fields.containerParams;
this.garbageCollectionSlot = fields.garbageCollectionSlot;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.option(borsh.u64(), "bounty"),
borsh.option(borsh.u64(), "slotsUntilExpiration"),
borsh.option(borsh.u32(), "maxContainerParamsLen"),
borsh.option(borsh.vecU8(), "containerParams"),
borsh.option(borsh.u64(), "garbageCollectionSlot"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestInitAndTriggerParams({
bounty: obj.bounty,
slotsUntilExpiration: obj.slotsUntilExpiration,
maxContainerParamsLen: obj.maxContainerParamsLen,
containerParams:
(obj.containerParams &&
new Uint8Array(
obj.containerParams.buffer,
obj.containerParams.byteOffset,
obj.containerParams.length
)) ||
null,
garbageCollectionSlot: obj.garbageCollectionSlot,
});
}
static toEncodable(fields: FunctionRequestInitAndTriggerParamsFields) {
return {
bounty: fields.bounty,
slotsUntilExpiration: fields.slotsUntilExpiration,
maxContainerParamsLen: fields.maxContainerParamsLen,
containerParams:
(fields.containerParams &&
Buffer.from(
fields.containerParams.buffer,
fields.containerParams.byteOffset,
fields.containerParams.length
)) ||
null,
garbageCollectionSlot: fields.garbageCollectionSlot,
};
}
toJSON(): FunctionRequestInitAndTriggerParamsJSON {
return {
bounty: (this.bounty && this.bounty.toString()) || null,
slotsUntilExpiration:
(this.slotsUntilExpiration && this.slotsUntilExpiration.toString()) ||
null,
maxContainerParamsLen: this.maxContainerParamsLen,
containerParams:
(this.containerParams && Array.from(this.containerParams.values())) ||
null,
garbageCollectionSlot:
(this.garbageCollectionSlot && this.garbageCollectionSlot.toString()) ||
null,
};
}
static fromJSON(
obj: FunctionRequestInitAndTriggerParamsJSON
): FunctionRequestInitAndTriggerParams {
return new FunctionRequestInitAndTriggerParams({
bounty: (obj.bounty && new BN(obj.bounty)) || null,
slotsUntilExpiration:
(obj.slotsUntilExpiration && new BN(obj.slotsUntilExpiration)) || null,
maxContainerParamsLen: obj.maxContainerParamsLen,
containerParams:
(obj.containerParams && Uint8Array.from(obj.containerParams)) || null,
garbageCollectionSlot:
(obj.garbageCollectionSlot && new BN(obj.garbageCollectionSlot)) ||
null,
});
}
toEncodable() {
return FunctionRequestInitAndTriggerParams.toEncodable(this);
}
}

View File

@ -0,0 +1,92 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestInitParamsFields {
maxContainerParamsLen: number | null;
containerParams: Uint8Array;
garbageCollectionSlot: BN | null;
}
export interface FunctionRequestInitParamsJSON {
maxContainerParamsLen: number | null;
containerParams: Array<number>;
garbageCollectionSlot: string | null;
}
export class FunctionRequestInitParams {
readonly maxContainerParamsLen: number | null;
readonly containerParams: Uint8Array;
readonly garbageCollectionSlot: BN | null;
constructor(fields: FunctionRequestInitParamsFields) {
this.maxContainerParamsLen = fields.maxContainerParamsLen;
this.containerParams = fields.containerParams;
this.garbageCollectionSlot = fields.garbageCollectionSlot;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.option(borsh.u32(), "maxContainerParamsLen"),
borsh.vecU8("containerParams"),
borsh.option(borsh.u64(), "garbageCollectionSlot"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestInitParams({
maxContainerParamsLen: obj.maxContainerParamsLen,
containerParams: new Uint8Array(
obj.containerParams.buffer,
obj.containerParams.byteOffset,
obj.containerParams.length
),
garbageCollectionSlot: obj.garbageCollectionSlot,
});
}
static toEncodable(fields: FunctionRequestInitParamsFields) {
return {
maxContainerParamsLen: fields.maxContainerParamsLen,
containerParams: Buffer.from(
fields.containerParams.buffer,
fields.containerParams.byteOffset,
fields.containerParams.length
),
garbageCollectionSlot: fields.garbageCollectionSlot,
};
}
toJSON(): FunctionRequestInitParamsJSON {
return {
maxContainerParamsLen: this.maxContainerParamsLen,
containerParams: Array.from(this.containerParams.values()),
garbageCollectionSlot:
(this.garbageCollectionSlot && this.garbageCollectionSlot.toString()) ||
null,
};
}
static fromJSON(
obj: FunctionRequestInitParamsJSON
): FunctionRequestInitParams {
return new FunctionRequestInitParams({
maxContainerParamsLen: obj.maxContainerParamsLen,
containerParams: Uint8Array.from(obj.containerParams),
garbageCollectionSlot:
(obj.garbageCollectionSlot && new BN(obj.garbageCollectionSlot)) ||
null,
});
}
toEncodable() {
return FunctionRequestInitParams.toEncodable(this);
}
}

View File

@ -0,0 +1,76 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestSetConfigParamsFields {
containerParams: Uint8Array;
appendContainerParams: boolean;
}
export interface FunctionRequestSetConfigParamsJSON {
containerParams: Array<number>;
appendContainerParams: boolean;
}
export class FunctionRequestSetConfigParams {
readonly containerParams: Uint8Array;
readonly appendContainerParams: boolean;
constructor(fields: FunctionRequestSetConfigParamsFields) {
this.containerParams = fields.containerParams;
this.appendContainerParams = fields.appendContainerParams;
}
static layout(property?: string) {
return borsh.struct(
[borsh.vecU8("containerParams"), borsh.bool("appendContainerParams")],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestSetConfigParams({
containerParams: new Uint8Array(
obj.containerParams.buffer,
obj.containerParams.byteOffset,
obj.containerParams.length
),
appendContainerParams: obj.appendContainerParams,
});
}
static toEncodable(fields: FunctionRequestSetConfigParamsFields) {
return {
containerParams: Buffer.from(
fields.containerParams.buffer,
fields.containerParams.byteOffset,
fields.containerParams.length
),
appendContainerParams: fields.appendContainerParams,
};
}
toJSON(): FunctionRequestSetConfigParamsJSON {
return {
containerParams: Array.from(this.containerParams.values()),
appendContainerParams: this.appendContainerParams,
};
}
static fromJSON(
obj: FunctionRequestSetConfigParamsJSON
): FunctionRequestSetConfigParams {
return new FunctionRequestSetConfigParams({
containerParams: Uint8Array.from(obj.containerParams),
appendContainerParams: obj.appendContainerParams,
});
}
toEncodable() {
return FunctionRequestSetConfigParams.toEncodable(this);
}
}

View File

@ -0,0 +1,74 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestTriggerParamsFields {
bounty: BN | null;
slotsUntilExpiration: BN | null;
}
export interface FunctionRequestTriggerParamsJSON {
bounty: string | null;
slotsUntilExpiration: string | null;
}
export class FunctionRequestTriggerParams {
readonly bounty: BN | null;
readonly slotsUntilExpiration: BN | null;
constructor(fields: FunctionRequestTriggerParamsFields) {
this.bounty = fields.bounty;
this.slotsUntilExpiration = fields.slotsUntilExpiration;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.option(borsh.u64(), "bounty"),
borsh.option(borsh.u64(), "slotsUntilExpiration"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestTriggerParams({
bounty: obj.bounty,
slotsUntilExpiration: obj.slotsUntilExpiration,
});
}
static toEncodable(fields: FunctionRequestTriggerParamsFields) {
return {
bounty: fields.bounty,
slotsUntilExpiration: fields.slotsUntilExpiration,
};
}
toJSON(): FunctionRequestTriggerParamsJSON {
return {
bounty: (this.bounty && this.bounty.toString()) || null,
slotsUntilExpiration:
(this.slotsUntilExpiration && this.slotsUntilExpiration.toString()) ||
null,
};
}
static fromJSON(
obj: FunctionRequestTriggerParamsJSON
): FunctionRequestTriggerParams {
return new FunctionRequestTriggerParams({
bounty: (obj.bounty && new BN(obj.bounty)) || null,
slotsUntilExpiration:
(obj.slotsUntilExpiration && new BN(obj.slotsUntilExpiration)) || null,
});
}
toEncodable() {
return FunctionRequestTriggerParams.toEncodable(this);
}
}

View File

@ -0,0 +1,158 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestTriggerRoundFields {
/** The status of the request. */
status: types.RequestStatusKind;
/** The SOL bounty in lamports used to incentivize a verifier to expedite the request. */
bounty: BN;
/** The slot the request was published */
requestSlot: BN;
/** The slot when the request was fulfilled */
fulfilledSlot: BN;
/** The slot when the request will expire and be able to be closed by the non-authority account */
expirationSlot: BN;
/** The EnclaveAccount who verified the enclave for this request */
verifier: PublicKey;
/**
* The keypair generated in the enclave and required to sign any
* valid transactions processed by the function.
*/
enclaveSigner: PublicKey;
/** Reserved. */
ebuf: Array<number>;
}
export interface FunctionRequestTriggerRoundJSON {
/** The status of the request. */
status: types.RequestStatusJSON;
/** The SOL bounty in lamports used to incentivize a verifier to expedite the request. */
bounty: string;
/** The slot the request was published */
requestSlot: string;
/** The slot when the request was fulfilled */
fulfilledSlot: string;
/** The slot when the request will expire and be able to be closed by the non-authority account */
expirationSlot: string;
/** The EnclaveAccount who verified the enclave for this request */
verifier: string;
/**
* The keypair generated in the enclave and required to sign any
* valid transactions processed by the function.
*/
enclaveSigner: string;
/** Reserved. */
ebuf: Array<number>;
}
export class FunctionRequestTriggerRound {
/** The status of the request. */
readonly status: types.RequestStatusKind;
/** The SOL bounty in lamports used to incentivize a verifier to expedite the request. */
readonly bounty: BN;
/** The slot the request was published */
readonly requestSlot: BN;
/** The slot when the request was fulfilled */
readonly fulfilledSlot: BN;
/** The slot when the request will expire and be able to be closed by the non-authority account */
readonly expirationSlot: BN;
/** The EnclaveAccount who verified the enclave for this request */
readonly verifier: PublicKey;
/**
* The keypair generated in the enclave and required to sign any
* valid transactions processed by the function.
*/
readonly enclaveSigner: PublicKey;
/** Reserved. */
readonly ebuf: Array<number>;
constructor(fields: FunctionRequestTriggerRoundFields) {
this.status = fields.status;
this.bounty = fields.bounty;
this.requestSlot = fields.requestSlot;
this.fulfilledSlot = fields.fulfilledSlot;
this.expirationSlot = fields.expirationSlot;
this.verifier = fields.verifier;
this.enclaveSigner = fields.enclaveSigner;
this.ebuf = fields.ebuf;
}
static layout(property?: string) {
return borsh.struct(
[
types.RequestStatus.layout("status"),
borsh.u64("bounty"),
borsh.u64("requestSlot"),
borsh.u64("fulfilledSlot"),
borsh.u64("expirationSlot"),
borsh.publicKey("verifier"),
borsh.publicKey("enclaveSigner"),
borsh.array(borsh.u8(), 64, "ebuf"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestTriggerRound({
status: types.RequestStatus.fromDecoded(obj.status),
bounty: obj.bounty,
requestSlot: obj.requestSlot,
fulfilledSlot: obj.fulfilledSlot,
expirationSlot: obj.expirationSlot,
verifier: obj.verifier,
enclaveSigner: obj.enclaveSigner,
ebuf: obj.ebuf,
});
}
static toEncodable(fields: FunctionRequestTriggerRoundFields) {
return {
status: fields.status.toEncodable(),
bounty: fields.bounty,
requestSlot: fields.requestSlot,
fulfilledSlot: fields.fulfilledSlot,
expirationSlot: fields.expirationSlot,
verifier: fields.verifier,
enclaveSigner: fields.enclaveSigner,
ebuf: fields.ebuf,
};
}
toJSON(): FunctionRequestTriggerRoundJSON {
return {
status: this.status.toJSON(),
bounty: this.bounty.toString(),
requestSlot: this.requestSlot.toString(),
fulfilledSlot: this.fulfilledSlot.toString(),
expirationSlot: this.expirationSlot.toString(),
verifier: this.verifier.toString(),
enclaveSigner: this.enclaveSigner.toString(),
ebuf: this.ebuf,
};
}
static fromJSON(
obj: FunctionRequestTriggerRoundJSON
): FunctionRequestTriggerRound {
return new FunctionRequestTriggerRound({
status: types.RequestStatus.fromJSON(obj.status),
bounty: new BN(obj.bounty),
requestSlot: new BN(obj.requestSlot),
fulfilledSlot: new BN(obj.fulfilledSlot),
expirationSlot: new BN(obj.expirationSlot),
verifier: new PublicKey(obj.verifier),
enclaveSigner: new PublicKey(obj.enclaveSigner),
ebuf: obj.ebuf,
});
}
toEncodable() {
return FunctionRequestTriggerRound.toEncodable(this);
}
}

View File

@ -0,0 +1,98 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionRequestVerifyParamsFields {
observedTime: BN;
isFailure: boolean;
mrEnclave: Array<number>;
requestSlot: BN;
containerParamsHash: Array<number>;
}
export interface FunctionRequestVerifyParamsJSON {
observedTime: string;
isFailure: boolean;
mrEnclave: Array<number>;
requestSlot: string;
containerParamsHash: Array<number>;
}
export class FunctionRequestVerifyParams {
readonly observedTime: BN;
readonly isFailure: boolean;
readonly mrEnclave: Array<number>;
readonly requestSlot: BN;
readonly containerParamsHash: Array<number>;
constructor(fields: FunctionRequestVerifyParamsFields) {
this.observedTime = fields.observedTime;
this.isFailure = fields.isFailure;
this.mrEnclave = fields.mrEnclave;
this.requestSlot = fields.requestSlot;
this.containerParamsHash = fields.containerParamsHash;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.i64("observedTime"),
borsh.bool("isFailure"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
borsh.u64("requestSlot"),
borsh.array(borsh.u8(), 32, "containerParamsHash"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionRequestVerifyParams({
observedTime: obj.observedTime,
isFailure: obj.isFailure,
mrEnclave: obj.mrEnclave,
requestSlot: obj.requestSlot,
containerParamsHash: obj.containerParamsHash,
});
}
static toEncodable(fields: FunctionRequestVerifyParamsFields) {
return {
observedTime: fields.observedTime,
isFailure: fields.isFailure,
mrEnclave: fields.mrEnclave,
requestSlot: fields.requestSlot,
containerParamsHash: fields.containerParamsHash,
};
}
toJSON(): FunctionRequestVerifyParamsJSON {
return {
observedTime: this.observedTime.toString(),
isFailure: this.isFailure,
mrEnclave: this.mrEnclave,
requestSlot: this.requestSlot.toString(),
containerParamsHash: this.containerParamsHash,
};
}
static fromJSON(
obj: FunctionRequestVerifyParamsJSON
): FunctionRequestVerifyParams {
return new FunctionRequestVerifyParams({
observedTime: new BN(obj.observedTime),
isFailure: obj.isFailure,
mrEnclave: obj.mrEnclave,
requestSlot: new BN(obj.requestSlot),
containerParamsHash: obj.containerParamsHash,
});
}
toEncodable() {
return FunctionRequestVerifyParams.toEncodable(this);
}
}

View File

@ -12,6 +12,11 @@ export interface FunctionSetConfigParamsFields {
containerRegistry: Uint8Array | null;
version: Uint8Array | null;
schedule: Uint8Array | null;
mrEnclaves: Array<Array<number>> | null;
requestsDisabled: boolean | null;
requestsRequireAuthorization: boolean | null;
requestsDefaultSlotsUntilExpiration: BN | null;
requestsFee: BN | null;
}
export interface FunctionSetConfigParamsJSON {
@ -21,6 +26,11 @@ export interface FunctionSetConfigParamsJSON {
containerRegistry: Array<number> | null;
version: Array<number> | null;
schedule: Array<number> | null;
mrEnclaves: Array<Array<number>> | null;
requestsDisabled: boolean | null;
requestsRequireAuthorization: boolean | null;
requestsDefaultSlotsUntilExpiration: string | null;
requestsFee: string | null;
}
export class FunctionSetConfigParams {
@ -30,6 +40,11 @@ export class FunctionSetConfigParams {
readonly containerRegistry: Uint8Array | null;
readonly version: Uint8Array | null;
readonly schedule: Uint8Array | null;
readonly mrEnclaves: Array<Array<number>> | null;
readonly requestsDisabled: boolean | null;
readonly requestsRequireAuthorization: boolean | null;
readonly requestsDefaultSlotsUntilExpiration: BN | null;
readonly requestsFee: BN | null;
constructor(fields: FunctionSetConfigParamsFields) {
this.name = fields.name;
@ -38,6 +53,12 @@ export class FunctionSetConfigParams {
this.containerRegistry = fields.containerRegistry;
this.version = fields.version;
this.schedule = fields.schedule;
this.mrEnclaves = fields.mrEnclaves;
this.requestsDisabled = fields.requestsDisabled;
this.requestsRequireAuthorization = fields.requestsRequireAuthorization;
this.requestsDefaultSlotsUntilExpiration =
fields.requestsDefaultSlotsUntilExpiration;
this.requestsFee = fields.requestsFee;
}
static layout(property?: string) {
@ -49,6 +70,11 @@ export class FunctionSetConfigParams {
borsh.option(borsh.vecU8(), "containerRegistry"),
borsh.option(borsh.vecU8(), "version"),
borsh.option(borsh.vecU8(), "schedule"),
borsh.option(borsh.vec(borsh.array(borsh.u8(), 32)), "mrEnclaves"),
borsh.option(borsh.bool(), "requestsDisabled"),
borsh.option(borsh.bool(), "requestsRequireAuthorization"),
borsh.option(borsh.u64(), "requestsDefaultSlotsUntilExpiration"),
borsh.option(borsh.u64(), "requestsFee"),
],
property
);
@ -105,6 +131,12 @@ export class FunctionSetConfigParams {
obj.schedule.length
)) ||
null,
mrEnclaves: obj.mrEnclaves,
requestsDisabled: obj.requestsDisabled,
requestsRequireAuthorization: obj.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
obj.requestsDefaultSlotsUntilExpiration,
requestsFee: obj.requestsFee,
});
}
@ -158,6 +190,12 @@ export class FunctionSetConfigParams {
fields.schedule.length
)) ||
null,
mrEnclaves: fields.mrEnclaves,
requestsDisabled: fields.requestsDisabled,
requestsRequireAuthorization: fields.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
fields.requestsDefaultSlotsUntilExpiration,
requestsFee: fields.requestsFee,
};
}
@ -173,6 +211,14 @@ export class FunctionSetConfigParams {
null,
version: (this.version && Array.from(this.version.values())) || null,
schedule: (this.schedule && Array.from(this.schedule.values())) || null,
mrEnclaves: this.mrEnclaves,
requestsDisabled: this.requestsDisabled,
requestsRequireAuthorization: this.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
(this.requestsDefaultSlotsUntilExpiration &&
this.requestsDefaultSlotsUntilExpiration.toString()) ||
null,
requestsFee: (this.requestsFee && this.requestsFee.toString()) || null,
};
}
@ -186,6 +232,14 @@ export class FunctionSetConfigParams {
null,
version: (obj.version && Uint8Array.from(obj.version)) || null,
schedule: (obj.schedule && Uint8Array.from(obj.schedule)) || null,
mrEnclaves: obj.mrEnclaves,
requestsDisabled: obj.requestsDisabled,
requestsRequireAuthorization: obj.requestsRequireAuthorization,
requestsDefaultSlotsUntilExpiration:
(obj.requestsDefaultSlotsUntilExpiration &&
new BN(obj.requestsDefaultSlotsUntilExpiration)) ||
null,
requestsFee: (obj.requestsFee && new BN(obj.requestsFee)) || null,
});
}

View File

@ -0,0 +1,212 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface NoneJSON {
kind: "None";
}
export class None {
static readonly discriminator = 0;
static readonly kind = "None";
readonly discriminator = 0;
readonly kind = "None";
toJSON(): NoneJSON {
return {
kind: "None",
};
}
toEncodable() {
return {
None: {},
};
}
}
export interface RequestPendingJSON {
kind: "RequestPending";
}
export class RequestPending {
static readonly discriminator = 1;
static readonly kind = "RequestPending";
readonly discriminator = 1;
readonly kind = "RequestPending";
toJSON(): RequestPendingJSON {
return {
kind: "RequestPending",
};
}
toEncodable() {
return {
RequestPending: {},
};
}
}
export interface RequestCancelledJSON {
kind: "RequestCancelled";
}
export class RequestCancelled {
static readonly discriminator = 2;
static readonly kind = "RequestCancelled";
readonly discriminator = 2;
readonly kind = "RequestCancelled";
toJSON(): RequestCancelledJSON {
return {
kind: "RequestCancelled",
};
}
toEncodable() {
return {
RequestCancelled: {},
};
}
}
export interface RequestFailureJSON {
kind: "RequestFailure";
}
export class RequestFailure {
static readonly discriminator = 3;
static readonly kind = "RequestFailure";
readonly discriminator = 3;
readonly kind = "RequestFailure";
toJSON(): RequestFailureJSON {
return {
kind: "RequestFailure",
};
}
toEncodable() {
return {
RequestFailure: {},
};
}
}
export interface RequestExpiredJSON {
kind: "RequestExpired";
}
export class RequestExpired {
static readonly discriminator = 4;
static readonly kind = "RequestExpired";
readonly discriminator = 4;
readonly kind = "RequestExpired";
toJSON(): RequestExpiredJSON {
return {
kind: "RequestExpired",
};
}
toEncodable() {
return {
RequestExpired: {},
};
}
}
export interface RequestSuccessJSON {
kind: "RequestSuccess";
}
export class RequestSuccess {
static readonly discriminator = 5;
static readonly kind = "RequestSuccess";
readonly discriminator = 5;
readonly kind = "RequestSuccess";
toJSON(): RequestSuccessJSON {
return {
kind: "RequestSuccess",
};
}
toEncodable() {
return {
RequestSuccess: {},
};
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function fromDecoded(obj: any): types.RequestStatusKind {
if (typeof obj !== "object") {
throw new Error("Invalid enum object");
}
if ("None" in obj) {
return new None();
}
if ("RequestPending" in obj) {
return new RequestPending();
}
if ("RequestCancelled" in obj) {
return new RequestCancelled();
}
if ("RequestFailure" in obj) {
return new RequestFailure();
}
if ("RequestExpired" in obj) {
return new RequestExpired();
}
if ("RequestSuccess" in obj) {
return new RequestSuccess();
}
throw new Error("Invalid enum object");
}
export function fromJSON(
obj: types.RequestStatusJSON
): types.RequestStatusKind {
switch (obj.kind) {
case "None": {
return new None();
}
case "RequestPending": {
return new RequestPending();
}
case "RequestCancelled": {
return new RequestCancelled();
}
case "RequestFailure": {
return new RequestFailure();
}
case "RequestExpired": {
return new RequestExpired();
}
case "RequestSuccess": {
return new RequestSuccess();
}
}
}
export function layout(property?: string) {
const ret = borsh.rustEnum([
borsh.struct([], "None"),
borsh.struct([], "RequestPending"),
borsh.struct([], "RequestCancelled"),
borsh.struct([], "RequestFailure"),
borsh.struct([], "RequestExpired"),
borsh.struct([], "RequestSuccess"),
]);
if (property !== undefined) {
return ret.replicate(property);
}
return ret;
}

View File

@ -5,6 +5,29 @@ import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface NoneJSON {
kind: "None";
}
export class None {
static readonly discriminator = 0;
static readonly kind = "None";
readonly discriminator = 0;
readonly kind = "None";
toJSON(): NoneJSON {
return {
kind: "None",
};
}
toEncodable() {
return {
None: {},
};
}
}
export interface PermitNodeheartbeatJSON {
kind: "PermitNodeheartbeat";
}
@ -59,6 +82,9 @@ export function fromDecoded(
throw new Error("Invalid enum object");
}
if ("None" in obj) {
return new None();
}
if ("PermitNodeheartbeat" in obj) {
return new PermitNodeheartbeat();
}
@ -73,6 +99,9 @@ export function fromJSON(
obj: types.SwitchboardAttestationPermissionJSON
): types.SwitchboardAttestationPermissionKind {
switch (obj.kind) {
case "None": {
return new None();
}
case "PermitNodeheartbeat": {
return new PermitNodeheartbeat();
}
@ -84,6 +113,7 @@ export function fromJSON(
export function layout(property?: string) {
const ret = borsh.rustEnum([
borsh.struct([], "None"),
borsh.struct([], "PermitNodeheartbeat"),
borsh.struct([], "PermitQueueUsage"),
]);

View File

@ -1,4 +1,5 @@
import * as FunctionStatus from "./FunctionStatus.js";
import * as RequestStatus from "./RequestStatus.js";
import * as SwitchboardAttestationPermission from "./SwitchboardAttestationPermission.js";
import * as VerificationStatus from "./VerificationStatus.js";
@ -27,6 +28,11 @@ export type {
AttestationQueueRemoveMrEnclaveParamsJSON,
} from "./AttestationQueueRemoveMrEnclaveParams.js";
export { AttestationQueueRemoveMrEnclaveParams } from "./AttestationQueueRemoveMrEnclaveParams.js";
export type {
FunctionCloseParamsFields,
FunctionCloseParamsJSON,
} from "./FunctionCloseParams.js";
export { FunctionCloseParams } from "./FunctionCloseParams.js";
export type {
FunctionFundParamsFields,
FunctionFundParamsJSON,
@ -37,6 +43,41 @@ export type {
FunctionInitParamsJSON,
} from "./FunctionInitParams.js";
export { FunctionInitParams } from "./FunctionInitParams.js";
export type {
FunctionRequestCloseParamsFields,
FunctionRequestCloseParamsJSON,
} from "./FunctionRequestCloseParams.js";
export { FunctionRequestCloseParams } from "./FunctionRequestCloseParams.js";
export type {
FunctionRequestInitAndTriggerParamsFields,
FunctionRequestInitAndTriggerParamsJSON,
} from "./FunctionRequestInitAndTriggerParams.js";
export { FunctionRequestInitAndTriggerParams } from "./FunctionRequestInitAndTriggerParams.js";
export type {
FunctionRequestInitParamsFields,
FunctionRequestInitParamsJSON,
} from "./FunctionRequestInitParams.js";
export { FunctionRequestInitParams } from "./FunctionRequestInitParams.js";
export type {
FunctionRequestSetConfigParamsFields,
FunctionRequestSetConfigParamsJSON,
} from "./FunctionRequestSetConfigParams.js";
export { FunctionRequestSetConfigParams } from "./FunctionRequestSetConfigParams.js";
export type {
FunctionRequestTriggerParamsFields,
FunctionRequestTriggerParamsJSON,
} from "./FunctionRequestTriggerParams.js";
export { FunctionRequestTriggerParams } from "./FunctionRequestTriggerParams.js";
export type {
FunctionRequestTriggerRoundFields,
FunctionRequestTriggerRoundJSON,
} from "./FunctionRequestTriggerRound.js";
export { FunctionRequestTriggerRound } from "./FunctionRequestTriggerRound.js";
export type {
FunctionRequestVerifyParamsFields,
FunctionRequestVerifyParamsJSON,
} from "./FunctionRequestVerifyParams.js";
export { FunctionRequestVerifyParams } from "./FunctionRequestVerifyParams.js";
export type {
FunctionSetConfigParamsFields,
FunctionSetConfigParamsJSON,
@ -99,6 +140,23 @@ export type FunctionStatusJSON =
| FunctionStatus.OutOfFundsJSON
| FunctionStatus.InvalidPermissionsJSON;
export { RequestStatus };
export type RequestStatusKind =
| RequestStatus.None
| RequestStatus.RequestPending
| RequestStatus.RequestCancelled
| RequestStatus.RequestFailure
| RequestStatus.RequestExpired
| RequestStatus.RequestSuccess;
export type RequestStatusJSON =
| RequestStatus.NoneJSON
| RequestStatus.RequestPendingJSON
| RequestStatus.RequestCancelledJSON
| RequestStatus.RequestFailureJSON
| RequestStatus.RequestExpiredJSON
| RequestStatus.RequestSuccessJSON;
export { VerificationStatus };
export type VerificationStatusKind =
@ -117,8 +175,10 @@ export type VerificationStatusJSON =
export { SwitchboardAttestationPermission };
export type SwitchboardAttestationPermissionKind =
| SwitchboardAttestationPermission.None
| SwitchboardAttestationPermission.PermitNodeheartbeat
| SwitchboardAttestationPermission.PermitQueueUsage;
export type SwitchboardAttestationPermissionJSON =
| SwitchboardAttestationPermission.NoneJSON
| SwitchboardAttestationPermission.PermitNodeheartbeatJSON
| SwitchboardAttestationPermission.PermitQueueUsageJSON;

View File

@ -0,0 +1,219 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
import { PublicKey } from "@solana/web3.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface EnclaveAccountDataFields {
/** The address of the signer generated within an enclave. */
enclaveSigner: PublicKey;
/** The authority of the EnclaveAccount which is permitted to make account changes. */
authority: PublicKey;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
attestationQueue: PublicKey;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
mrEnclave: Array<number>;
/** The VerificationStatus of the quote. */
verificationStatus: number;
/** The unix timestamp when the quote was last verified. */
verificationTimestamp: BN;
/** The unix timestamp when the quotes verification status expires. */
validUntil: BN;
/** The unix timestamp when the quote was created. */
createdAt: BN;
/** The off-chain registry where the verifiers quote can be located. */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
/** Whether the quote is located on the AttestationQueues buffer. */
isOnQueue: boolean;
/** The last time the quote heartbeated on-chain. */
lastHeartbeat: BN;
/** The PDA bump. Only set for FunctionAccount quotes. */
bump: number;
/** Reserved. */
ebuf: Array<number>;
}
export interface EnclaveAccountDataJSON {
/** The address of the signer generated within an enclave. */
enclaveSigner: string;
/** The authority of the EnclaveAccount which is permitted to make account changes. */
authority: string;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
attestationQueue: string;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
mrEnclave: Array<number>;
/** The VerificationStatus of the quote. */
verificationStatus: number;
/** The unix timestamp when the quote was last verified. */
verificationTimestamp: string;
/** The unix timestamp when the quotes verification status expires. */
validUntil: string;
/** The unix timestamp when the quote was created. */
createdAt: string;
/** The off-chain registry where the verifiers quote can be located. */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
/** Whether the quote is located on the AttestationQueues buffer. */
isOnQueue: boolean;
/** The last time the quote heartbeated on-chain. */
lastHeartbeat: string;
/** The PDA bump. Only set for FunctionAccount quotes. */
bump: number;
/** Reserved. */
ebuf: Array<number>;
}
export class EnclaveAccountData {
/** The address of the signer generated within an enclave. */
readonly enclaveSigner: PublicKey;
/** The authority of the EnclaveAccount which is permitted to make account changes. */
readonly authority: PublicKey;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
readonly attestationQueue: PublicKey;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
readonly mrEnclave: Array<number>;
/** The VerificationStatus of the quote. */
readonly verificationStatus: number;
/** The unix timestamp when the quote was last verified. */
readonly verificationTimestamp: BN;
/** The unix timestamp when the quotes verification status expires. */
readonly validUntil: BN;
/** The unix timestamp when the quote was created. */
readonly createdAt: BN;
/** The off-chain registry where the verifiers quote can be located. */
readonly quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
readonly registryKey: Array<number>;
/** Whether the quote is located on the AttestationQueues buffer. */
readonly isOnQueue: boolean;
/** The last time the quote heartbeated on-chain. */
readonly lastHeartbeat: BN;
/** The PDA bump. Only set for FunctionAccount quotes. */
readonly bump: number;
/** Reserved. */
readonly ebuf: Array<number>;
constructor(fields: EnclaveAccountDataFields) {
this.enclaveSigner = fields.enclaveSigner;
this.authority = fields.authority;
this.attestationQueue = fields.attestationQueue;
this.mrEnclave = fields.mrEnclave;
this.verificationStatus = fields.verificationStatus;
this.verificationTimestamp = fields.verificationTimestamp;
this.validUntil = fields.validUntil;
this.createdAt = fields.createdAt;
this.quoteRegistry = fields.quoteRegistry;
this.registryKey = fields.registryKey;
this.isOnQueue = fields.isOnQueue;
this.lastHeartbeat = fields.lastHeartbeat;
this.bump = fields.bump;
this.ebuf = fields.ebuf;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.publicKey("enclaveSigner"),
borsh.publicKey("authority"),
borsh.publicKey("attestationQueue"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
borsh.u8("verificationStatus"),
borsh.i64("verificationTimestamp"),
borsh.i64("validUntil"),
borsh.i64("createdAt"),
borsh.array(borsh.u8(), 32, "quoteRegistry"),
borsh.array(borsh.u8(), 64, "registryKey"),
borsh.bool("isOnQueue"),
borsh.i64("lastHeartbeat"),
borsh.u8("bump"),
borsh.array(borsh.u8(), 1024, "ebuf"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new EnclaveAccountData({
enclaveSigner: obj.enclaveSigner,
authority: obj.authority,
attestationQueue: obj.attestationQueue,
mrEnclave: obj.mrEnclave,
verificationStatus: obj.verificationStatus,
verificationTimestamp: obj.verificationTimestamp,
validUntil: obj.validUntil,
createdAt: obj.createdAt,
quoteRegistry: obj.quoteRegistry,
registryKey: obj.registryKey,
isOnQueue: obj.isOnQueue,
lastHeartbeat: obj.lastHeartbeat,
bump: obj.bump,
ebuf: obj.ebuf,
});
}
static toEncodable(fields: EnclaveAccountDataFields) {
return {
enclaveSigner: fields.enclaveSigner,
authority: fields.authority,
attestationQueue: fields.attestationQueue,
mrEnclave: fields.mrEnclave,
verificationStatus: fields.verificationStatus,
verificationTimestamp: fields.verificationTimestamp,
validUntil: fields.validUntil,
createdAt: fields.createdAt,
quoteRegistry: fields.quoteRegistry,
registryKey: fields.registryKey,
isOnQueue: fields.isOnQueue,
lastHeartbeat: fields.lastHeartbeat,
bump: fields.bump,
ebuf: fields.ebuf,
};
}
toJSON(): EnclaveAccountDataJSON {
return {
enclaveSigner: this.enclaveSigner.toString(),
authority: this.authority.toString(),
attestationQueue: this.attestationQueue.toString(),
mrEnclave: this.mrEnclave,
verificationStatus: this.verificationStatus,
verificationTimestamp: this.verificationTimestamp.toString(),
validUntil: this.validUntil.toString(),
createdAt: this.createdAt.toString(),
quoteRegistry: this.quoteRegistry,
registryKey: this.registryKey,
isOnQueue: this.isOnQueue,
lastHeartbeat: this.lastHeartbeat.toString(),
bump: this.bump,
ebuf: this.ebuf,
};
}
static fromJSON(obj: EnclaveAccountDataJSON): EnclaveAccountData {
return new EnclaveAccountData({
enclaveSigner: new PublicKey(obj.enclaveSigner),
authority: new PublicKey(obj.authority),
attestationQueue: new PublicKey(obj.attestationQueue),
mrEnclave: obj.mrEnclave,
verificationStatus: obj.verificationStatus,
verificationTimestamp: new BN(obj.verificationTimestamp),
validUntil: new BN(obj.validUntil),
createdAt: new BN(obj.createdAt),
quoteRegistry: obj.quoteRegistry,
registryKey: obj.registryKey,
isOnQueue: obj.isOnQueue,
lastHeartbeat: new BN(obj.lastHeartbeat),
bump: obj.bump,
ebuf: obj.ebuf,
});
}
toEncodable() {
return EnclaveAccountData.toEncodable(this);
}
}

View File

@ -2,7 +2,7 @@ import "mocha";
import { functionVerify } from "../src/generated/index.js";
import * as sbv2 from "../src/index.js";
import { QuoteAccount } from "../src/index.js";
import { AttestationQueueAccount, EnclaveAccount } from "../src/index.js";
import { setupTest, TestContext } from "./utils.js";
@ -17,8 +17,8 @@ const unixTimestamp = () => Math.floor(Date.now() / 1000);
describe("Function Tests", () => {
let ctx: TestContext;
let attestationQueueAccount: sbv2.AttestationQueueAccount;
let attestationQuoteVerifierAccount: sbv2.QuoteAccount;
let attestationQueueAccount: AttestationQueueAccount;
let attestationQuoteVerifierAccount: EnclaveAccount;
const quoteVerifierKeypair = Keypair.generate();
const quoteVerifierSigner = Keypair.generate();
@ -76,14 +76,14 @@ describe("Function Tests", () => {
);
await attestationQuoteVerifierAccount.rotate({
securedSigner: quoteVerifierSigner,
enclaveSigner: quoteVerifierSigner,
authority: ctx.payer,
registryKey: new Uint8Array(Array(64).fill(1)),
});
const quoteData1 = await attestationQuoteVerifierAccount.loadData();
assert(
quoteData1.securedSigner.equals(quoteVerifierSigner.publicKey),
quoteData1.enclaveSigner.equals(quoteVerifierSigner.publicKey),
"QuoteAuthorityMismatch"
);
assert(
@ -93,7 +93,7 @@ describe("Function Tests", () => {
// join the queue so we can verify other quotes
await attestationQuoteVerifierAccount.heartbeat({
securedSigner: quoteVerifierSigner,
enclaveSigner: quoteVerifierSigner,
});
});
@ -139,11 +139,11 @@ describe("Function Tests", () => {
});
it("Verifies the function's quote", async () => {
const [functionQuoteAccount] = functionAccount.getQuoteAccount();
const [functionQuoteAccount] = functionAccount.getEnclaveAccount();
const initialQuoteState = await functionQuoteAccount.loadData();
const initialVerificationStatus =
QuoteAccount.getVerificationStatus(initialQuoteState);
EnclaveAccount.getVerificationStatus(initialQuoteState);
assert(
initialVerificationStatus.kind === "None",
@ -159,7 +159,7 @@ describe("Function Tests", () => {
const finalQuoteState = await functionQuoteAccount.loadData();
const finalVerificationStatus =
QuoteAccount.getVerificationStatus(finalQuoteState);
EnclaveAccount.getVerificationStatus(finalQuoteState);
assert(
finalVerificationStatus.kind === "VerificationSuccess",
@ -270,7 +270,6 @@ describe("Function Tests", () => {
attestationQueuePubkey,
functionPubkey,
escrowPubkey,
fnPermission,
fnQuote,
} = sbv2.FunctionAccount.decodeAddressLookup(lookupTable);
@ -287,8 +286,8 @@ describe("Function Tests", () => {
},
{
function: functionAccount.publicKey,
fnSigner: trustedSigner.publicKey,
securedSigner: quoteVerifierSigner.publicKey,
functionEnclaveSigner: trustedSigner.publicKey,
verifierEnclaveSigner: quoteVerifierSigner.publicKey,
verifierQuote: attestationQuoteVerifierAccount.publicKey,
attestationQueue: attestationQueuePubkey,
escrow: escrowPubkey,
@ -302,12 +301,9 @@ describe("Function Tests", () => {
ctx.payer.publicKey,
ctx.payer.publicKey
)[0].publicKey,
fnPermission: fnPermission,
state: statePubkey,
payer: ctx.payer.publicKey,
fnQuote: fnQuote,
tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
systemProgram: anchor.web3.SystemProgram.programId,
}
);
};
@ -385,7 +381,7 @@ describe("Function Tests", () => {
const preFunctionData = await functionAccount.loadData();
assert(
preFunctionData.isTriggered === false,
preFunctionData.isTriggered === 0,
"Function should be originally untriggered"
);
@ -393,7 +389,7 @@ describe("Function Tests", () => {
const postFunctionData = await functionAccount.loadData();
assert(
postFunctionData.isTriggered === true,
postFunctionData.isTriggered === 1,
"Function should have been triggered"
);
});

View File

@ -20,13 +20,13 @@ describe("Attestation Oracle Tests", () => {
let queueAccount: sbv2.QueueAccount;
let oracleAccount: sbv2.OracleAccount;
let oracleQuoteAccount: sbv2.QuoteAccount;
let oracleQuoteAccount: sbv2.EnclaveAccount;
const oracleQuoteKeypair = Keypair.generate();
let attestationQueueAccount: sbv2.AttestationQueueAccount;
const quoteKeypair = Keypair.generate();
const quoteSigner = Keypair.generate();
let attestationQuoteAccount: sbv2.QuoteAccount;
let attestationQuoteAccount: sbv2.EnclaveAccount;
const quoteVerifierMrEnclave = Array.from(
Buffer.from("This is the quote verifier MrEnclave")
@ -142,20 +142,20 @@ describe("Attestation Oracle Tests", () => {
});
await attestationQuoteAccount.rotate({
securedSigner: quoteSigner,
enclaveSigner: quoteSigner,
registryKey: new Uint8Array(Array(64).fill(1)),
});
const quoteState = await attestationQuoteAccount.loadData();
const verificationStatus =
sbv2.QuoteAccount.getVerificationStatus(quoteState);
sbv2.EnclaveAccount.getVerificationStatus(quoteState);
assert(
verificationStatus.kind === "VerificationOverride",
`Quote account has not been verified`
);
// join the queue so we can verify other quotes
await attestationQuoteAccount.heartbeat({ securedSigner: quoteSigner });
await attestationQuoteAccount.heartbeat({ enclaveSigner: quoteSigner });
const payer2 = Keypair.generate();
@ -185,7 +185,7 @@ describe("Attestation Oracle Tests", () => {
});
await attestationQuoteAccount2.rotate({
securedSigner: quoteSigner2,
enclaveSigner: quoteSigner2,
registryKey: new Uint8Array(Array(64).fill(1)),
authority: payer2,
});
@ -199,14 +199,14 @@ describe("Attestation Oracle Tests", () => {
const quoteState2 = await attestationQuoteAccount2.loadData();
const verificationStatus2 =
sbv2.QuoteAccount.getVerificationStatus(quoteState2);
sbv2.EnclaveAccount.getVerificationStatus(quoteState2);
assert(
verificationStatus2.kind === "VerificationSuccess",
`Quote account has not been verified`
);
// join the queue so we can verify the overrridden quote
await attestationQuoteAccount2.heartbeat({ securedSigner: quoteSigner2 });
await attestationQuoteAccount2.heartbeat({ enclaveSigner: quoteSigner2 });
await attestationQuoteAccount.verify({
timestamp: new BN(Math.floor(Date.now() / 1000)),
@ -217,7 +217,7 @@ describe("Attestation Oracle Tests", () => {
const newQuoteState = await attestationQuoteAccount.loadData();
const newVerificationStatus =
sbv2.QuoteAccount.getVerificationStatus(newQuoteState);
sbv2.EnclaveAccount.getVerificationStatus(newQuoteState);
assert(
newVerificationStatus.kind === "VerificationSuccess",
`Quote account has not been verified`

View File

@ -2,7 +2,7 @@
"extends": "../tsconfig.json",
"include": [
"../src",
"../tests"
"../test"
],
"exclude": [
"**/node_modules"
@ -16,4 +16,4 @@
"allowJs": true,
"rootDir": "../"
}
}
}

View File

@ -1,4 +1,4 @@
lockfileVersion: '6.1'
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
@ -368,26 +368,26 @@ importers:
javascript/solana.js:
dependencies:
'@coral-xyz/anchor':
specifier: ^0.27.0
version: 0.27.0
specifier: ^0.28.0
version: 0.28.0
'@coral-xyz/borsh':
specifier: ^0.27.0
version: 0.27.0(@solana/web3.js@1.73.0)
specifier: ^0.28.0
version: 0.28.0(@solana/web3.js@1.77.3)
'@solana/spl-token':
specifier: ^0.3.6
version: 0.3.6(@solana/web3.js@1.73.0)
specifier: ^0.3.8
version: 0.3.8(@solana/web3.js@1.77.3)
'@solana/web3.js':
specifier: ^1.73.0
version: 1.73.0
specifier: ^1.77.3
version: 1.77.3
'@switchboard-xyz/common':
specifier: ^2.1.46
version: 2.2.0
specifier: ^2.2.3
version: 2.2.3
cron-validator:
specifier: ^1.3.1
version: 1.3.1
dotenv:
specifier: ^16.0.3
version: 16.0.3
specifier: ^16.3.1
version: 16.3.1
lodash:
specifier: ^4.17.21
version: 4.17.21
@ -408,14 +408,14 @@ importers:
specifier: ^10.0.0
version: 10.0.0
'@types/node':
specifier: ^18.11.18
version: 18.11.18
specifier: ^20.3.1
version: 20.3.1
'@types/shelljs':
specifier: ^0.8.12
version: 0.8.12
'@typescript-eslint/eslint-plugin':
specifier: ^5.44.0
version: 5.54.1(@typescript-eslint/parser@5.54.1)(eslint@8.35.0)(typescript@4.9.4)
version: 5.54.1(@typescript-eslint/parser@5.54.1)(eslint@8.35.0)(typescript@5.1.3)
chai:
specifier: ^4.3.7
version: 4.3.7
@ -430,7 +430,7 @@ importers:
version: 8.35.0
gts:
specifier: ^3.1.1
version: 3.1.1(typescript@4.9.4)
version: 3.1.1(typescript@5.1.3)
mocha:
specifier: ^10.1.0
version: 10.1.0
@ -445,16 +445,16 @@ importers:
version: 10.0.0(mocha@10.1.0)
ts-node:
specifier: ^10.9.1
version: 10.9.1(@types/node@18.11.18)(typescript@4.9.4)
version: 10.9.1(@types/node@20.3.1)(typescript@5.1.3)
tsx:
specifier: ^3.12.7
version: 3.12.7
typedoc:
specifier: ^0.23.23
version: 0.23.23(typescript@4.9.4)
version: 0.23.23(typescript@5.1.3)
typescript:
specifier: ^4.9.4
version: 4.9.4
specifier: ^5.1.3
version: 5.1.3
rust/switchboard-solana: {}
@ -489,13 +489,6 @@ packages:
js-tokens: 4.0.0
dev: true
/@babel/runtime@7.19.4:
resolution: {integrity: sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.10
dev: false
/@babel/runtime@7.22.5:
resolution: {integrity: sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==}
engines: {node: '>=6.9.0'}
@ -884,8 +877,8 @@ packages:
resolution: {integrity: sha512-kQ02Hv2ZqxtWP30WN1d4xxT4QqlOXYDxmEd3k/bbneqhV3X5QMO4LAtoUFs7otxyivOgoqam5Il5qx81FuI4vw==}
engines: {node: '>=11'}
dependencies:
'@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.73.3)
'@solana/web3.js': 1.73.3
'@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.77.3)
'@solana/web3.js': 1.77.3
base64-js: 1.5.1
bn.js: 5.2.1
bs58: 4.0.1
@ -906,17 +899,6 @@ packages:
- utf-8-validate
dev: false
/@coral-xyz/borsh@0.27.0(@solana/web3.js@1.73.0):
resolution: {integrity: sha512-tJKzhLukghTWPLy+n8K8iJKgBq1yLT/AxaNd10yJrX8mI56ao5+OFAKAqW/h0i79KCvb4BK0VGO5ECmmolFz9A==}
engines: {node: '>=10'}
peerDependencies:
'@solana/web3.js': ^1.68.0
dependencies:
'@solana/web3.js': 1.73.0
bn.js: 5.2.1
buffer-layout: 1.2.2
dev: false
/@coral-xyz/borsh@0.27.0(@solana/web3.js@1.73.3):
resolution: {integrity: sha512-tJKzhLukghTWPLy+n8K8iJKgBq1yLT/AxaNd10yJrX8mI56ao5+OFAKAqW/h0i79KCvb4BK0VGO5ECmmolFz9A==}
engines: {node: '>=10'}
@ -928,13 +910,13 @@ packages:
buffer-layout: 1.2.2
dev: false
/@coral-xyz/borsh@0.28.0(@solana/web3.js@1.73.3):
/@coral-xyz/borsh@0.28.0(@solana/web3.js@1.77.3):
resolution: {integrity: sha512-/u1VTzw7XooK7rqeD7JLUSwOyRSesPUk0U37BV9zK0axJc1q0nRbKFGFLYCQ16OtdOJTTwGfGp11Lx9B45bRCQ==}
engines: {node: '>=10'}
peerDependencies:
'@solana/web3.js': ^1.68.0
dependencies:
'@solana/web3.js': 1.73.3
'@solana/web3.js': 1.77.3
bn.js: 5.2.1
buffer-layout: 1.2.2
dev: false
@ -1319,6 +1301,12 @@ packages:
read-yaml-file: 1.1.0
dev: true
/@noble/curves@1.1.0:
resolution: {integrity: sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==}
dependencies:
'@noble/hashes': 1.3.1
dev: false
/@noble/ed25519@1.7.1:
resolution: {integrity: sha512-Rk4SkJFaXZiznFyC/t77Q0NKS4FL7TLJJsVG2V2oiEq3kJVeTdxysEe/yRWSpnWMe808XRDJ+VFh5pt/FN5plw==}
dev: false
@ -1327,6 +1315,11 @@ packages:
resolution: {integrity: sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==}
dev: false
/@noble/hashes@1.3.1:
resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==}
engines: {node: '>= 16'}
dev: false
/@noble/secp256k1@1.7.0:
resolution: {integrity: sha512-kbacwGSsH/CTout0ZnZWxnW1B+jH/7r/WAAKLBtrRJ/+CUH7lgmQzl3GTrQua3SGKWNSDsS6lmjnDpIJ5Dxyaw==}
dev: false
@ -1415,7 +1408,7 @@ packages:
engines: {node: '>= 10'}
dependencies:
'@solana/buffer-layout': 4.0.0
'@solana/web3.js': 1.73.3
'@solana/web3.js': 1.77.3
bigint-buffer: 1.1.5
bignumber.js: 9.1.0
transitivePeerDependencies:
@ -1432,23 +1425,6 @@ packages:
buffer: 6.0.3
dev: false
/@solana/spl-token@0.3.6(@solana/web3.js@1.73.0):
resolution: {integrity: sha512-P9pTXjDIRvVbjr3J0mCnSamYqLnICeds7IoH1/Ro2R9OBuOHdp5pqKZoscfZ3UYrgnCWUc1bc9M2m/YPHjw+1g==}
engines: {node: '>=16'}
peerDependencies:
'@solana/web3.js': ^1.47.4
dependencies:
'@solana/buffer-layout': 4.0.0
'@solana/buffer-layout-utils': 0.2.0
'@solana/web3.js': 1.73.0
buffer: 6.0.3
transitivePeerDependencies:
- bufferutil
- encoding
- supports-color
- utf-8-validate
dev: false
/@solana/spl-token@0.3.6(@solana/web3.js@1.73.3):
resolution: {integrity: sha512-P9pTXjDIRvVbjr3J0mCnSamYqLnICeds7IoH1/Ro2R9OBuOHdp5pqKZoscfZ3UYrgnCWUc1bc9M2m/YPHjw+1g==}
engines: {node: '>=16'}
@ -1466,26 +1442,16 @@ packages:
- utf-8-validate
dev: false
/@solana/web3.js@1.73.0:
resolution: {integrity: sha512-YrgX3Py7ylh8NYkbanoINUPCj//bWUjYZ5/WPy9nQ9SK3Cl7QWCR+NmbDjmC/fTspZGR+VO9LTQslM++jr5PRw==}
engines: {node: '>=12.20.0'}
/@solana/spl-token@0.3.8(@solana/web3.js@1.77.3):
resolution: {integrity: sha512-ogwGDcunP9Lkj+9CODOWMiVJEdRtqHAtX2rWF62KxnnSWtMZtV9rDhTrZFshiyJmxDnRL/1nKE1yJHg4jjs3gg==}
engines: {node: '>=16'}
peerDependencies:
'@solana/web3.js': ^1.47.4
dependencies:
'@babel/runtime': 7.19.4
'@noble/ed25519': 1.7.1
'@noble/hashes': 1.1.3
'@noble/secp256k1': 1.7.0
'@solana/buffer-layout': 4.0.0
agentkeepalive: 4.2.1
bigint-buffer: 1.1.5
bn.js: 5.2.1
borsh: 0.7.0
bs58: 4.0.1
buffer: 6.0.1
fast-stable-stringify: 1.0.0
jayson: 3.7.0
node-fetch: 2.6.9
rpc-websockets: 7.5.1
superstruct: 0.14.2
'@solana/buffer-layout-utils': 0.2.0
'@solana/web3.js': 1.77.3
buffer: 6.0.3
transitivePeerDependencies:
- bufferutil
- encoding
@ -1519,6 +1485,31 @@ packages:
- utf-8-validate
dev: false
/@solana/web3.js@1.77.3:
resolution: {integrity: sha512-PHaO0BdoiQRPpieC1p31wJsBaxwIOWLh8j2ocXNKX8boCQVldt26Jqm2tZE4KlrvnCIV78owPLv1pEUgqhxZ3w==}
dependencies:
'@babel/runtime': 7.22.5
'@noble/curves': 1.1.0
'@noble/hashes': 1.3.1
'@solana/buffer-layout': 4.0.0
agentkeepalive: 4.2.1
bigint-buffer: 1.1.5
bn.js: 5.2.1
borsh: 0.7.0
bs58: 4.0.1
buffer: 6.0.3
fast-stable-stringify: 1.0.0
jayson: 4.1.0
node-fetch: 2.6.9
rpc-websockets: 7.5.1
superstruct: 0.14.2
transitivePeerDependencies:
- bufferutil
- encoding
- supports-color
- utf-8-validate
dev: false
/@switchboard-xyz/common@2.2.0:
resolution: {integrity: sha512-ciy3mSPh02e2Zk/54C8AJp7S35Z1rpyy3vyieVBB/k6bKyg0GG4snGgTGjiOAAsk/EQvxORy6S2TIwjbDa4r0g==}
engines: {node: '>=12'}
@ -1542,7 +1533,7 @@ packages:
resolution: {integrity: sha512-E4NQf9aXdOiul+sySAbFPAW9k0qz4wRTfqrU7cEa8nRIvUkg6VIZ+5JfajHv/VfK9UOD+6ZfMBxq2+dHkiz9zw==}
engines: {node: '>=12'}
dependencies:
'@solana/web3.js': 1.73.3
'@solana/web3.js': 1.77.3
'@types/big.js': 6.1.6
'@types/bn.js': 5.1.1
big.js: 6.2.1
@ -1726,6 +1717,10 @@ packages:
resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==}
dev: true
/@types/node@20.3.1:
resolution: {integrity: sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==}
dev: true
/@types/normalize-package-data@2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
dev: true
@ -1793,6 +1788,32 @@ packages:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.3):
resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
'@typescript-eslint/parser': ^4.0.0
eslint: ^5.0.0 || ^6.0.0 || ^7.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.1.3)
'@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.3)
'@typescript-eslint/scope-manager': 4.33.0
debug: 4.3.4(supports-color@8.1.1)
eslint: 7.32.0
functional-red-black-tree: 1.0.1
ignore: 5.2.0
regexpp: 3.2.0
semver: 7.3.8
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@5.44.0(@typescript-eslint/parser@5.44.0)(eslint@8.42.0)(typescript@4.9.4):
resolution: {integrity: sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -1820,7 +1841,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@5.54.1(@typescript-eslint/parser@5.54.1)(eslint@8.35.0)(typescript@4.9.4):
/@typescript-eslint/eslint-plugin@5.54.1(@typescript-eslint/parser@5.54.1)(eslint@8.35.0)(typescript@5.1.3):
resolution: {integrity: sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -1831,10 +1852,10 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.54.1(eslint@8.35.0)(typescript@4.9.4)
'@typescript-eslint/parser': 5.54.1(eslint@8.35.0)(typescript@5.1.3)
'@typescript-eslint/scope-manager': 5.54.1
'@typescript-eslint/type-utils': 5.54.1(eslint@8.35.0)(typescript@4.9.4)
'@typescript-eslint/utils': 5.54.1(eslint@8.35.0)(typescript@4.9.4)
'@typescript-eslint/type-utils': 5.54.1(eslint@8.35.0)(typescript@5.1.3)
'@typescript-eslint/utils': 5.54.1(eslint@8.35.0)(typescript@5.1.3)
debug: 4.3.4(supports-color@8.1.1)
eslint: 8.35.0
grapheme-splitter: 1.0.4
@ -1842,8 +1863,8 @@ packages:
natural-compare-lite: 1.4.0
regexpp: 3.2.0
semver: 7.3.8
tsutils: 3.21.0(typescript@4.9.4)
typescript: 4.9.4
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
@ -1894,6 +1915,44 @@ packages:
- typescript
dev: true
/@typescript-eslint/experimental-utils@4.33.0(eslint@7.32.0)(typescript@5.1.3):
resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
eslint: '*'
dependencies:
'@types/json-schema': 7.0.11
'@typescript-eslint/scope-manager': 4.33.0
'@typescript-eslint/types': 4.33.0
'@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.3)
eslint: 7.32.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0(eslint@7.32.0)
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.1.3):
resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
eslint: ^5.0.0 || ^6.0.0 || ^7.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 4.33.0
'@typescript-eslint/types': 4.33.0
'@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.3)
debug: 4.3.4(supports-color@8.1.1)
eslint: 7.32.0
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser@4.33.0(eslint@8.42.0)(typescript@4.9.4):
resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -1934,7 +1993,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser@5.54.1(eslint@8.35.0)(typescript@4.9.4):
/@typescript-eslint/parser@5.54.1(eslint@8.35.0)(typescript@5.1.3):
resolution: {integrity: sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -1946,10 +2005,10 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 5.54.1
'@typescript-eslint/types': 5.54.1
'@typescript-eslint/typescript-estree': 5.54.1(typescript@4.9.4)
'@typescript-eslint/typescript-estree': 5.54.1(typescript@5.1.3)
debug: 4.3.4(supports-color@8.1.1)
eslint: 8.35.0
typescript: 4.9.4
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
@ -2018,7 +2077,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/type-utils@5.54.1(eslint@8.35.0)(typescript@4.9.4):
/@typescript-eslint/type-utils@5.54.1(eslint@8.35.0)(typescript@5.1.3):
resolution: {integrity: sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -2028,12 +2087,12 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 5.54.1(typescript@4.9.4)
'@typescript-eslint/utils': 5.54.1(eslint@8.35.0)(typescript@4.9.4)
'@typescript-eslint/typescript-estree': 5.54.1(typescript@5.1.3)
'@typescript-eslint/utils': 5.54.1(eslint@8.35.0)(typescript@5.1.3)
debug: 4.3.4(supports-color@8.1.1)
eslint: 8.35.0
tsutils: 3.21.0(typescript@4.9.4)
typescript: 4.9.4
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
@ -2094,6 +2153,27 @@ packages:
- supports-color
dev: true
/@typescript-eslint/typescript-estree@4.33.0(typescript@5.1.3):
resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 4.33.0
'@typescript-eslint/visitor-keys': 4.33.0
debug: 4.3.4(supports-color@8.1.1)
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.8
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/typescript-estree@5.44.0(typescript@4.9.4):
resolution: {integrity: sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -2136,6 +2216,27 @@ packages:
- supports-color
dev: true
/@typescript-eslint/typescript-estree@5.54.1(typescript@5.1.3):
resolution: {integrity: sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.54.1
'@typescript-eslint/visitor-keys': 5.54.1
debug: 4.3.4(supports-color@8.1.1)
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.8
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils@5.44.0(eslint@8.42.0)(typescript@4.9.4):
resolution: {integrity: sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -2156,7 +2257,7 @@ packages:
- typescript
dev: true
/@typescript-eslint/utils@5.54.1(eslint@8.35.0)(typescript@4.9.4):
/@typescript-eslint/utils@5.54.1(eslint@8.35.0)(typescript@5.1.3):
resolution: {integrity: sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -2166,7 +2267,7 @@ packages:
'@types/semver': 7.3.13
'@typescript-eslint/scope-manager': 5.54.1
'@typescript-eslint/types': 5.54.1
'@typescript-eslint/typescript-estree': 5.54.1(typescript@4.9.4)
'@typescript-eslint/typescript-estree': 5.54.1(typescript@5.1.3)
eslint: 8.35.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0(eslint@8.35.0)
@ -3055,6 +3156,11 @@ packages:
engines: {node: '>=12'}
dev: false
/dotenv@16.3.1:
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
engines: {node: '>=12'}
dev: false
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@ -4055,6 +4161,33 @@ packages:
- supports-color
dev: true
/gts@3.1.1(typescript@5.1.3):
resolution: {integrity: sha512-Jw44aBbzMnd1vtZs7tZt3LMstKQukCBg7N4CKVGzviIQ45Cz5b9lxDJGXVKj/9ySuGv6TYEeijZJGbiiVcM27w==}
engines: {node: '>=10'}
hasBin: true
peerDependencies:
typescript: '>=3'
dependencies:
'@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.3)
'@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.3)
chalk: 4.1.2
eslint: 7.32.0
eslint-config-prettier: 7.2.0(eslint@7.32.0)
eslint-plugin-node: 11.1.0(eslint@7.32.0)
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@7.2.0)(eslint@7.32.0)(prettier@2.8.0)
execa: 5.1.1
inquirer: 7.3.3
json5: 2.2.1
meow: 9.0.0
ncp: 2.0.0
prettier: 2.8.0
rimraf: 3.0.2
typescript: 5.1.3
write-file-atomic: 3.0.3
transitivePeerDependencies:
- supports-color
dev: true
/hard-rejection@2.1.0:
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
engines: {node: '>=6'}
@ -4434,6 +4567,28 @@ packages:
- utf-8-validate
dev: false
/jayson@4.1.0:
resolution: {integrity: sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==}
engines: {node: '>=8'}
hasBin: true
dependencies:
'@types/connect': 3.4.35
'@types/node': 12.20.55
'@types/ws': 7.4.7
JSONStream: 1.3.5
commander: 2.20.3
delay: 5.0.0
es6-promisify: 5.0.0
eyes: 0.1.8
isomorphic-ws: 4.0.1(ws@7.5.9)
json-stringify-safe: 5.0.1
uuid: 8.3.2
ws: 7.5.9
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: false
/js-sdsl@4.3.0:
resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==}
dev: true
@ -5426,10 +5581,6 @@ packages:
strip-indent: 3.0.0
dev: true
/regenerator-runtime@0.13.10:
resolution: {integrity: sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==}
dev: false
/regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
@ -6043,6 +6194,37 @@ packages:
yn: 3.1.1
dev: true
/ts-node@10.9.1(@types/node@20.3.1)(typescript@5.1.3):
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
'@swc/wasm': '>=1.2.50'
'@types/node': '*'
typescript: '>=2.7'
peerDependenciesMeta:
'@swc/core':
optional: true
'@swc/wasm':
optional: true
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.9
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.3
'@types/node': 20.3.1
acorn: 8.8.1
acorn-walk: 8.2.0
arg: 4.1.3
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
typescript: 5.1.3
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
dev: true
/ts-node@7.0.1:
resolution: {integrity: sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==}
engines: {node: '>=4.2.0'}
@ -6086,6 +6268,16 @@ packages:
typescript: 4.9.4
dev: true
/tsutils@3.21.0(typescript@5.1.3):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
typescript: 5.1.3
dev: true
/tsx@3.12.7:
resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==}
hasBin: true
@ -6220,7 +6412,7 @@ packages:
is-typedarray: 1.0.0
dev: true
/typedoc@0.23.23(typescript@4.9.4):
/typedoc@0.23.23(typescript@5.1.3):
resolution: {integrity: sha512-cg1YQWj+/BU6wq74iott513U16fbrPCbyYs04PHZgvoKJIc6EY4xNobyDZh4KMfRGW8Yjv6wwIzQyoqopKOUGw==}
engines: {node: '>= 14.14'}
hasBin: true
@ -6231,7 +6423,7 @@ packages:
marked: 4.2.5
minimatch: 5.1.2
shiki: 0.11.1
typescript: 4.9.4
typescript: 5.1.3
dev: true
/typescript@4.9.4:
@ -6246,6 +6438,12 @@ packages:
hasBin: true
dev: true
/typescript@5.1.3:
resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==}
engines: {node: '>=14.17'}
hasBin: true
dev: true
/unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
dependencies:
@ -6570,17 +6768,16 @@ packages:
file:javascript/solana.js:
resolution: {directory: javascript/solana.js, type: directory}
name: '@switchboard-xyz/solana.js'
version: 2.3.0-beta.7
engines: {node: '>=16.0.0', npm: '>=7.0.0'}
dependencies:
'@coral-xyz/anchor': 0.27.0
'@coral-xyz/borsh': 0.27.0(@solana/web3.js@1.73.3)
'@solana/spl-token': 0.3.6(@solana/web3.js@1.73.3)
'@solana/web3.js': 1.73.3
'@coral-xyz/anchor': 0.28.0
'@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.77.3)
'@solana/spl-token': 0.3.8(@solana/web3.js@1.77.3)
'@solana/web3.js': 1.77.3
'@switchboard-xyz/common': 2.2.3
'@switchboard-xyz/oracle': 2.1.11
cron-validator: 1.3.1
dotenv: 16.0.3
dotenv: 16.3.1
lodash: 4.17.21
transitivePeerDependencies:
- bufferutil

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "switchboard-solana"
version = "0.5.3"
version = "0.6.1"
edition = "2021"
description = "A Rust library to interact with Switchboard accounts."
readme = "README.md"
@ -21,29 +21,25 @@ no-entrypoint = []
cpi = ["no-entrypoint"]
[dependencies]
anchor-spl = "=0.26.0"
solana-program = ">= 1.13.5, < 1.14.19"
anchor-spl = "0.28.0"
solana-program = ">= 1.16.1, < 1.17"
solana-address-lookup-table-program = ">= 1.16.1, < 1.17"
rust_decimal = "^1"
bytemuck = "^1"
superslice = "1"
# These may not be needed, anchor27 keeps complaining
winnow = "=0.4.1"
toml_edit = "=0.19.8"
toml_datetime = "=0.6.1"
[target.'cfg(target_os = "solana")'.dependencies]
switchboard-common = { version = "0.5.3" }
anchor-lang = { version = "=0.26.0" }
switchboard-common = { version = "0.6" }
anchor-lang = { version = "0.28.0" }
[target.'cfg(not(target_os = "solana"))'.dependencies]
switchboard-common = { version = "0.5.3", features = ["sgx"] }
anchor-client = { version = "=0.26.0" }
switchboard-common = { version = "0.6", features = ["client"] }
anchor-client = { version = "0.28.0" }
solana-client = ">= 1.16.1, < 1.17"
bincode = { version = "^1" }
sgx-quote = { version = "0.1.0" }
cron = { version = "0.12.0" }
chrono = { version = "0.4.25" }
[package.metadata.docs.rs]
default-target = "x86_64-unknown-linux-gnu"
targets = ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu"]
rustdoc-args = ["--cfg", "doc_cfg"]

View File

@ -6,6 +6,6 @@ pub use crate::oracle_program::accounts::{
};
pub use crate::attestation_program::accounts::{
AttestationPermissionAccountData, AttestationQueueAccountData, AttestationState,
FunctionAccountData, QuoteAccountData,
AttestationPermissionAccountData, AttestationProgramState, AttestationQueueAccountData,
EnclaveAccountData, FunctionAccountData, FunctionRequestAccountData,
};

View File

@ -5,13 +5,33 @@ use std::cell::Ref;
use crate::SWITCHBOARD_ATTESTATION_PROGRAM_ID;
#[derive(Copy, Clone, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
pub enum SwitchboardAttestationPermission {
#[default]
None = 0,
PermitNodeheartbeat = 1 << 0,
PermitQueueUsage = 1 << 1,
}
impl From<SwitchboardAttestationPermission> for u32 {
fn from(value: SwitchboardAttestationPermission) -> Self {
match value {
SwitchboardAttestationPermission::PermitNodeheartbeat => 1 << 0,
SwitchboardAttestationPermission::PermitQueueUsage => 1 << 1,
_ => 0,
}
}
}
impl From<u32> for SwitchboardAttestationPermission {
fn from(value: u32) -> Self {
match value {
1 => SwitchboardAttestationPermission::PermitNodeheartbeat,
2 => SwitchboardAttestationPermission::PermitQueueUsage,
_ => SwitchboardAttestationPermission::default(),
}
}
}
#[zero_copy]
#[zero_copy(unsafe)]
#[repr(packed)]
#[derive(Debug)]
pub struct AttestationPermissionAccountData {
@ -40,6 +60,10 @@ impl Owner for AttestationPermissionAccountData {
impl ZeroCopy for AttestationPermissionAccountData {}
impl AttestationPermissionAccountData {
pub fn size() -> usize {
8 + std::mem::size_of::<AttestationPermissionAccountData>()
}
/// Returns the deserialized Switchboard AttestationPermission account
///
/// # Arguments

View File

@ -5,28 +5,39 @@ use std::cell::Ref;
use crate::SWITCHBOARD_ATTESTATION_PROGRAM_ID;
#[zero_copy]
#[zero_copy(unsafe)]
#[repr(packed)]
pub struct AttestationQueueAccountData {
// Authority controls adding/removing allowed enclave measurements
/// The address of the authority which is permitted to add/remove allowed enclave measurements.
pub authority: Pubkey,
// allowed enclave measurements
pub mr_enclaves: [MrEnclave; 32],
/// Allowed enclave measurements.
pub mr_enclaves: [[u8; 32]; 32],
/// The number of allowed enclave measurements.
pub mr_enclaves_len: u32,
/// The addresses of the quote verifiers who have a valid
/// verification status and have heartbeated on-chain recently.
pub data: [Pubkey; 128],
/// The length of valid quote verifiers for the given attestation queue.
pub data_len: u32,
// Allow authority to force add a node after X seconds with no heartbeat
/// Allow authority to force add a node after X seconds with no heartbeat.
pub allow_authority_override_after: i64,
// Even if a heartbeating machine quote verifies with proper measurement,
// require authority signoff.
/// Even if a heartbeating machine quote verifies with proper measurement,
/// require authority signoff.
pub require_authority_heartbeat_permission: bool,
/// Require FunctionAccounts to have PermitQueueUsage before they are executed.
pub require_usage_permissions: bool,
/// The maximum allowable time until a EnclaveAccount needs to be re-verified on-chain.
pub max_quote_verification_age: i64,
/// The reward paid to quote verifiers for attesting on-chain.
pub reward: u32, //TODO
/// The unix timestamp when the last quote verifier heartbeated on-chain.
pub last_heartbeat: i64,
pub node_timeout: i64,
pub node_timeout: i64, // TODO ??
/// Incrementer used to track the current quote verifier permitted to run any available functions.
pub curr_idx: u32,
/// Incrementer used to garbage collect and remove stale quote verifiers.
pub gc_idx: u32,
/// Reserved.
pub _ebuf: [u8; 1024],
}
@ -46,6 +57,10 @@ impl Owner for AttestationQueueAccountData {
impl ZeroCopy for AttestationQueueAccountData {}
impl AttestationQueueAccountData {
pub fn size() -> usize {
8 + std::mem::size_of::<AttestationQueueAccountData>()
}
/// Returns the deserialized Switchboard AttestationQueue account
///
/// # Arguments

View File

@ -4,30 +4,34 @@ use bytemuck::{Pod, Zeroable};
use crate::SWITCHBOARD_ATTESTATION_PROGRAM_ID;
#[zero_copy]
#[zero_copy(unsafe)]
#[repr(packed)]
#[derive(Debug)]
pub struct AttestationState {
pub struct AttestationProgramState {
pub bump: u8,
pub _ebuf: [u8; 2048],
}
unsafe impl Pod for AttestationState {}
unsafe impl Zeroable for AttestationState {}
unsafe impl Pod for AttestationProgramState {}
unsafe impl Zeroable for AttestationProgramState {}
impl Discriminator for AttestationState {
const DISCRIMINATOR: [u8; 8] = [216, 146, 107, 94, 104, 75, 182, 177];
impl Discriminator for AttestationProgramState {
const DISCRIMINATOR: [u8; 8] = [42, 145, 190, 11, 203, 77, 146, 231];
}
impl Owner for AttestationState {
impl Owner for AttestationProgramState {
fn owner() -> Pubkey {
SWITCHBOARD_ATTESTATION_PROGRAM_ID
}
}
impl ZeroCopy for AttestationState {}
impl ZeroCopy for AttestationProgramState {}
impl AttestationProgramState {
pub fn size() -> usize {
8 + std::mem::size_of::<AttestationProgramState>()
}
impl AttestationState {
pub fn get_pda() -> Pubkey {
let (pda_key, _) =
Pubkey::find_program_address(&[STATE_SEED], &SWITCHBOARD_ATTESTATION_PROGRAM_ID);

View File

@ -8,60 +8,97 @@ use crate::{QUOTE_SEED, SWITCHBOARD_ATTESTATION_PROGRAM_ID};
pub type MrEnclave = [u8; 32];
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
pub enum VerificationStatus {
#[default]
None = 0,
VerificationPending = 1 << 0,
VerificationFailure = 1 << 1,
VerificationSuccess = 1 << 2,
VerificationOverride = 1 << 3,
}
impl From<VerificationStatus> for u8 {
fn from(value: VerificationStatus) -> Self {
match value {
VerificationStatus::VerificationPending => 1 << 0,
VerificationStatus::VerificationFailure => 1 << 1,
VerificationStatus::VerificationSuccess => 1 << 2,
VerificationStatus::VerificationOverride => 1 << 3,
_ => 0,
}
}
}
impl From<u8> for VerificationStatus {
fn from(value: u8) -> Self {
match value {
1 => VerificationStatus::VerificationPending,
2 => VerificationStatus::VerificationFailure,
4 => VerificationStatus::VerificationSuccess,
8 => VerificationStatus::VerificationOverride,
_ => VerificationStatus::default(),
}
}
}
#[zero_copy]
#[zero_copy(unsafe)]
#[repr(packed)]
#[derive(Debug)]
pub struct QuoteAccountData {
pub secured_signer: Pubkey,
pub bump: u8,
// Set except for function quotes
/// TODO: Add description
pub quote_registry: [u8; 32],
/// Key to lookup the buffer data on IPFS or an alternative decentralized storage solution.
pub registry_key: [u8; 64],
// always set
pub struct EnclaveAccountData {
/// The address of the signer generated within an enclave.
pub enclave_signer: Pubkey,
/// The authority of the EnclaveAccount which is permitted to make account changes.
pub authority: Pubkey,
/// Queue used for attestation to verify a MRENCLAVE measurement.
pub attestation_queue: Pubkey,
/// The quotes MRENCLAVE measurement dictating the contents of the secure enclave.
pub mr_enclave: MrEnclave,
pub mr_enclave: [u8; 32],
/// The VerificationStatus of the quote.
pub verification_status: u8,
/// The unix timestamp when the quote was last verified.
pub verification_timestamp: i64,
/// The unix timestamp when the quotes verification status expires.
pub valid_until: i64,
// Set for verifiers
pub is_on_queue: bool,
/// The last time the quote heartbeated.
pub last_heartbeat: i64,
pub authority: Pubkey,
//
/// The unix timestamp when the quote was created.
pub created_at: i64,
pub _ebuf: [u8; 992],
// Quote Verifier ONLY fields
/// The off-chain registry where the verifiers quote can be located.
pub quote_registry: [u8; 32],
/// Key to lookup the buffer data on IPFS or an alternative decentralized storage solution.
pub registry_key: [u8; 64],
/// Whether the quote is located on the AttestationQueues buffer.
pub is_on_queue: bool,
/// The last time the quote heartbeated on-chain.
pub last_heartbeat: i64,
// FunctionAccount only fields
/// The PDA bump. Only set for FunctionAccount quotes.
pub bump: u8,
/// Reserved.
pub _ebuf: [u8; 1024],
}
unsafe impl Pod for QuoteAccountData {}
unsafe impl Zeroable for QuoteAccountData {}
unsafe impl Pod for EnclaveAccountData {}
unsafe impl Zeroable for EnclaveAccountData {}
impl Discriminator for QuoteAccountData {
const DISCRIMINATOR: [u8; 8] = [205, 205, 167, 232, 0, 74, 44, 160];
impl Discriminator for EnclaveAccountData {
const DISCRIMINATOR: [u8; 8] = [90, 162, 39, 88, 77, 157, 156, 165];
}
impl Owner for QuoteAccountData {
impl Owner for EnclaveAccountData {
fn owner() -> Pubkey {
SWITCHBOARD_ATTESTATION_PROGRAM_ID
}
}
impl ZeroCopy for QuoteAccountData {}
impl ZeroCopy for EnclaveAccountData {}
impl EnclaveAccountData {
pub fn size() -> usize {
8 + std::mem::size_of::<EnclaveAccountData>()
}
impl QuoteAccountData {
/// Returns the deserialized Switchboard Quote account
///
/// # Arguments
@ -71,26 +108,26 @@ impl QuoteAccountData {
/// # Examples
///
/// ```ignore
/// use switchboard_solana::QuoteAccountData;
/// use switchboard_solana::EnclaveAccountData;
///
/// let quote_account = QuoteAccountData::new(quote_account_info)?;
/// let quote_account = EnclaveAccountData::new(quote_account_info)?;
/// ```
pub fn new<'info>(
quote_account_info: &'info AccountInfo<'info>,
) -> anchor_lang::Result<Ref<'info, QuoteAccountData>> {
) -> anchor_lang::Result<Ref<'info, EnclaveAccountData>> {
let data = quote_account_info.try_borrow_data()?;
if data.len() < QuoteAccountData::discriminator().len() {
if data.len() < EnclaveAccountData::discriminator().len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let mut disc_bytes = [0u8; 8];
disc_bytes.copy_from_slice(&data[..8]);
if disc_bytes != QuoteAccountData::discriminator() {
if disc_bytes != EnclaveAccountData::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[8..std::mem::size_of::<QuoteAccountData>() + 8])
bytemuck::from_bytes(&data[8..std::mem::size_of::<EnclaveAccountData>() + 8])
}))
}
@ -103,23 +140,23 @@ impl QuoteAccountData {
/// # Examples
///
/// ```ignore
/// use switchboard_solana::QuoteAccountData;
/// use switchboard_solana::EnclaveAccountData;
///
/// let quote_account = QuoteAccountData::new(quote_account_info.try_borrow_data()?)?;
/// let quote_account = EnclaveAccountData::new(quote_account_info.try_borrow_data()?)?;
/// ```
pub fn new_from_bytes(data: &[u8]) -> anchor_lang::Result<&QuoteAccountData> {
if data.len() < QuoteAccountData::discriminator().len() {
pub fn new_from_bytes(data: &[u8]) -> anchor_lang::Result<&EnclaveAccountData> {
if data.len() < EnclaveAccountData::discriminator().len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let mut disc_bytes = [0u8; 8];
disc_bytes.copy_from_slice(&data[..8]);
if disc_bytes != QuoteAccountData::discriminator() {
if disc_bytes != EnclaveAccountData::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(bytemuck::from_bytes(
&data[8..std::mem::size_of::<QuoteAccountData>() + 8],
&data[8..std::mem::size_of::<EnclaveAccountData>() + 8],
))
}

View File

@ -1,12 +1,13 @@
use super::QuoteAccountData;
use super::EnclaveAccountData;
use crate::cfg_client;
use crate::prelude::*;
use bytemuck::{Pod, Zeroable};
use std::cell::Ref;
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
pub enum FunctionStatus {
#[default]
None = 0,
Active = 1 << 0,
NonExecutable = 1 << 1,
@ -14,28 +15,105 @@ pub enum FunctionStatus {
OutOfFunds = 1 << 3,
InvalidPermissions = 1 << 4,
}
#[zero_copy]
impl From<FunctionStatus> for u8 {
fn from(value: FunctionStatus) -> Self {
match value {
FunctionStatus::Active => 1 << 0,
FunctionStatus::NonExecutable => 1 << 1,
FunctionStatus::Expired => 1 << 2,
FunctionStatus::OutOfFunds => 1 << 3,
FunctionStatus::InvalidPermissions => 1 << 4,
_ => 0,
}
}
}
impl From<u8> for FunctionStatus {
fn from(value: u8) -> Self {
match value {
1 => FunctionStatus::Active,
2 => FunctionStatus::NonExecutable,
4 => FunctionStatus::Expired,
8 => FunctionStatus::OutOfFunds,
16 => FunctionStatus::InvalidPermissions,
_ => FunctionStatus::default(),
}
}
}
#[zero_copy(unsafe)]
#[repr(packed)]
#[derive(Debug, PartialEq)]
pub struct FunctionAccountData {
/// Whether the function is invoked on a schedule or by request
pub is_scheduled: u8, // keep this up-front for filtering
/// Whether the function has been manually triggered with the function_trigger instruction
pub is_triggered: u8, // keep this up-front for filtering
/// The function permissions granted by the attestation_queue.authority
pub permissions: u32, // keep this up-front for filtering
pub status: FunctionStatus, // keep this up-front for filtering
// Metadata
/// The name of the function for easier identification.
pub name: [u8; 64],
/// The metadata of the function for easier identification.
pub metadata: [u8; 256],
pub authority: Pubkey,
pub container_registry: [u8; 64],
pub container: [u8; 64],
pub version: [u8; 32],
pub attestation_queue: Pubkey,
pub queue_idx: u32,
pub last_execution_timestamp: i64,
pub next_allowed_timestamp: i64,
pub schedule: [u8; 64],
pub escrow: Pubkey,
pub status: FunctionStatus,
/// The unix timestamp when the function was created.
pub created_at: i64,
pub is_triggered: bool,
/// The unix timestamp when the function config (container, registry, version, or schedule) was changed.
pub updated_at: i64,
// Container Settings
/// The off-chain registry to fetch the function container from.
pub container_registry: [u8; 64],
/// The identifier of the container in the given container_registry.
pub container: [u8; 64],
/// The version tag of the container to pull.
pub version: [u8; 32],
// Accounts
/// The authority of the function which is authorized to make account changes.
pub authority: Pubkey,
/// The wrapped SOL escrow of the function to pay for scheduled requests.
pub escrow: Pubkey,
/// The address_lookup_table of the function used to increase the number of accounts we can fit into a function result.
pub address_lookup_table: Pubkey,
pub _ebuf: [u8; 991],
/// The address of the AttestationQueueAccountData that will be processing function requests and verifying the function measurements.
pub attestation_queue: Pubkey,
/// An incrementer used to rotate through an AttestationQueue's verifiers.
pub queue_idx: u32,
// Schedule
/// The cron schedule to run the function on.
pub schedule: [u8; 64],
/// The unix timestamp when the function was last run.
pub last_execution_timestamp: i64,
/// The unix timestamp when the function is allowed to run next.
pub next_allowed_timestamp: i64,
/// The number of times to trigger the function upon the next invocation.
pub trigger_count: u64,
// pub schedule_container_params: Vec<u8>,
// Permission Settings
/// UNUSED. The unix timestamp when the current permissions expire.
pub permission_expiration: i64,
// Request Settings
/// Number of requests created for this function. Used to prevent closing when there are live requests.
pub num_requests: u64,
/// Whether custom requests have been disabled for this function.
pub requests_disabled: bool,
/// Whether new requests need to be authorized by the FunctionAccount authority before being initialized.
/// Useful if you want to use CPIs to control request account creation.
pub requests_require_authorization: bool,
/// The number of slots after a request has been verified before allowing a non-authority account to close the account.
/// Useful if you want to submit multiple txns in your custom function and need the account to be kept alive for multiple slots.
pub requests_default_slots_until_expiration: u64,
/// The lamports paid to the FunctionAccount escrow on each successful update request.
pub requests_fee: u64,
/// An array of permitted mr_enclave measurements for the function.
pub mr_enclaves: [[u8; 32]; 32],
/// Reserved.
pub _ebuf: [u8; 1024],
}
unsafe impl Pod for FunctionAccountData {}
@ -54,6 +132,10 @@ impl Owner for FunctionAccountData {
impl ZeroCopy for FunctionAccountData {}
impl FunctionAccountData {
pub fn size() -> usize {
8 + std::mem::size_of::<FunctionAccountData>()
}
/// Returns the deserialized Switchboard Function account
///
/// # Arguments
@ -115,36 +197,88 @@ impl FunctionAccountData {
))
}
pub fn get_enclave_pda(fn_key: &Pubkey) -> Pubkey {
let (pda_key, _) = Pubkey::find_program_address(
&[QUOTE_SEED, &fn_key.to_bytes()],
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
);
pda_key
}
pub fn get_escrow_key(fn_key: &Pubkey) -> Pubkey {
let (ata_key, _) = Pubkey::find_program_address(
&[
&fn_key.to_bytes(),
&anchor_spl::token::ID.to_bytes(),
&anchor_spl::token::spl_token::native_mint::ID.to_bytes(),
],
&anchor_spl::associated_token::AssociatedToken::id(),
);
ata_key
}
/// Validate that the provided accounts correspond to the expected function accounts
///
/// # Arguments
///
/// * `function_account_info` - Solana AccountInfo for a FunctionAccountData
/// * `quote_account_info` - Solana AccountInfo for a QuoteAccountData
/// * `enclave_account_info` - Solana AccountInfo for a EnclaveAccountData
/// * `signer` - Solana AccountInfo for a signer
pub fn validate_quote<'a>(
function_account_info: &'a AccountInfo<'a>,
quote_account_info: &'a AccountInfo<'a>,
pub fn validate_enclave<'a>(
function_account_info: &AccountInfo<'a>,
enclave_account_info: &AccountInfo<'a>,
signer: &AccountInfo<'a>,
) -> anchor_lang::Result<bool> {
// deserialize accounts and verify the owner
FunctionAccountData::new(function_account_info)?;
let quote = QuoteAccountData::new(quote_account_info)?;
// validate function PDA matches the expected derivation
let expected_quote_key = QuoteAccountData::get_pda_pubkey(&function_account_info.key())?;
if quote_account_info.key() != expected_quote_key {
let expected_enclave_key =
EnclaveAccountData::get_pda_pubkey(&function_account_info.key())?;
if enclave_account_info.key() != expected_enclave_key {
return Ok(false);
}
// validate the quotes delegated signer matches
if quote.secured_signer != signer.key() {
// deserialize accounts and verify the owner
let function_loader =
AccountLoader::<'_, FunctionAccountData>::try_from(&function_account_info.clone())?;
let func = function_loader.load()?;
let enclave_loader =
AccountLoader::<'_, EnclaveAccountData>::try_from(&enclave_account_info.clone())?;
let enclave = enclave_loader.load()?;
// validate the enclaves enclave is not empty
if enclave.mr_enclave == [0u8; 32] {
return Ok(false);
}
// validate the enclaves measurement is present in FunctionAccount config
if !func.is_valid_enclave(&enclave.mr_enclave) {
return Ok(false);
}
// validate the enclaves delegated signer matches
if enclave.enclave_signer != signer.key() {
return Ok(false);
}
Ok(true)
}
pub fn is_empty_schedule(&self) -> bool {
if self.schedule == [0u8; 64] {
return true;
}
let first_byte_null = self
.schedule
.first()
.map(|&byte| byte == 0)
.unwrap_or(false);
if first_byte_null {
return true;
}
false
}
pub fn get_container(&self) -> String {
std::str::from_utf8(&self.container)
.unwrap_or("")
@ -161,6 +295,14 @@ impl FunctionAccountData {
format!("{}:{}", self.get_container(), self.get_version())
}
pub fn is_valid_enclave(&self, mr_enclave: &[u8; 32]) -> bool {
if *mr_enclave == [0u8; 32] {
return false;
}
self.mr_enclaves.contains(mr_enclave)
}
cfg_client! {
pub fn get_schedule(&self) -> Option<cron::Schedule> {
if self.schedule[0] == 0 {
@ -181,7 +323,17 @@ impl FunctionAccountData {
)
}
pub fn get_next_execution_datetime(&self) -> chrono::DateTime<chrono::Utc> {
chrono::DateTime::from_utc(
chrono::NaiveDateTime::from_timestamp_opt(self.next_allowed_timestamp, 0).unwrap(),
chrono::Utc,
)
}
pub fn should_execute(&self, now: chrono::DateTime<chrono::Utc>) -> bool {
if self.is_triggered > 0 {
return true;
}
let schedule = self.get_schedule();
if schedule.is_none() {
return false;
@ -198,16 +350,6 @@ impl FunctionAccountData {
true
}
pub fn next_execution_timestamp(&self) -> Option<chrono::DateTime<chrono::Utc>> {
let schedule = self.get_schedule();
if schedule.is_none() {
return None;
}
let dt = self.get_last_execution_datetime();
schedule.unwrap().after(&dt).next()
}
pub async fn fetch(
client: &solana_client::rpc_client::RpcClient,
pubkey: Pubkey,

View File

@ -0,0 +1,208 @@
use crate::prelude::*;
use solana_program::borsh::get_instance_packed_len;
#[repr(u8)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
pub enum RequestStatus {
#[default]
None = 0,
RequestPending = 1,
RequestCancelled = 2,
RequestFailure = 3,
RequestExpired = 4,
RequestSuccess = 5,
}
impl From<RequestStatus> for u8 {
fn from(value: RequestStatus) -> Self {
match value {
RequestStatus::RequestPending => 1,
RequestStatus::RequestCancelled => 2,
RequestStatus::RequestFailure => 3,
RequestStatus::RequestExpired => 4,
RequestStatus::RequestSuccess => 5,
_ => 0,
}
}
}
impl From<u8> for RequestStatus {
fn from(value: u8) -> Self {
match value {
1 => RequestStatus::RequestPending,
2 => RequestStatus::RequestCancelled,
3 => RequestStatus::RequestFailure,
4 => RequestStatus::RequestExpired,
5 => RequestStatus::RequestSuccess,
_ => RequestStatus::default(),
}
}
}
#[derive(Copy, Clone, AnchorSerialize, AnchorDeserialize)]
pub struct FunctionRequestTriggerRound {
/// The status of the request.
pub status: RequestStatus,
/// The SOL bounty in lamports used to incentivize a verifier to expedite the request.
pub bounty: u64,
/// The slot the request was published
pub request_slot: u64,
/// The slot when the request was fulfilled
pub fulfilled_slot: u64,
/// The slot when the request will expire and be able to be closed by the non-authority account
pub expiration_slot: u64,
/// The EnclaveAccount who verified the enclave for this request
pub verifier: Pubkey,
/// The keypair generated in the enclave and required to sign any
/// valid transactions processed by the function.
pub enclave_signer: Pubkey,
/// Reserved.
pub _ebuf: [u8; 64],
}
impl Default for FunctionRequestTriggerRound {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
// #[account]
#[derive(AnchorDeserialize, AnchorSerialize, Clone)]
pub struct FunctionRequestAccountData {
// Up-Front Params for RPC filtering
/// Whether the request is ready to be processed.
pub is_triggered: u8,
/// The status of the current request.
pub status: RequestStatus,
// Accounts
/// Signer allowed to cancel the request.
pub authority: Pubkey,
/// The default destination for rent exemption when the account is closed.
pub payer: Pubkey,
/// The function that can process this request
pub function: Pubkey,
/// The tokenAccount escrow
pub escrow: Pubkey,
// Rounds
/// The current active request.
pub active_request: FunctionRequestTriggerRound,
/// The previous request.
pub previous_request: FunctionRequestTriggerRound,
// Container Params
/// The maximum number of bytes to pass to the container params.
pub max_container_params_len: u32,
/// Hash of the serialized container_params to prevent RPC tampering.
/// Should be verified within your function to ensure you are using the correct parameters.
pub container_params_hash: [u8; 32],
/// The stringified container params to pass to the function.
pub container_params: Vec<u8>,
// Metadata
/// The unix timestamp when the function was created.
pub created_at: i64,
/// The slot when the account can be garbage collected and closed by anyone for a portion of the rent.
pub garbage_collection_slot: Option<u64>,
/// Reserved.
pub _ebuf: [u8; 256],
}
impl Default for FunctionRequestAccountData {
fn default() -> Self {
Self {
is_triggered: 0,
status: RequestStatus::None,
authority: Pubkey::default(),
payer: Pubkey::default(),
function: Pubkey::default(),
escrow: Pubkey::default(),
active_request: FunctionRequestTriggerRound::default(),
previous_request: FunctionRequestTriggerRound::default(),
max_container_params_len: 0,
container_params_hash: [0u8; 32],
container_params: Vec::new(),
created_at: 0,
garbage_collection_slot: None,
_ebuf: [0u8; 256],
}
}
}
impl anchor_lang::AccountSerialize for FunctionRequestAccountData {
fn try_serialize<W: std::io::Write>(&self, writer: &mut W) -> anchor_lang::Result<()> {
if writer
.write_all(&FunctionRequestAccountData::discriminator())
.is_err()
{
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}
if AnchorSerialize::serialize(self, writer).is_err() {
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}
Ok(())
}
}
impl anchor_lang::AccountDeserialize for FunctionRequestAccountData {
fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
if buf.len() < FunctionRequestAccountData::discriminator().len() {
return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
}
let given_disc = &buf[..8];
if &FunctionRequestAccountData::discriminator() != given_disc {
return Err(
anchor_lang::error::Error::from(anchor_lang::error::AnchorError {
error_name: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.name(),
error_code_number: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch
.into(),
error_msg: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch
.to_string(),
error_origin: Some(anchor_lang::error::ErrorOrigin::Source(
anchor_lang::error::Source {
filename: "programs/attestation_program/src/lib.rs",
line: 357u32,
},
)),
compared_values: None,
})
.with_account_name("FunctionRequestAccountData"),
);
}
Self::try_deserialize_unchecked(buf)
}
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
let mut data: &[u8] = &buf[8..];
AnchorDeserialize::deserialize(&mut data)
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into())
}
}
impl Discriminator for FunctionRequestAccountData {
const DISCRIMINATOR: [u8; 8] = [8, 14, 177, 85, 144, 65, 148, 246];
}
impl Owner for FunctionRequestAccountData {
fn owner() -> Pubkey {
SWITCHBOARD_ATTESTATION_PROGRAM_ID
}
}
impl FunctionRequestAccountData {
pub fn space(len: Option<u32>) -> usize {
let base: usize = 8 // discriminator
+ get_instance_packed_len(&FunctionRequestAccountData::default()).unwrap();
let vec_elements: usize = len.unwrap_or(crate::DEFAULT_USERS_CONTAINER_PARAMS_LEN) as usize;
base + vec_elements
}
// verify if their is a non-expired pending request
pub fn is_round_active(&self, clock: &Clock) -> bool {
if self.status == RequestStatus::RequestPending {
if self.active_request.expiration_slot < clock.slot {
return false;
}
return true;
}
false
}
}

View File

@ -1,11 +1,13 @@
pub mod attestation_permission;
pub mod attestation_queue;
pub mod attestation_state;
pub mod enclave;
pub mod function;
pub mod quote;
pub mod function_request;
pub use attestation_permission::*;
pub use attestation_queue::*;
pub use attestation_state::*;
pub use enclave::*;
pub use function::*;
pub use quote::*;
pub use function_request::*;

View File

@ -0,0 +1,74 @@
use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params:ActionTemplateParams)]
pub struct ActionTemplate<'info> {
// accounts here
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct ActionTemplateParams {
// params here
}
impl InstructionData for ActionTemplateParams {}
impl Discriminator for ActionTemplateParams {
const DISCRIMINATOR: [u8; 8] = [
// discriminator here
];
}
impl Discriminator for ActionTemplate<'_> {
const DISCRIMINATOR: [u8; 8] = [
// discriminator here
];
}
impl<'info> ActionTemplate<'info> {
pub fn get_instruction(
&self,
program_id: Pubkey,
params: &ActionTemplateParams,
) -> anchor_lang::Result<Instruction> {
let accounts = self.to_account_metas(None);
let mut data: Vec<u8> = ActionTemplate::discriminator().try_to_vec()?;
data.append(&mut params.try_to_vec()?);
let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
Ok(instruction)
}
pub fn invoke(
&self,
program: AccountInfo<'info>,
params: &ActionTemplateParams,
) -> ProgramResult {
let instruction = self.get_instruction(*program.key, params)?;
let account_infos = self.to_account_infos();
invoke(&instruction, &account_infos[..])
}
pub fn invoke_signed(
&self,
program: AccountInfo<'info>,
params: &ActionTemplateParams,
signer_seeds: &[&[&[u8]]],
) -> ProgramResult {
let instruction = self.get_instruction(*program.key, params)?;
let account_infos = self.to_account_infos();
invoke_signed(&instruction, &account_infos[..], signer_seeds)
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
// to account infos here
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
// to account metas here
}
}

View File

@ -0,0 +1,123 @@
use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params:FunctionCloseParams)]
pub struct FunctionClose<'info> {
#[account(
mut,
close = sol_dest,
has_one = authority,
has_one = escrow,
has_one = address_lookup_table,
)]
pub function: AccountLoader<'info, FunctionAccountData>,
pub authority: Signer<'info>,
#[account(
mut,
constraint = escrow.is_native() && escrow.owner == state.key()
)]
pub escrow: Box<Account<'info, TokenAccount>>,
/// CHECK: handled in function has_one
#[account(
mut,
constraint = *address_lookup_table.owner == address_lookup_program.key()
)]
pub address_lookup_table: AccountInfo<'info>,
/// CHECK:
pub sol_dest: AccountInfo<'info>,
#[account(mut, constraint = escrow.is_native())]
pub escrow_dest: Box<Account<'info, TokenAccount>>,
#[account(seeds = [STATE_SEED], bump = state.load()?.bump)]
pub state: AccountLoader<'info, AttestationProgramState>,
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,
/// CHECK:
#[account(
constraint = address_lookup_program.executable && address_lookup_program.key().as_ref() == solana_address_lookup_table_program::id().as_ref()
)]
pub address_lookup_program: AccountInfo<'info>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct FunctionCloseParams {}
impl InstructionData for FunctionCloseParams {}
impl Discriminator for FunctionCloseParams {
const DISCRIMINATOR: [u8; 8] = [94, 164, 174, 42, 156, 29, 244, 236];
}
impl Discriminator for FunctionClose<'_> {
const DISCRIMINATOR: [u8; 8] = [94, 164, 174, 42, 156, 29, 244, 236];
}
impl<'info> FunctionClose<'info> {
pub fn get_instruction(&self, program_id: Pubkey) -> anchor_lang::Result<Instruction> {
let accounts = self.to_account_metas(None);
let mut data: Vec<u8> = FunctionClose::discriminator().try_to_vec()?;
let params = FunctionCloseParams {};
data.append(&mut params.try_to_vec()?);
let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
Ok(instruction)
}
pub fn invoke(&self, program: AccountInfo<'info>) -> ProgramResult {
let instruction = self.get_instruction(*program.key)?;
let account_infos = self.to_account_infos();
invoke(&instruction, &account_infos[..])
}
pub fn invoke_signed(
&self,
program: AccountInfo<'info>,
signer_seeds: &[&[&[u8]]],
) -> ProgramResult {
let instruction = self.get_instruction(*program.key)?;
let account_infos = self.to_account_infos();
invoke_signed(&instruction, &account_infos[..], signer_seeds)
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
let mut account_infos = Vec::new();
account_infos.extend(self.function.to_account_infos());
account_infos.extend(self.authority.to_account_infos());
account_infos.extend(self.escrow.to_account_infos());
account_infos.extend(self.address_lookup_table.to_account_infos());
account_infos.extend(self.sol_dest.to_account_infos());
account_infos.extend(self.escrow_dest.to_account_infos());
account_infos.extend(self.state.to_account_infos());
account_infos.extend(self.token_program.to_account_infos());
account_infos.extend(self.system_program.to_account_infos());
account_infos.extend(self.address_lookup_program.to_account_infos());
account_infos
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
let mut account_metas = Vec::new();
account_metas.extend(self.function.to_account_metas(None));
account_metas.extend(self.authority.to_account_metas(None));
account_metas.extend(self.escrow.to_account_metas(None));
account_metas.extend(self.address_lookup_table.to_account_metas(None));
account_metas.extend(self.sol_dest.to_account_metas(None));
account_metas.extend(self.escrow_dest.to_account_metas(None));
account_metas.extend(self.state.to_account_metas(None));
account_metas.extend(self.token_program.to_account_metas(None));
account_metas.extend(self.system_program.to_account_metas(None));
account_metas.extend(self.address_lookup_program.to_account_metas(None));
account_metas
}
}

View File

@ -0,0 +1,163 @@
use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params:FunctionInitParams)]
pub struct FunctionInit<'info> {
#[account(
init,
space = FunctionAccountData::size(),
payer = payer
)]
pub function: AccountLoader<'info, FunctionAccountData>,
/// CHECK: todo
#[account(mut)]
pub address_lookup_table: AccountInfo<'info>,
/// CHECK: todo
pub authority: AccountInfo<'info>,
#[account(
init,
seeds = [QUOTE_SEED,
function.key().as_ref()],
space = EnclaveAccountData::size(),
payer = payer,
bump,
)]
pub quote: AccountLoader<'info, EnclaveAccountData>,
pub attestation_queue: AccountLoader<'info, AttestationQueueAccountData>,
#[account(mut)]
pub payer: Signer<'info>,
#[account(
init,
payer = payer,
associated_token::mint = mint,
associated_token::authority = function,
)]
pub escrow: Account<'info, TokenAccount>,
#[account(seeds = [STATE_SEED], bump = state.load()?.bump)]
pub state: AccountLoader<'info, AttestationProgramState>,
#[account(address = anchor_spl::token::spl_token::native_mint::ID)]
pub mint: Account<'info, Mint>,
pub token_program: Program<'info, Token>,
pub associated_token_program: Program<'info, AssociatedToken>,
pub system_program: Program<'info, System>,
/// CHECK:
#[account(
constraint = address_lookup_program.executable && address_lookup_program.key().as_ref() == solana_address_lookup_table_program::id().as_ref()
)]
pub address_lookup_program: AccountInfo<'info>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct FunctionInitParams {
pub name: Vec<u8>,
pub metadata: Vec<u8>,
pub container: Vec<u8>,
pub container_registry: Vec<u8>,
pub version: Vec<u8>,
pub schedule: Vec<u8>,
pub mr_enclave: [u8; 32],
pub recent_slot: u64,
pub requests_disabled: bool,
pub requests_require_authorization: bool,
pub requests_default_slots_until_expiration: u64,
pub requests_fee: u64,
}
impl InstructionData for FunctionInitParams {}
impl Discriminator for FunctionInitParams {
const DISCRIMINATOR: [u8; 8] = [0, 20, 30, 24, 100, 146, 13, 162];
}
impl Discriminator for FunctionInit<'_> {
const DISCRIMINATOR: [u8; 8] = [0, 20, 30, 24, 100, 146, 13, 162];
}
impl<'info> FunctionInit<'info> {
pub fn get_instruction(
&self,
program_id: Pubkey,
params: &FunctionInitParams,
) -> anchor_lang::Result<Instruction> {
let accounts = self.to_account_metas(None);
let mut data: Vec<u8> = FunctionInit::discriminator().try_to_vec()?;
data.append(&mut params.try_to_vec()?);
let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
Ok(instruction)
}
pub fn invoke(
&self,
program: AccountInfo<'info>,
params: &FunctionInitParams,
) -> ProgramResult {
let instruction = self.get_instruction(*program.key, params)?;
let account_infos = self.to_account_infos();
invoke(&instruction, &account_infos[..])
}
pub fn invoke_signed(
&self,
program: AccountInfo<'info>,
params: &FunctionInitParams,
signer_seeds: &[&[&[u8]]],
) -> ProgramResult {
let instruction = self.get_instruction(*program.key, params)?;
let account_infos = self.to_account_infos();
invoke_signed(&instruction, &account_infos[..], signer_seeds)
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
let mut account_infos = Vec::new();
account_infos.extend(self.function.to_account_infos());
account_infos.extend(self.address_lookup_table.to_account_infos());
account_infos.extend(self.authority.to_account_infos());
account_infos.extend(self.quote.to_account_infos());
account_infos.extend(self.attestation_queue.to_account_infos());
account_infos.extend(self.payer.to_account_infos());
account_infos.extend(self.escrow.to_account_infos());
account_infos.extend(self.state.to_account_infos());
account_infos.extend(self.mint.to_account_infos());
account_infos.extend(self.token_program.to_account_infos());
account_infos.extend(self.associated_token_program.to_account_infos());
account_infos.extend(self.system_program.to_account_infos());
account_infos.extend(self.address_lookup_program.to_account_infos());
account_infos
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
let mut account_metas = Vec::new();
account_metas.extend(self.function.to_account_metas(Some(true)));
account_metas.extend(self.address_lookup_table.to_account_metas(None));
account_metas.extend(self.authority.to_account_metas(None));
account_metas.extend(self.quote.to_account_metas(None));
account_metas.extend(self.attestation_queue.to_account_metas(None));
account_metas.extend(self.payer.to_account_metas(None));
account_metas.extend(self.escrow.to_account_metas(None));
account_metas.extend(self.state.to_account_metas(None));
account_metas.extend(self.mint.to_account_metas(None));
account_metas.extend(self.token_program.to_account_metas(None));
account_metas
.extend(self.associated_token_program.to_account_metas(None));
account_metas.extend(self.system_program.to_account_metas(None));
account_metas.extend(self.address_lookup_program.to_account_metas(None));
account_metas
}
}

View File

@ -0,0 +1,149 @@
use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params:FunctionRequestInitAndTriggerParams)]
pub struct FunctionRequestInitAndTrigger<'info> {
#[account(
init,
payer = payer,
space = FunctionRequestAccountData::space(
params.max_container_params_len
),
)]
pub request: Box<Account<'info, FunctionRequestAccountData>>,
#[account(mut, has_one = attestation_queue)]
pub function: AccountLoader<'info, FunctionAccountData>,
#[account(
init,
payer = payer,
associated_token::mint = mint,
associated_token::authority = request,
)]
pub escrow: Box<Account<'info, TokenAccount>>,
#[account(address = anchor_spl::token::spl_token::native_mint::ID)]
pub mint: Account<'info, Mint>,
#[account(seeds = [STATE_SEED], bump = state.load()?.bump)]
pub state: AccountLoader<'info, AttestationProgramState>,
pub attestation_queue: AccountLoader<'info, AttestationQueueAccountData>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, anchor_spl::token::Token>,
pub associated_token_program: Program<'info, anchor_spl::associated_token::AssociatedToken>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct FunctionRequestInitAndTriggerParams {
pub bounty: Option<u64>,
pub slots_until_expiration: Option<u64>,
pub max_container_params_len: Option<u32>,
pub container_params: Option<Vec<u8>>,
pub garbage_collection_slot: Option<u64>,
}
impl InstructionData for FunctionRequestInitAndTriggerParams {}
impl Discriminator for FunctionRequestInitAndTriggerParams {
const DISCRIMINATOR: [u8; 8] = [86, 151, 134, 172, 35, 218, 207, 154];
}
impl Discriminator for FunctionRequestInitAndTrigger<'_> {
const DISCRIMINATOR: [u8; 8] = [86, 151, 134, 172, 35, 218, 207, 154];
}
impl<'info> FunctionRequestInitAndTrigger<'info> {
pub fn get_instruction(
&self,
program_id: Pubkey,
params: FunctionRequestInitAndTriggerParams,
) -> anchor_lang::Result<Instruction> {
let accounts = self.to_account_metas(None);
let mut data: Vec<u8> = FunctionRequestInitAndTrigger::discriminator().try_to_vec()?;
let mut param_vec: Vec<u8> = params.try_to_vec()?;
data.append(&mut param_vec);
let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
Ok(instruction)
}
pub fn invoke(
&self,
program: AccountInfo<'info>,
bounty: Option<u64>,
slots_until_expiration: Option<u64>,
max_container_params_len: Option<u32>,
container_params: Option<Vec<u8>>,
garbage_collection_slot: Option<u64>,
) -> ProgramResult {
let instruction = self.get_instruction(
*program.key,
FunctionRequestInitAndTriggerParams {
bounty,
slots_until_expiration,
max_container_params_len,
container_params,
garbage_collection_slot,
},
)?;
let account_infos = self.to_account_infos();
invoke(&instruction, &account_infos[..])
}
pub fn invoke_signed(
&self,
program: AccountInfo<'info>,
bounty: Option<u64>,
slots_until_expiration: Option<u64>,
max_container_params_len: Option<u32>,
container_params: Option<Vec<u8>>,
garbage_collection_slot: Option<u64>,
signer_seeds: &[&[&[u8]]],
) -> ProgramResult {
let instruction = self.get_instruction(
*program.key,
FunctionRequestInitAndTriggerParams {
bounty,
slots_until_expiration,
max_container_params_len,
container_params,
garbage_collection_slot,
},
)?;
let account_infos = self.to_account_infos();
invoke_signed(&instruction, &account_infos[..], signer_seeds)
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
let mut account_infos = Vec::new();
account_infos.extend(self.request.to_account_infos());
account_infos.extend(self.function.to_account_infos());
account_infos.extend(self.escrow.to_account_infos());
account_infos.extend(self.mint.to_account_infos());
account_infos.extend(self.state.to_account_infos());
account_infos.extend(self.attestation_queue.to_account_infos());
account_infos.extend(self.payer.to_account_infos());
account_infos.extend(self.system_program.to_account_infos());
account_infos.extend(self.token_program.to_account_infos());
account_infos.extend(self.associated_token_program.to_account_infos());
account_infos
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
let mut account_metas = Vec::new();
account_metas.extend(self.request.to_account_metas(Some(true)));
account_metas.extend(self.function.to_account_metas(None));
account_metas.extend(self.escrow.to_account_metas(None));
account_metas.extend(self.mint.to_account_metas(None));
account_metas.extend(self.state.to_account_metas(None));
account_metas.extend(self.attestation_queue.to_account_metas(None));
account_metas.extend(self.payer.to_account_metas(None));
account_metas.extend(self.system_program.to_account_metas(None));
account_metas.extend(self.token_program.to_account_metas(None));
account_metas.extend(self.associated_token_program.to_account_metas(None));
account_metas
}
}

View File

@ -0,0 +1,104 @@
use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params:FunctionSetConfigParams)]
pub struct FunctionSetConfig<'info> {
#[account(
mut,
has_one = authority
)]
pub function: AccountLoader<'info, FunctionAccountData>,
#[account(
mut,
seeds = [
QUOTE_SEED,
function.key().as_ref()
],
bump = quote.load()?.bump,
)]
pub quote: AccountLoader<'info, EnclaveAccountData>,
pub authority: Signer<'info>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct FunctionSetConfigParams {
pub name: Option<Vec<u8>>,
pub metadata: Option<Vec<u8>>,
pub container: Option<Vec<u8>>,
pub container_registry: Option<Vec<u8>>,
pub version: Option<Vec<u8>>,
pub schedule: Option<Vec<u8>>,
pub mr_enclaves: Option<Vec<[u8; 32]>>,
pub requests_disabled: Option<bool>,
pub requests_require_authorization: Option<bool>,
pub requests_default_slots_until_expiration: Option<u64>,
pub requests_fee: Option<u64>,
}
impl InstructionData for FunctionSetConfigParams {}
impl Discriminator for FunctionSetConfigParams {
const DISCRIMINATOR: [u8; 8] = [232, 132, 21, 251, 253, 189, 96, 94];
}
impl Discriminator for FunctionSetConfig<'_> {
const DISCRIMINATOR: [u8; 8] = [232, 132, 21, 251, 253, 189, 96, 94];
}
impl<'info> FunctionSetConfig<'info> {
pub fn get_instruction(
&self,
program_id: Pubkey,
params: &FunctionSetConfigParams,
) -> anchor_lang::Result<Instruction> {
let accounts = self.to_account_metas(None);
let mut data: Vec<u8> = FunctionSetConfig::discriminator().try_to_vec()?;
data.append(&mut params.try_to_vec()?);
let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
Ok(instruction)
}
pub fn invoke(
&self,
program: AccountInfo<'info>,
params: &FunctionSetConfigParams,
) -> ProgramResult {
let instruction = self.get_instruction(*program.key, params)?;
let account_infos = self.to_account_infos();
invoke(&instruction, &account_infos[..])
}
pub fn invoke_signed(
&self,
program: AccountInfo<'info>,
params: &FunctionSetConfigParams,
signer_seeds: &[&[&[u8]]],
) -> ProgramResult {
let instruction = self.get_instruction(*program.key, params)?;
let account_infos = self.to_account_infos();
invoke_signed(&instruction, &account_infos[..], signer_seeds)
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
let mut account_infos = Vec::new();
account_infos.extend(self.function.to_account_infos());
account_infos.extend(self.quote.to_account_infos());
account_infos.extend(self.authority.to_account_infos());
account_infos
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
let mut account_metas = Vec::new();
account_metas.extend(self.function.to_account_metas(None));
account_metas.extend(self.quote.to_account_metas(None));
account_metas.extend(self.authority.to_account_metas(None));
account_metas
}
}

View File

@ -1,36 +1,40 @@
use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params: FunctionTriggerParams)] // rpc parameters hint
#[instruction(params:FunctionTriggerParams)]
pub struct FunctionTrigger<'info> {
#[account(mut)]
pub function: AccountInfo<'info>,
#[account(
mut,
has_one = authority,
has_one = attestation_queue,
)]
pub function: AccountLoader<'info, FunctionAccountData>,
#[account(signer)]
pub authority: AccountInfo<'info>,
pub authority: Signer<'info>,
pub attestation_queue: AccountLoader<'info, AttestationQueueAccountData>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct FunctionTriggerParams {}
impl InstructionData for FunctionTriggerParams {}
impl Discriminator for FunctionTriggerParams {
const DISCRIMINATOR: [u8; 8] = [45, 224, 218, 184, 248, 83, 239, 200];
}
impl Discriminator for FunctionTrigger<'_> {
const DISCRIMINATOR: [u8; 8] = [45, 224, 218, 184, 248, 83, 239, 200];
}
impl<'info> FunctionTrigger<'info> {
pub fn get_instruction(&self, program_id: Pubkey) -> anchor_lang::Result<Instruction> {
let accounts = self.to_account_metas(None);
let mut data: Vec<u8> = FunctionTrigger::discriminator().try_to_vec()?;
let params = FunctionTriggerParams {};
let mut param_vec: Vec<u8> = params.try_to_vec()?;
data.append(&mut param_vec);
let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
Ok(instruction)
Ok(Instruction::new_with_bytes(
program_id,
&FunctionTrigger::discriminator().try_to_vec()?,
self.to_account_metas(None),
))
}
pub fn invoke(&self, program: AccountInfo<'info>) -> ProgramResult {
@ -52,22 +56,19 @@ impl<'info> FunctionTrigger<'info> {
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
vec![self.function.clone(), self.authority.clone()]
let mut account_infos = Vec::new();
account_infos.extend(self.function.to_account_infos());
account_infos.extend(self.authority.to_account_infos());
account_infos.extend(self.attestation_queue.to_account_infos());
account_infos
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
vec![
AccountMeta {
pubkey: *self.function.key,
is_signer: self.function.is_signer,
is_writable: self.function.is_writable,
},
AccountMeta {
pubkey: *self.authority.key,
is_signer: self.authority.is_signer,
is_writable: self.authority.is_writable,
},
]
let mut account_metas = Vec::new();
account_metas.extend(self.function.to_account_metas(None));
account_metas.extend(self.authority.to_account_metas(None));
account_metas.extend(self.attestation_queue.to_account_metas(None));
account_metas
}
}

View File

@ -3,30 +3,58 @@ use crate::prelude::*;
#[derive(Accounts)]
#[instruction(params: FunctionVerifyParams)] // rpc parameters hint
pub struct FunctionVerify<'info> {
#[account(mut)]
pub function: AccountInfo<'info>,
#[account(signer)]
pub fn_signer: AccountInfo<'info>,
/// CHECK:
pub fn_quote: AccountInfo<'info>,
pub verifier_quote: AccountInfo<'info>,
#[account(signer)]
pub secured_signer: AccountInfo<'info>,
pub attestation_queue: AccountInfo<'info>,
/// CHECK:
#[account(mut)]
pub escrow: Account<'info, TokenAccount>,
/// CHECK:
#[account(mut)]
pub receiver: Account<'info, TokenAccount>,
pub verifier_permission: AccountInfo<'info>,
pub fn_permission: AccountInfo<'info>,
#[account(mut)]
pub state: AccountInfo<'info>,
pub token_program: AccountInfo<'info>,
#[account(signer)]
pub payer: AccountInfo<'info>,
pub system_program: AccountInfo<'info>,
#[account(
mut,
has_one = attestation_queue,
has_one = escrow,
)]
pub function: AccountLoader<'info, FunctionAccountData>,
pub function_enclave_signer: Signer<'info>,
#[account(
mut,
seeds = [QUOTE_SEED, function.key().as_ref()],
bump = fn_quote.load()?.bump,
has_one = attestation_queue
)]
pub fn_quote: AccountLoader<'info, EnclaveAccountData>,
#[account(
has_one = attestation_queue,
constraint = verifier_quote.load()?.enclave_signer == verifier_enclave_signer.key(),
)]
pub verifier_quote: AccountLoader<'info, EnclaveAccountData>,
pub verifier_enclave_signer: Signer<'info>,
#[account(
seeds = [PERMISSION_SEED,
attestation_queue.load()?.authority.as_ref(),
attestation_queue.key().as_ref(),
verifier_quote.key().as_ref()],
bump = verifier_permission.load()?.bump,
)]
pub verifier_permission: AccountLoader<'info,AttestationPermissionAccountData>,
#[account(
mut,
constraint = escrow.is_native() && escrow.owner == state.key()
)]
pub escrow: Box<Account<'info, TokenAccount>>,
#[account(
mut,
constraint = receiver.is_native()
)]
pub receiver: Box<Account<'info, TokenAccount>>,
#[account(seeds = [STATE_SEED], bump = state.load()?.bump)]
pub state: AccountLoader<'info, AttestationProgramState>,
pub attestation_queue: AccountLoader<'info, AttestationQueueAccountData>,
pub token_program: Program<'info, Token>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
@ -102,97 +130,38 @@ impl<'info> FunctionVerify<'info> {
}
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
vec![
self.function.clone(),
self.fn_signer.clone(),
self.fn_quote.clone(),
self.verifier_quote.clone(),
self.secured_signer.clone(),
self.attestation_queue.clone(),
self.escrow.to_account_info().clone(),
self.receiver.to_account_info().clone(),
self.verifier_permission.clone(),
self.fn_permission.clone(),
self.state.clone(),
self.token_program.clone(),
self.payer.clone(),
self.system_program.clone(),
]
let mut account_infos = Vec::new();
account_infos.extend(self.function.to_account_infos());
account_infos.extend(self.function_enclave_signer.to_account_infos());
account_infos.extend(self.fn_quote.to_account_infos());
account_infos.extend(self.verifier_quote.to_account_infos());
account_infos.extend(self.verifier_enclave_signer.to_account_infos());
account_infos.extend(self.verifier_permission.to_account_infos());
account_infos.extend(self.escrow.to_account_infos());
account_infos.extend(self.receiver.to_account_infos());
account_infos.extend(self.state.to_account_infos());
account_infos.extend(self.attestation_queue.to_account_infos());
account_infos.extend(self.token_program.to_account_infos());
account_infos
}
#[allow(unused_variables)]
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
vec![
AccountMeta {
pubkey: *self.function.key,
is_signer: self.function.is_signer,
is_writable: self.function.is_writable,
},
AccountMeta {
pubkey: *self.fn_signer.key,
is_signer: self.fn_signer.is_signer,
is_writable: self.fn_signer.is_writable,
},
AccountMeta {
pubkey: *self.fn_quote.key,
is_signer: self.fn_quote.is_signer,
is_writable: self.fn_quote.is_writable,
},
AccountMeta {
pubkey: *self.verifier_quote.key,
is_signer: self.verifier_quote.is_signer,
is_writable: self.verifier_quote.is_writable,
},
AccountMeta {
pubkey: *self.secured_signer.key,
is_signer: self.verifier_quote.is_signer,
is_writable: self.verifier_quote.is_writable,
},
AccountMeta {
pubkey: *self.attestation_queue.key,
is_signer: self.attestation_queue.is_signer,
is_writable: self.attestation_queue.is_writable,
},
AccountMeta {
pubkey: self.escrow.key(),
is_signer: self.escrow.to_account_info().is_signer,
is_writable: self.escrow.to_account_info().is_writable,
},
AccountMeta {
pubkey: self.receiver.key(),
is_signer: self.receiver.to_account_info().is_signer,
is_writable: self.receiver.to_account_info().is_writable,
},
AccountMeta {
pubkey: *self.verifier_permission.key,
is_signer: self.verifier_permission.is_signer,
is_writable: self.verifier_permission.is_writable,
},
AccountMeta {
pubkey: *self.fn_permission.key,
is_signer: self.fn_permission.is_signer,
is_writable: self.fn_permission.is_writable,
},
AccountMeta {
pubkey: *self.state.key,
is_signer: self.state.is_signer,
is_writable: self.state.is_writable,
},
AccountMeta {
pubkey: *self.token_program.key,
is_signer: self.token_program.is_signer,
is_writable: self.token_program.is_writable,
},
AccountMeta {
pubkey: *self.payer.key,
is_signer: self.payer.is_signer,
is_writable: self.payer.is_writable,
},
AccountMeta {
pubkey: *self.system_program.key,
is_signer: self.system_program.is_signer,
is_writable: self.system_program.is_writable,
},
]
let mut account_metas = Vec::new();
account_metas.extend(self.function.to_account_metas(None));
account_metas
.extend(self.function_enclave_signer.to_account_metas(None));
account_metas.extend(self.fn_quote.to_account_metas(None));
account_metas.extend(self.verifier_quote.to_account_metas(None));
account_metas
.extend(self.verifier_enclave_signer.to_account_metas(None));
account_metas.extend(self.verifier_permission.to_account_metas(None));
account_metas.extend(self.escrow.to_account_metas(None));
account_metas.extend(self.receiver.to_account_metas(None));
account_metas.extend(self.state.to_account_metas(None));
account_metas.extend(self.attestation_queue.to_account_metas(None));
account_metas.extend(self.token_program.to_account_metas(None));
account_metas
}
}

View File

@ -1,5 +1,26 @@
pub mod function_verify;
pub use function_verify::*;
pub mod function_init;
pub use function_init::*;
pub mod function_set_config;
pub use function_set_config::*;
pub mod function_trigger;
pub use function_trigger::*;
pub mod function_verify;
pub use function_verify::*;
pub mod function_close;
pub use function_close::*;
pub mod function_request_init_and_trigger;
pub use function_request_init_and_trigger::*;
pub mod request_init;
pub use request_init::*;
pub mod request_verify;
pub use request_verify::*;
pub mod request_close;
pub use request_close::*;

Some files were not shown because too many files have changed in this diff Show More