switchboard_evm/lib.rs
1//! Switchboard is a multi-chain, permissionless oracle protocol providing
2//! verifiable off-chain compute for smart contracts.
3//!
4//! This library provides the ethers-rs [`bindings`] for interacting and operating
5//! Switchboard, along side the [`EvmFunctionRunner`] to write custom Switchboard
6//! Functions.
7//!
8//! Here's an example of using the EvmFunctionRunner inside a Switchboard Function:
9//!
10//! ```
11//! // Generate your contract's ABI
12//! abigen!(Receiver, r#"[ function callback(int256, uint256) ]"#,);
13//!
14//! #[derive(Debug, Deserialize)]
15//! pub struct DeribitRespnseInner {
16//! pub mark_iv: f64,
17//! pub timestamp: u64,
18//! }
19//!
20//! #[derive(Debug, Deserialize)]
21//! pub struct DeribitResponse {
22//! pub result: DeribitRespnseInner,
23//! }
24//!
25//! #[tokio::main(worker_threads = 12)]
26//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
27//! // --- Initialize clients ---
28//! let function_runner = EvmFunctionRunner::new()?;
29//! let client = function_runner.get_client(None).await?;
30//!
31//! let receiver: Address = env!("EXAMPLE_PROGRAM").parse()?;
32//! let receiver_contract = Receiver::new(receiver, client.into());
33
34//! // --- Logic Below ---
35//! let url = "https://www.deribit.com/api/v2/public/get_order_book?instrument_name=ETH-29SEP23-2000-C";
36//! let derebit_response: DeribitResponse = reqwest::get(url).await?.json().await?;
37
38//! let timestamp = derebit_response.result.timestamp.into();
39//! let mut mark_iv = Decimal::from_f64(derebit_response.result.mark_iv).unwrap();
40//! mark_iv.rescale(8);
41
42//! // --- Send the callback to the contract with Switchboard verification ---
43//! let callback = receiver_contract.callback(mark_iv.mantissa().into(), timestamp);
44//! let expiration = (Utc::now().timestamp() + 120).into();
45//! let gas_limit = 5_500_000.into();
46//! function_runner.emit(receiver, expiration, gas_limit, vec![callback])?;
47//! Ok(())
48//! }
49//! ```
50
51pub mod bindings;
52pub mod sdk;
53pub mod utils;
54pub use switchboard_common::*;
55pub mod secrets;
56pub use secrets::*;
57pub mod test;
58use ethers::prelude::*;
59pub use sb_macros::*;
60pub use test::*;
61
62pub type FnCall = FunctionCall<
63 std::sync::Arc<SignerMiddleware<Provider<Http>, Wallet<ecdsa::SigningKey<k256::Secp256k1>>>>,
64 SignerMiddleware<Provider<Http>, Wallet<ecdsa::SigningKey<k256::Secp256k1>>>,
65 (),
66>;
67pub type SbMiddleware =
68 SignerMiddleware<Provider<Http>, Wallet<ecdsa::SigningKey<k256::Secp256k1>>>;
69
70/// The Switchboard contract ABI with the included facets.
71pub const SWITCHBOARD_ABI: &str = std::include_str!("../Switchboard.json");
72
73/// The Switchboard Push Receiver contract ABI with the included facets.
74pub const SWITCHBOARD_PUSH_RECEIVER_ABI: &str =
75 std::include_str!("../SwitchboardPushReceiver.json");
76
77pub use switchboard_common::{
78 ChainResultInfo, EvmFunctionResult, EvmTransaction, FunctionResult, Gramine,
79 SbError as SwitchboardClientError,
80};
81
82// pub type FnCall<M, S> = FunctionCall<Arc<SignerMiddleware<M, S>>, SignerMiddleware<M, S>, ()>;
83
84pub trait SbFunctionParameters {
85 fn decode(data: &[u8]) -> Option<Self>
86 where
87 Self: Sized;
88}
89
90#[derive(Clone, Copy, Debug, Default)]
91pub struct NoParams;
92impl SbFunctionParameters for NoParams {
93 fn decode(_data: &[u8]) -> Option<Self>
94 where
95 Self: Sized,
96 {
97 Some(Self {})
98 }
99}
100
101//#[cfg(test)]
102
103// @TODO: update this test / finish inline ierc20 call
104// mod tests {
105// use std::env;
106// use std::sync::Arc;
107
108// use ethers::prelude::{abigen, ContractCall};
109// use ethers::signers::Signer;
110// use ethers::types::transaction::eip712::EIP712Domain;
111// use ethers::types::Address;
112
113// use ethers::{
114// prelude::{k256::ecdsa::SigningKey, SignerMiddleware},
115// providers::{Http, Middleware, Provider},
116// signers::{LocalWallet, Wallet},
117// // types::Address,
118// };
119
120// use crate::sdk::{EvmFunctionRunner, EVMMiddleware};
121
122// use super::*;
123
124// #[tokio::test]
125// async fn test_function_result() {
126// std::env::set_var("CHAIN_ID", "421613"); // arb Goerli testnet
127// std::env::set_var(
128// "VERIFYING_CONTRACT",
129// "0x8b8F944F8506db8A91f85A31A956b165259C617F",
130// ); // SB arb testnet contract
131// std::env::set_var(
132// "TARGET_CONTRACT",
133// "0xcD016103a3d6aeD82b19B99f766ef0444a09000c",
134// );
135// // set the gas limit and expiration
136// let gas_limit = 1000000;
137// let expiration_time_seconds = 60;
138
139// // create a client, wallet and middleware. This is just so we can create the contract instance and sign the txn.
140// let client = Provider::<Http>::try_from("https://goerli-rollup.arbitrum.io/rpc").unwrap();
141// let wallet: Wallet<SigningKey> =
142// "725fd1619b2653b7ff1806bf29ae11d0568606d83777afd5b1f2e649bd5132a9"
143// .parse::<LocalWallet>()
144// .unwrap()
145// .with_chain_id(client.get_chainid().await.unwrap().as_u64());
146
147// // your target contract address
148// let contract_address = "0xcD016103a3d6aeD82b19B99f766ef0444a09000c"
149// .parse::<ethers::types::Address>()
150// .unwrap();
151// abigen!(
152// SBTEST,
153// r#"[
154// function totalSupply() external view returns (uint256)
155// function balanceOf(address account) external view returns (uint256)
156// function transfer(address recipient, uint256 amount) external returns (bool)
157// function allowance(address owner, address spender) external view returns (uint256)
158// function approve(address spender, uint256 amount) external returns (bool)
159// function transferFrom( address sender, address recipient, uint256 amount) external returns (bool)
160// event Transfer(address indexed from, address indexed to, uint256 value)
161// event Approval(address indexed owner, address indexed spender, uint256 value)
162// ]"#,
163// );
164
165// let middleware: Arc<SignerMiddleware<Provider<Http>, Wallet<SigningKey>>> = Arc::new(
166// SignerMiddleware::new_with_provider_chain(client.clone(), wallet.clone())
167// .await
168// .unwrap(),
169// );
170// // the switchboard verifying contract
171// let sb_contract =
172// bindings::switchboard::Switchboard::new(contract_address, middleware.clone());
173
174// let erc20_contract = SBTEST::new(contract_address, middleware);
175// let recipient = "0x56929386E0966a8bb9734a8949AFCF5c9df47743"
176// .parse()
177// .unwrap();
178// let contract_fn_call: ContractCall<EVMMiddleware<_>, _> =
179// erc20_contract.mint(recipient, 100.into());
180
181// // create a vec of contract calls to pass to the function runner
182// let calls = vec![contract_fn_call.clone()];
183
184// // First, initialize the runner instance with a freshly generated Gramine keypair
185// let function_runner = EvmFunctionRunner::new().unwrap();
186
187// let _fr = function_runner.emit(
188// sb_contract,
189// expiration_time_seconds.into(),
190// gas_limit.into(),
191// calls,
192// );
193// }
194// }