ethereum.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. use {
  2. crate::{
  3. api::ChainId,
  4. chain::{
  5. eth_gas_oracle::EthProviderOracle,
  6. reader::{
  7. self,
  8. BlockNumber,
  9. BlockStatus,
  10. EntropyReader,
  11. RequestedWithCallbackEvent,
  12. },
  13. traced_client::{
  14. RpcMetrics,
  15. TracedClient,
  16. },
  17. },
  18. config::EthereumConfig,
  19. },
  20. anyhow::{
  21. anyhow,
  22. Error,
  23. Result,
  24. },
  25. axum::async_trait,
  26. ethers::{
  27. abi::RawLog,
  28. contract::{
  29. abigen,
  30. EthLogDecode,
  31. },
  32. core::types::Address,
  33. middleware::{
  34. gas_oracle::GasOracleMiddleware,
  35. MiddlewareError,
  36. NonceManagerMiddleware,
  37. SignerMiddleware,
  38. },
  39. prelude::{
  40. BlockId,
  41. JsonRpcClient,
  42. PendingTransaction,
  43. TransactionRequest,
  44. },
  45. providers::{
  46. Http,
  47. Middleware,
  48. Provider,
  49. },
  50. signers::{
  51. LocalWallet,
  52. Signer,
  53. },
  54. types::{
  55. transaction::eip2718::TypedTransaction,
  56. BlockNumber as EthersBlockNumber,
  57. U256,
  58. },
  59. },
  60. sha3::{
  61. Digest,
  62. Keccak256,
  63. },
  64. std::sync::Arc,
  65. thiserror::Error,
  66. };
  67. // TODO: Programmatically generate this so we don't have to keep committed ABI in sync with the
  68. // contract in the same repo.
  69. abigen!(
  70. PythRandom,
  71. "../../target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json"
  72. );
  73. pub type SignablePythContractInner<T> = PythRandom<
  74. LegacyTxMiddleware<
  75. GasOracleMiddleware<
  76. NonceManagerMiddleware<SignerMiddleware<Provider<T>, LocalWallet>>,
  77. EthProviderOracle<Provider<T>>,
  78. >,
  79. >,
  80. >;
  81. pub type SignablePythContract = SignablePythContractInner<Http>;
  82. pub type InstrumentedSignablePythContract = SignablePythContractInner<TracedClient>;
  83. pub type PythContract = PythRandom<Provider<Http>>;
  84. pub type InstrumentedPythContract = PythRandom<Provider<TracedClient>>;
  85. /// Middleware that converts a transaction into a legacy transaction if use_legacy_tx is true.
  86. /// We can not use TransformerMiddleware because keeper calls fill_transaction first which bypasses
  87. /// the transformer.
  88. #[derive(Clone, Debug)]
  89. pub struct LegacyTxMiddleware<M> {
  90. use_legacy_tx: bool,
  91. inner: M,
  92. }
  93. impl<M> LegacyTxMiddleware<M> {
  94. pub fn new(use_legacy_tx: bool, inner: M) -> Self {
  95. Self {
  96. use_legacy_tx,
  97. inner,
  98. }
  99. }
  100. }
  101. #[derive(Error, Debug)]
  102. pub enum LegacyTxMiddlewareError<M: Middleware> {
  103. #[error("{0}")]
  104. MiddlewareError(M::Error),
  105. }
  106. impl<M: Middleware> MiddlewareError for LegacyTxMiddlewareError<M> {
  107. type Inner = M::Error;
  108. fn from_err(src: M::Error) -> Self {
  109. LegacyTxMiddlewareError::MiddlewareError(src)
  110. }
  111. fn as_inner(&self) -> Option<&Self::Inner> {
  112. match self {
  113. LegacyTxMiddlewareError::MiddlewareError(e) => Some(e),
  114. }
  115. }
  116. }
  117. #[async_trait]
  118. impl<M: Middleware> Middleware for LegacyTxMiddleware<M> {
  119. type Error = LegacyTxMiddlewareError<M>;
  120. type Provider = M::Provider;
  121. type Inner = M;
  122. fn inner(&self) -> &M {
  123. &self.inner
  124. }
  125. async fn send_transaction<T: Into<TypedTransaction> + Send + Sync>(
  126. &self,
  127. tx: T,
  128. block: Option<BlockId>,
  129. ) -> std::result::Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
  130. let mut tx = tx.into();
  131. if self.use_legacy_tx {
  132. let legacy_request: TransactionRequest = tx.into();
  133. tx = legacy_request.into();
  134. }
  135. self.inner()
  136. .send_transaction(tx, block)
  137. .await
  138. .map_err(MiddlewareError::from_err)
  139. }
  140. async fn fill_transaction(
  141. &self,
  142. tx: &mut TypedTransaction,
  143. block: Option<BlockId>,
  144. ) -> std::result::Result<(), Self::Error> {
  145. if self.use_legacy_tx {
  146. let legacy_request: TransactionRequest = (*tx).clone().into();
  147. *tx = legacy_request.into();
  148. }
  149. self.inner()
  150. .fill_transaction(tx, block)
  151. .await
  152. .map_err(MiddlewareError::from_err)
  153. }
  154. }
  155. impl<T: JsonRpcClient + 'static + Clone> SignablePythContractInner<T> {
  156. /// Get the wallet that signs transactions sent to this contract.
  157. pub fn wallet(&self) -> LocalWallet {
  158. self.client().inner().inner().inner().signer().clone()
  159. }
  160. /// Get the underlying provider that communicates with the blockchain.
  161. pub fn provider(&self) -> Provider<T> {
  162. self.client().inner().inner().inner().provider().clone()
  163. }
  164. /// Submit a request for a random number to the contract.
  165. ///
  166. /// This method is a version of the autogenned `request` method that parses the emitted logs
  167. /// to return the sequence number of the created Request.
  168. pub async fn request_wrapper(
  169. &self,
  170. provider: &Address,
  171. user_randomness: &[u8; 32],
  172. use_blockhash: bool,
  173. ) -> Result<u64> {
  174. let fee = self.get_fee(*provider).call().await?;
  175. let hashed_randomness: [u8; 32] = Keccak256::digest(user_randomness).into();
  176. if let Some(r) = self
  177. .request(*provider, hashed_randomness, use_blockhash)
  178. .value(fee)
  179. .send()
  180. .await?
  181. .await?
  182. {
  183. // Extract Log from TransactionReceipt.
  184. let l: RawLog = r.logs[0].clone().into();
  185. if let PythRandomEvents::RequestedFilter(r) = PythRandomEvents::decode_log(&l)? {
  186. Ok(r.request.sequence_number)
  187. } else {
  188. Err(anyhow!("No log with sequence number").into())
  189. }
  190. } else {
  191. Err(anyhow!("Request failed").into())
  192. }
  193. }
  194. /// Reveal the generated random number to the contract.
  195. ///
  196. /// This method is a version of the autogenned `reveal` method that parses the emitted logs
  197. /// to return the generated random number.
  198. pub async fn reveal_wrapper(
  199. &self,
  200. provider: &Address,
  201. sequence_number: u64,
  202. user_randomness: &[u8; 32],
  203. provider_randomness: &[u8; 32],
  204. ) -> Result<[u8; 32]> {
  205. if let Some(r) = self
  206. .reveal(
  207. *provider,
  208. sequence_number,
  209. *user_randomness,
  210. *provider_randomness,
  211. )
  212. .send()
  213. .await?
  214. .await?
  215. {
  216. if let PythRandomEvents::RevealedFilter(r) =
  217. PythRandomEvents::decode_log(&r.logs[0].clone().into())?
  218. {
  219. Ok(r.random_number)
  220. } else {
  221. Err(anyhow!("No log with randomnumber").into())
  222. }
  223. } else {
  224. Err(anyhow!("Request failed").into())
  225. }
  226. }
  227. pub async fn from_config_and_provider(
  228. chain_config: &EthereumConfig,
  229. private_key: &str,
  230. provider: Provider<T>,
  231. ) -> Result<SignablePythContractInner<T>> {
  232. let chain_id = provider.get_chainid().await?;
  233. let gas_oracle = EthProviderOracle::new(provider.clone());
  234. let wallet__ = private_key
  235. .parse::<LocalWallet>()?
  236. .with_chain_id(chain_id.as_u64());
  237. let address = wallet__.address();
  238. Ok(PythRandom::new(
  239. chain_config.contract_addr,
  240. Arc::new(LegacyTxMiddleware::new(
  241. chain_config.legacy_tx,
  242. GasOracleMiddleware::new(
  243. NonceManagerMiddleware::new(SignerMiddleware::new(provider, wallet__), address),
  244. gas_oracle,
  245. ),
  246. )),
  247. ))
  248. }
  249. }
  250. impl SignablePythContract {
  251. pub async fn from_config(chain_config: &EthereumConfig, private_key: &str) -> Result<Self> {
  252. let provider = Provider::<Http>::try_from(&chain_config.geth_rpc_addr)?;
  253. Self::from_config_and_provider(chain_config, private_key, provider).await
  254. }
  255. }
  256. impl InstrumentedSignablePythContract {
  257. pub async fn from_config(
  258. chain_config: &EthereumConfig,
  259. private_key: &str,
  260. chain_id: ChainId,
  261. metrics: Arc<RpcMetrics>,
  262. ) -> Result<Self> {
  263. let provider = TracedClient::new(chain_id, &chain_config.geth_rpc_addr, metrics)?;
  264. Self::from_config_and_provider(chain_config, private_key, provider).await
  265. }
  266. }
  267. impl PythContract {
  268. pub fn from_config(chain_config: &EthereumConfig) -> Result<Self> {
  269. let provider = Provider::<Http>::try_from(&chain_config.geth_rpc_addr)?;
  270. Ok(PythRandom::new(
  271. chain_config.contract_addr,
  272. Arc::new(provider),
  273. ))
  274. }
  275. }
  276. impl InstrumentedPythContract {
  277. pub fn from_config(
  278. chain_config: &EthereumConfig,
  279. chain_id: ChainId,
  280. metrics: Arc<RpcMetrics>,
  281. ) -> Result<Self> {
  282. let provider = TracedClient::new(chain_id, &chain_config.geth_rpc_addr, metrics)?;
  283. Ok(PythRandom::new(
  284. chain_config.contract_addr,
  285. Arc::new(provider),
  286. ))
  287. }
  288. }
  289. #[async_trait]
  290. impl<T: JsonRpcClient + 'static> EntropyReader for PythRandom<Provider<T>> {
  291. async fn get_request(
  292. &self,
  293. provider_address: Address,
  294. sequence_number: u64,
  295. ) -> Result<Option<reader::Request>> {
  296. let r = self
  297. .get_request(provider_address, sequence_number)
  298. // TODO: This doesn't work for lighlink right now. Figure out how to do this in lightlink
  299. // .block(ethers::core::types::BlockNumber::Finalized)
  300. .call()
  301. .await?;
  302. // sequence_number == 0 means the request does not exist.
  303. if r.sequence_number != 0 {
  304. Ok(Some(reader::Request {
  305. provider: r.provider,
  306. sequence_number: r.sequence_number,
  307. block_number: r.block_number.try_into()?,
  308. use_blockhash: r.use_blockhash,
  309. }))
  310. } else {
  311. Ok(None)
  312. }
  313. }
  314. async fn get_block_number(&self, confirmed_block_status: BlockStatus) -> Result<BlockNumber> {
  315. let block_number: EthersBlockNumber = confirmed_block_status.into();
  316. let block = self
  317. .client()
  318. .get_block(block_number)
  319. .await?
  320. .ok_or_else(|| Error::msg("pending block confirmation"))?;
  321. Ok(block
  322. .number
  323. .ok_or_else(|| Error::msg("pending confirmation"))?
  324. .as_u64())
  325. }
  326. async fn get_request_with_callback_events(
  327. &self,
  328. from_block: BlockNumber,
  329. to_block: BlockNumber,
  330. ) -> Result<Vec<RequestedWithCallbackEvent>> {
  331. let mut event = self.requested_with_callback_filter();
  332. event.filter = event.filter.from_block(from_block).to_block(to_block);
  333. let res: Vec<RequestedWithCallbackFilter> = event.query().await?;
  334. Ok(res
  335. .iter()
  336. .map(|r| RequestedWithCallbackEvent {
  337. sequence_number: r.sequence_number,
  338. user_random_number: r.user_random_number,
  339. provider_address: r.request.provider,
  340. })
  341. .collect())
  342. }
  343. async fn estimate_reveal_with_callback_gas(
  344. &self,
  345. provider: Address,
  346. sequence_number: u64,
  347. user_random_number: [u8; 32],
  348. provider_revelation: [u8; 32],
  349. ) -> Result<U256> {
  350. let result = self
  351. .reveal_with_callback(
  352. provider,
  353. sequence_number,
  354. user_random_number,
  355. provider_revelation,
  356. )
  357. .estimate_gas()
  358. .await;
  359. result.map_err(|e| e.into())
  360. }
  361. }