Skip to content

Commit

Permalink
Merge pull request #782 from rainlanguage/2024-08-21-cli-calldata
Browse files Browse the repository at this point in the history
  • Loading branch information
hardyjosh authored Aug 23, 2024
2 parents 5398541 + 08123c3 commit 8f76973
Show file tree
Hide file tree
Showing 7 changed files with 504 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ reqwest = { workspace = true }
rust-bigint = { workspace = true }
serde = { workspace = true }
serde_bytes = { workspace = true }
# tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ['env-filter'] }
comfy-table = { workspace = true }
Expand All @@ -32,4 +31,7 @@ chrono = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[target.'cfg(target_family = "wasm")'.dependencies]
tokio = { workspace = true, features = ["sync", "macros", "io-util", "rt", "time"] }
tokio = { workspace = true, features = ["sync", "macros", "io-util", "rt", "time"] }

[dev-dependencies]
httpmock = "0.7.0"
250 changes: 250 additions & 0 deletions crates/cli/src/commands/order/calldata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
use crate::execute::Execute;
use crate::output::{output, SupportedOutputEncoding};
use alloy::sol_types::SolCall;
use anyhow::{anyhow, Result};
use clap::Parser;
use rain_orderbook_common::add_order::AddOrderArgs;
use rain_orderbook_common::dotrain_order::DotrainOrder;
use std::fs::read_to_string;
use std::ops::Deref;
use std::path::PathBuf;

#[derive(Parser, Clone)]
pub struct AddOrderCalldata {
#[arg(
short = 'f',
long,
help = "Path to the .rain file specifying the order"
)]
dotrain_file: PathBuf,

#[arg(short = 'c', long, help = "Path to the settings yaml file")]
settings_file: Option<PathBuf>,

#[arg(short = 'e', long, help = "Deployment key to select from frontmatter")]
deployment: String,

#[arg(short = 'o', long, help = "Output encoding", default_value = "binary")]
encoding: SupportedOutputEncoding,
}

impl Execute for AddOrderCalldata {
async fn execute(&self) -> Result<()> {
let dotrain = read_to_string(self.dotrain_file.clone()).map_err(|e| anyhow!(e))?;
let settings = match &self.settings_file {
Some(settings_file) => {
Some(read_to_string(settings_file.clone()).map_err(|e| anyhow!(e))?)
}
None => None,
};
let order = DotrainOrder::new(dotrain, settings).await?;
let dotrain_string = order.dotrain.clone();

let config_deployment = order
.config
.deployments
.get(&self.deployment)
.ok_or(anyhow!("specified deployment is undefined!"))?;

let add_order_args =
AddOrderArgs::new_from_deployment(dotrain_string, config_deployment.deref().clone())
.await;

let add_order_calldata = add_order_args?
.try_into_call(config_deployment.scenario.deployer.network.rpc.to_string())
.await?
.abi_encode();

output(&None, self.encoding.clone(), &add_order_calldata)?;

Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use alloy::primitives::{hex::encode_prefixed, Address, Bytes, B256};
use alloy::sol_types::SolValue;
use alloy_ethers_typecast::rpc::Response;
use clap::CommandFactory;
use httpmock::MockServer;
use std::str::FromStr;

#[test]
fn verify_cli() {
AddOrderCalldata::command().debug_assert();
}

#[test]
fn test_cli_args() {
let dotrain_file = PathBuf::from_str("./some/dotrain_file.rain").unwrap();
let settings_file = PathBuf::from_str("./some/settings_file.rain").unwrap();
let deployment_str = "some-deployment";
let output_str = "hex";

let cmd = AddOrderCalldata::command();
let result = cmd
.try_get_matches_from(vec![
"cmd",
"-f",
dotrain_file.to_str().unwrap(),
"-c",
settings_file.to_str().unwrap(),
"-e",
deployment_str,
"-o",
output_str,
])
.unwrap();
assert_eq!(
result.get_one::<PathBuf>("dotrain_file"),
Some(&dotrain_file)
);
assert_eq!(
result.get_one::<PathBuf>("settings_file"),
Some(&settings_file)
);
assert_eq!(
result.get_one::<String>("deployment"),
Some(&deployment_str.to_string())
);
assert_eq!(
result.get_one::<SupportedOutputEncoding>("encoding"),
Some(&SupportedOutputEncoding::Hex)
);
}

#[tokio::test]
async fn test_execute() {
let rpc_server = MockServer::start_async().await;
let dotrain = format!(
"
networks:
some-network:
rpc: {}
chain-id: 123
network-id: 123
currency: ETH
subgraphs:
some-sg: https://www.some-sg.com
deployers:
some-deployer:
network: some-network
address: 0xF14E09601A47552De6aBd3A0B165607FaFd2B5Ba
orderbooks:
some-orderbook:
address: 0xc95A5f8eFe14d7a20BD2E5BAFEC4E71f8Ce0B9A6
network: some-network
subgraph: some-sg
tokens:
token1:
network: some-network
address: 0xc2132d05d31c914a87c6611c10748aeb04b58e8f
decimals: 6
label: T1
symbol: T1
token2:
network: some-network
address: 0x8f3cf7ad23cd3cadbd9735aff958023239c6a063
decimals: 18
label: T2
symbol: T2
scenarios:
some-scenario:
network: some-network
deployer: some-deployer
orders:
some-order:
inputs:
- token: token1
vault-id: 1
outputs:
- token: token2
vault-id: 1
deployer: some-deployer
orderbook: some-orderbook
deployments:
some-deployment:
scenario: some-scenario
order: some-order
---
#calculate-io
_ _: 0 0;
#handle-io
:;
#post-add-order
:;",
rpc_server.url("/rpc").as_str()
);

let dotrain_path = "./test_dotrain1.rain";
std::fs::write(dotrain_path, dotrain).unwrap();

// mock rpc response data
// mock iInterpreter() call
rpc_server.mock(|when, then| {
when.path("/rpc").body_contains("0xf0cfdd37");
then.body(
Response::new_success(
1,
&B256::left_padding_from(Address::random().as_slice()).to_string(),
)
.to_json_string()
.unwrap(),
);
});
// mock iStore() call
rpc_server.mock(|when, then| {
when.path("/rpc").body_contains("0xc19423bc");
then.body(
Response::new_success(
2,
&B256::left_padding_from(Address::random().as_slice()).to_string(),
)
.to_json_string()
.unwrap(),
);
});
// mock iParser() call
rpc_server.mock(|when, then| {
when.path("/rpc").body_contains("0x24376855");
then.body(
Response::new_success(
3,
&B256::left_padding_from(Address::random().as_slice()).to_string(),
)
.to_json_string()
.unwrap(),
);
});
// mock parse2() call
rpc_server.mock(|when, then| {
when.path("/rpc").body_contains("0xa3869e14");
then.body(
Response::new_success(4, &encode_prefixed(Bytes::from(vec![1, 2]).abi_encode()))
.to_json_string()
.unwrap(),
);
});

let add_order_calldata = AddOrderCalldata {
dotrain_file: dotrain_path.into(),
settings_file: None,
deployment: "some-deployment".to_string(),
encoding: SupportedOutputEncoding::Hex,
};
// should succeed without err
add_order_calldata.execute().await.unwrap();

// remove test file
std::fs::remove_file(dotrain_path).unwrap();
}
}
19 changes: 19 additions & 0 deletions crates/cli/src/commands/order/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
mod add;
mod calldata;
mod compose;
mod detail;
mod list;
mod orderbook_address;
mod remove;

use crate::commands::order::orderbook_address::OrderbookAddress;
use crate::execute::Execute;
use add::CliOrderAddArgs;
use anyhow::Result;
use calldata::AddOrderCalldata;
use clap::Parser;
use compose::Compose;

use detail::CliOrderDetailArgs;
use list::CliOrderListArgs;
use remove::CliOrderRemoveArgs;
Expand All @@ -29,6 +34,18 @@ pub enum Order {

#[command(about = "Compose a .rain order file to Rainlang", alias = "comp")]
Compose(Compose),

#[command(
about = "Generate calldata for addOrder from a composition",
alias = "call"
)]
Calldata(AddOrderCalldata),

#[command(
about = "Get the orderbook address for a given order",
alias = "ob-addr"
)]
OrderbookAddress(OrderbookAddress),
}

impl Execute for Order {
Expand All @@ -39,6 +56,8 @@ impl Execute for Order {
Order::Create(create) => create.execute().await,
Order::Remove(remove) => remove.execute().await,
Order::Compose(compose) => compose.execute().await,
Order::Calldata(calldata) => calldata.execute().await,
Order::OrderbookAddress(orderbook_address) => orderbook_address.execute().await,
}
}
}
Loading

0 comments on commit 8f76973

Please sign in to comment.