Skip to content

Commit

Permalink
Log Tenderly Simulation URL (#1839)
Browse files Browse the repository at this point in the history
This PR does a few of things:

- Adds `TRACE` logs to Tenderly API implementation (this was used to
figure out how the `id` could be extracted from the Tenderly simulation
response).
- Parses the `id` field from the simulation result
- Builds and logs the URL for the simulation if it was saved.

### Test Plan

Run the orderbook - make sure to enable saving on trade simulations:

```shell
cargo run -p orderbook -- --trade-simulator Tenderly --tenderly-save-successful-trade-simulations true
```

Then, issue a verified quote:

```shell
curl -s http://localhost:8080/api/v1/quote -X POST -H 'content-type: application/json' --data '@-' <<JSON | jq
{
  "from": "0xa03be496e67ec29bc62f01a428683d7f9c204930",
  "sellToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
  "buyToken": "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB",
  "kind": "sell",
  "sellAmountBeforeFee": "100000000000000000000",
  "priceQuality": "verified"
}
JSON
```

Observe the log:
```
2023-09-04T13:30:42.231Z DEBUG request{id="0"}: shared::code_simulation: saved simulation url=https://dashboard.tenderly.co/gp-v2/nick/simulator/00b00269-6b8a-46a2-a640-f8596f1f7302
```
  • Loading branch information
Nicholas Rodrigues Lordello authored Sep 4, 2023
1 parent 72daad2 commit 27fa754
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 15 deletions.
9 changes: 9 additions & 0 deletions crates/shared/src/code_simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ impl CodeSimulating for TenderlyCodeSimulator {
})
.await?;

let saved = self.save.on_success && result.transaction.status
|| self.save.on_failure && !result.transaction.status;
if saved {
tracing::debug!(
url =% self.tenderly.simulation_url(&result.simulation.id),
"saved simulation"
);
}

let trace = result
.transaction
.call_trace
Expand Down
12 changes: 11 additions & 1 deletion crates/shared/src/price_estimation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,14 @@ pub struct Arguments {
#[clap(long, env)]
pub trade_simulator: Option<CodeSimulatorKind>,

/// Flag to enable saving Tenderly simulations in the dashboard for
/// successful trade simulations.
#[clap(long, env, action = clap::ArgAction::Set, default_value = "false")]
pub tenderly_save_successful_trade_simulations: bool,

/// Flag to enable saving Tenderly simulations in the dashboard for failed
/// trade simulations. This helps debugging reverted quote simulations.
#[clap(long, env)]
#[clap(long, env, action = clap::ArgAction::Set, default_value = "false")]
pub tenderly_save_failed_trade_simulations: bool,

/// Controls if we try to predict the winning price estimator for a given
Expand Down Expand Up @@ -307,6 +312,11 @@ impl Display for Arguments {
.as_ref()
.map(|value| format!("{value:?}")),
)?;
writeln!(
f,
"tenderly_save_successful_trade_simulations: {}",
self.tenderly_save_successful_trade_simulations
)?;
writeln!(
f,
"tenderly_save_failed_trade_simulations: {}",
Expand Down
8 changes: 4 additions & 4 deletions crates/shared/src/price_estimation/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ impl<'a> PriceEstimatorFactory<'a> {
CodeSimulatorKind::Web3 => {
Arc::new(web3_simulator()?) as Arc<dyn CodeSimulating>
}
CodeSimulatorKind::Tenderly => Arc::new(
tenderly_simulator()?
.save(false, args.tenderly_save_failed_trade_simulations),
),
CodeSimulatorKind::Tenderly => Arc::new(tenderly_simulator()?.save(
args.tenderly_save_successful_trade_simulations,
args.tenderly_save_failed_trade_simulations,
)),
CodeSimulatorKind::Web3ThenTenderly => {
Arc::new(code_simulation::Web3ThenTenderly::new(
web3_simulator()?,
Expand Down
52 changes: 42 additions & 10 deletions crates/shared/src/tenderly_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ use {
#[async_trait::async_trait]
pub trait TenderlyApi: Send + Sync + 'static {
async fn simulate(&self, simulation: SimulationRequest) -> Result<SimulationResponse>;
fn simulation_url(&self, id: &str) -> Url;
}

const BASE_URL: &str = "https://api.tenderly.co/api";
const API_URL: &str = "https://api.tenderly.co";
const DASHBOARD_URL: &str = "https://dashboard.tenderly.co";

/// Tenderly HTTP API.
pub struct TenderlyHttpApi {
url: Url,
api: Url,
dashboard: Url,
client: reqwest::Client,
}

Expand All @@ -51,7 +54,10 @@ impl TenderlyHttpApi {
headers.insert("x-access-key", api_key);

Ok(Self {
url: Url::parse(&format!("{BASE_URL}/v1/account/{user}/project/{project}/"))?,
api: Url::parse(&format!(
"{API_URL}/api/v1/account/{user}/project/{project}/"
))?,
dashboard: Url::parse(&format!("{DASHBOARD_URL}/{user}/{project}/"))?,
client: http_factory.configure(|builder| builder.default_headers(headers)),
})
}
Expand All @@ -73,15 +79,31 @@ impl TenderlyHttpApi {
#[async_trait::async_trait]
impl TenderlyApi for TenderlyHttpApi {
async fn simulate(&self, simulation: SimulationRequest) -> Result<SimulationResponse> {
Ok(self
let url = crate::url::join(&self.api, "simulate");
let body = serde_json::to_string(&simulation)?;
tracing::trace!(%url, %body, "simulating");

let response = self
.client
.post(crate::url::join(&self.url, "simulate"))
.json(&simulation)
.post(url)
.header("content-type", "application/json")
.body(body)
.send()
.await?
.error_for_status()?
.json()
.await?)
.await?;

let ok = response.error_for_status_ref().map(|_| ());
let status = response.status();
let body = response.text().await?;
// NOTE: Turn these logs on at your own risk... The Tenderly response
// objects are huge (order of ~3M).
tracing::trace!(status =% status.as_u16(), %body, "simulated");

ok?;
Ok(serde_json::from_str(&body)?)
}

fn simulation_url(&self, id: &str) -> Url {
crate::url::join(&self.dashboard, &format!("simulator/{id}"))
}
}

Expand Down Expand Up @@ -109,6 +131,10 @@ impl TenderlyApi for Instrumented {

result
}

fn simulation_url(&self, id: &str) -> Url {
self.inner.simulation_url(id)
}
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -169,6 +195,7 @@ pub struct StateObject {
pub struct SimulationResponse {
pub transaction: Transaction,
pub generated_access_list: Option<Vec<AccessListItem>>,
pub simulation: Simulation,
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -208,6 +235,11 @@ impl From<AccessListItem> for web3::types::AccessListItem {
}
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct Simulation {
pub id: String,
}

/// Tenderly API arguments.
#[derive(Debug, Parser)]
#[group(skip)]
Expand Down

0 comments on commit 27fa754

Please sign in to comment.