risc0_ethereum_contracts/
lib.rs1#![deny(rustdoc::broken_intra_doc_links)]
16#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
17
18pub mod groth16;
19
20pub use alloy;
25
26cfg_if::cfg_if! {
28 if #[cfg(feature = "unstable")] {
29 pub mod set_verifier;
30 pub mod event_query;
31 pub mod receipt;
32 pub mod selector;
33 }
34}
35
36use core::str::FromStr;
37
38use anyhow::{bail, Result};
39use risc0_zkvm::{sha::Digestible, InnerReceipt};
40
41#[cfg(not(target_os = "zkvm"))]
42use alloy::{primitives::Bytes, sol_types::SolInterface, transports::TransportError};
43
44alloy::sol!(
45 #![sol(rpc, all_derives)]
46 "src/IRiscZeroVerifier.sol"
47);
48
49alloy::sol!(
50 #![sol(rpc, all_derives)]
51 "src/IRiscZeroSetVerifier.sol"
52);
53
54#[cfg(not(target_os = "zkvm"))]
55pub use IRiscZeroSetVerifier::IRiscZeroSetVerifierErrors;
56
57#[cfg(not(target_os = "zkvm"))]
58#[derive(thiserror::Error, Debug)]
59pub enum Error {
60 #[error("SetVerifier error: {0:?}")]
61 SetVerifierError(IRiscZeroSetVerifierErrors),
62
63 #[error("contract error: {0}")]
64 ContractError(alloy::contract::Error),
65
66 #[error("decoding error: {0}")]
67 DecodingError(#[from] DecodingError),
68}
69
70#[cfg(not(target_os = "zkvm"))]
71#[derive(thiserror::Error, Debug)]
72pub enum DecodingError {
73 #[error("missing data, code: {0} msg: {1}")]
74 MissingData(i64, String),
75
76 #[error("error creating bytes from string")]
77 BytesFromStrError,
78
79 #[error("abi decoder error: {0} - {1}")]
80 Abi(alloy::sol_types::Error, Bytes),
81}
82
83pub fn encode_seal(receipt: &risc0_zkvm::Receipt) -> Result<Vec<u8>> {
89 let seal = match receipt.inner.clone() {
90 InnerReceipt::Fake(receipt) => {
91 let seal = receipt.claim.digest().as_bytes().to_vec();
92 let selector = &[0xFFu8; 4];
93 let mut selector_seal = Vec::with_capacity(selector.len() + seal.len());
95 selector_seal.extend_from_slice(selector);
96 selector_seal.extend_from_slice(&seal);
97 selector_seal
98 }
99 InnerReceipt::Groth16(receipt) => {
100 let selector = &receipt.verifier_parameters.as_bytes()[..4];
101 let mut selector_seal = Vec::with_capacity(selector.len() + receipt.seal.len());
103 selector_seal.extend_from_slice(selector);
104 selector_seal.extend_from_slice(receipt.seal.as_ref());
105 selector_seal
106 }
107 _ => bail!("Unsupported receipt type"),
108 };
110 Ok(seal)
111}
112
113#[cfg(not(target_os = "zkvm"))]
114fn decode_contract_err<T: SolInterface>(err: alloy::contract::Error) -> Result<T, Error> {
115 match err {
116 alloy::contract::Error::TransportError(TransportError::ErrorResp(ts_err)) => {
117 let Some(data) = ts_err.data else {
118 return Err(
119 DecodingError::MissingData(ts_err.code, ts_err.message.to_string()).into(),
120 );
121 };
122
123 let data = data.get().trim_matches('"');
124
125 let Ok(data) = Bytes::from_str(data) else {
126 return Err(DecodingError::BytesFromStrError.into());
127 };
128
129 let decoded_error = match T::abi_decode(&data, true) {
130 Ok(res) => res,
131 Err(err) => {
132 return Err(DecodingError::Abi(err, data).into());
133 }
134 };
135
136 Ok(decoded_error)
137 }
138 _ => Err(Error::ContractError(err)),
139 }
140}
141
142#[cfg(not(target_os = "zkvm"))]
143impl IRiscZeroSetVerifierErrors {
144 pub fn decode_error(err: alloy::contract::Error) -> Error {
145 match decode_contract_err(err) {
146 Ok(res) => Error::SetVerifierError(res),
147 Err(decode_err) => decode_err,
148 }
149 }
150}