linera_sdk/
ethereum.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Support for Linera applications that interact with Ethereum or other EVM contracts.
5
6use std::fmt::Debug;
7
8use async_graphql::scalar;
9use async_trait::async_trait;
10use linera_base::http;
11pub use linera_ethereum::{
12    client::EthereumQueries,
13    common::{EthereumDataType, EthereumEvent},
14};
15use linera_ethereum::{client::JsonRpcClient, common::EthereumServiceError};
16use serde::{Deserialize, Serialize};
17
18use crate::{
19    contract::wit::base_runtime_api as contract_wit, service::wit::base_runtime_api as service_wit,
20};
21
22// TODO(#3143): Unify the two types into a single `EthereumClient` type.
23
24/// A wrapper for a URL that implements `JsonRpcClient` and uses the JSON oracle to make requests.
25#[derive(Debug, Default, Deserialize, Serialize)]
26pub struct ContractEthereumClient {
27    /// The URL of the JSON-RPC server, without the method or parameters.
28    pub url: String,
29}
30scalar!(ContractEthereumClient);
31
32impl ContractEthereumClient {
33    /// Creates a new [`ContractEthereumClient`] from an URL.
34    pub fn new(url: String) -> Self {
35        Self { url }
36    }
37}
38
39#[async_trait]
40impl JsonRpcClient for ContractEthereumClient {
41    type Error = EthereumServiceError;
42
43    async fn get_id(&self) -> u64 {
44        1
45    }
46
47    async fn request_inner(&self, payload: Vec<u8>) -> Result<Vec<u8>, Self::Error> {
48        let response = contract_wit::perform_http_request(
49            &http::Request {
50                method: http::Method::Post,
51                url: self.url.clone(),
52                headers: Vec::from([http::Header::new("Content-Type", b"application/json")]),
53                body: payload,
54            }
55            .into(),
56        );
57
58        Ok(response.body)
59    }
60}
61
62/// A wrapper for a URL that implements `JsonRpcClient` and uses the JSON oracle to make requests.
63#[derive(Debug, Default, Deserialize, Serialize)]
64pub struct ServiceEthereumClient {
65    /// The URL of the JSON-RPC server, without the method or parameters.
66    pub url: String,
67}
68scalar!(ServiceEthereumClient);
69
70impl ServiceEthereumClient {
71    /// Creates a new [`ServiceEthereumClient`] from an URL.
72    pub fn new(url: String) -> Self {
73        Self { url }
74    }
75}
76
77#[async_trait]
78impl JsonRpcClient for ServiceEthereumClient {
79    type Error = EthereumServiceError;
80
81    async fn get_id(&self) -> u64 {
82        1
83    }
84
85    async fn request_inner(&self, payload: Vec<u8>) -> Result<Vec<u8>, Self::Error> {
86        let response = service_wit::perform_http_request(
87            &http::Request {
88                method: http::Method::Post,
89                url: self.url.clone(),
90                headers: Vec::from([http::Header::new("Content-Type", b"application/json")]),
91                body: payload,
92            }
93            .into(),
94        );
95
96        Ok(response.body)
97    }
98}