forked from interledger/interledger-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(eth-se): fixed ethereum settlement engine to take environment va…
…riables Signed-off-by: Taiga Nakayama <dora@dora-gt.jp> interledger#194
- Loading branch information
Showing
4 changed files
with
198 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,106 +1,209 @@ | ||
use clap::{value_t, App, Arg, SubCommand}; | ||
use config::{Source, Value, *}; | ||
use std::collections::{hash_map::RandomState, HashMap}; | ||
use std::str::FromStr; | ||
use structopt::StructOpt; | ||
use tokio; | ||
use url::Url; | ||
|
||
use interledger_settlement_engines::engines::ethereum_ledger::{run_ethereum_engine, EthAddress}; | ||
|
||
#[allow(clippy::cognitive_complexity)] | ||
pub fn main() { | ||
env_logger::init(); | ||
let opt = CliOpt::from_args(); | ||
opt.execute(); | ||
} | ||
|
||
// The commands structure | ||
// interledger-settlement-engines | ||
// - ethereum-ledger | ||
|
||
impl CliOpt { | ||
fn execute(&self) { | ||
match &self.sub_command { | ||
TopSubCommands::EthereumLedger(opt) => opt.execute(), | ||
}; | ||
} | ||
} | ||
|
||
impl EthereumLedgerOpt { | ||
fn execute(&self) { | ||
let mut config = config::Config::new(); | ||
config.merge(self.clone()).unwrap(); | ||
config | ||
.merge(config::Environment::with_prefix("ILP")) | ||
.unwrap(); | ||
|
||
let mut app = App::new("interledger-settlement-engines") | ||
.about("Interledger Settlement Engines CLI") | ||
.subcommands(vec![ | ||
SubCommand::with_name("ethereum-ledger") | ||
.about("Ethereum settlement engine which performs ledger (layer 1) transactions") | ||
.args(&[ | ||
Arg::with_name("port") | ||
.long("port") | ||
.help("Port to listen for settlement requests on") | ||
.default_value("3000"), | ||
Arg::with_name("key") | ||
.long("key") | ||
.help("private key for settlement account") | ||
.takes_value(true) | ||
.required(true), | ||
Arg::with_name("ethereum_endpoint") | ||
.long("ethereum_endpoint") | ||
.help("Ethereum node endpoint") | ||
.default_value("http://127.0.0.1:8545"), | ||
Arg::with_name("token_address") | ||
.long("token_address") | ||
.help("The address of the ERC20 token to be used for settlement (defaults to sending ETH if no token address is provided)") | ||
.default_value(""), | ||
Arg::with_name("connector_url") | ||
.long("connector_url") | ||
.help("Connector Settlement API endpoint") | ||
.default_value("http://127.0.0.1:7771"), | ||
Arg::with_name("redis_uri") | ||
.long("redis_uri") | ||
.help("Redis database to add the account to") | ||
.default_value("redis://127.0.0.1:6379"), | ||
Arg::with_name("chain_id") | ||
.long("chain_id") | ||
.help("The chain id so that the signer calculates the v value of the sig appropriately") | ||
.default_value("1"), | ||
Arg::with_name("confirmations") | ||
.long("confirmations") | ||
.help("The number of confirmations the engine will wait for a transaction's inclusion before it notifies the node of its success") | ||
.default_value("6"), | ||
Arg::with_name("asset_scale") | ||
.long("asset_scale") | ||
.help("The asset scale you want to use for your payments (default: 18)") | ||
.default_value("18"), | ||
Arg::with_name("poll_frequency") | ||
.long("poll_frequency") | ||
.help("The frequency in milliseconds at which the engine will check the blockchain about the confirmation status of a tx") | ||
.default_value("5000"), | ||
Arg::with_name("watch_incoming") | ||
.long("watch_incoming") | ||
.help("Launch a blockchain watcher that listens for incoming transactions and notifies the connector upon sufficient confirmations") | ||
.default_value("true"), | ||
]) | ||
] | ||
); | ||
let settlement_port = config.get("port").unwrap(); | ||
// TODO make compatible with | ||
// https://github.com/tendermint/signatory to have HSM sigs | ||
let private_key: String = config.get("key").unwrap(); | ||
let ethereum_endpoint: String = config.get("ethereum_endpoint").unwrap(); | ||
let token_address: String = config.get("token_address").unwrap(); | ||
let token_address = if token_address.len() == 20 { | ||
Some(EthAddress::from_str(&token_address).unwrap()) | ||
} else { | ||
None | ||
}; | ||
let connector_url: String = config.get("connector_url").unwrap(); | ||
let redis_uri: String = config.get("redis_uri").unwrap(); | ||
let redis_uri = Url::parse(&redis_uri).expect("redis_uri is not a valid URI"); | ||
let chain_id = config.get("chain_id").unwrap(); | ||
let confirmations = config.get("confirmations").unwrap(); | ||
let asset_scale = config.get("asset_scale").unwrap(); | ||
let poll_frequency = config.get("poll_frequency").unwrap(); | ||
let watch_incoming = !config.get::<bool>("without_incoming_watcher").unwrap(); | ||
|
||
tokio::run(run_ethereum_engine( | ||
redis_uri, | ||
ethereum_endpoint, | ||
settlement_port, | ||
private_key, | ||
chain_id, | ||
confirmations, | ||
asset_scale, | ||
poll_frequency, | ||
connector_url, | ||
token_address, | ||
watch_incoming, | ||
)); | ||
} | ||
} | ||
|
||
match app.clone().get_matches().subcommand() { | ||
("ethereum-ledger", Some(matches)) => { | ||
let settlement_port = | ||
value_t!(matches, "port", u16).expect("port for settlement engine required"); | ||
// TODO make compatible with | ||
// https://github.com/tendermint/signatory to have HSM sigs | ||
let private_key: String = value_t!(matches, "key", String).unwrap(); | ||
let ethereum_endpoint: String = value_t!(matches, "ethereum_endpoint", String).unwrap(); | ||
let token_address = value_t!(matches, "token_address", String).unwrap(); | ||
let token_address = if token_address.len() == 20 { | ||
Some(EthAddress::from_str(&token_address).unwrap()) | ||
} else { | ||
None | ||
}; | ||
let connector_url: String = value_t!(matches, "connector_url", String).unwrap(); | ||
let redis_uri = value_t!(matches, "redis_uri", String).expect("redis_uri is required"); | ||
let redis_uri = Url::parse(&redis_uri).expect("redis_uri is not a valid URI"); | ||
let chain_id = value_t!(matches, "chain_id", u8).unwrap(); | ||
let confirmations = value_t!(matches, "confirmations", u8).unwrap(); | ||
let asset_scale = value_t!(matches, "asset_scale", u8).unwrap(); | ||
let poll_frequency = value_t!(matches, "poll_frequency", u64).unwrap(); | ||
let watch_incoming = value_t!(matches, "watch_incoming", bool).unwrap(); | ||
impl Source for EthereumLedgerOpt { | ||
fn clone_into_box(&self) -> Box<Source + Send + Sync> { | ||
Box::new(self.clone()) | ||
} | ||
|
||
tokio::run(run_ethereum_engine( | ||
redis_uri, | ||
ethereum_endpoint, | ||
settlement_port, | ||
private_key, | ||
chain_id, | ||
confirmations, | ||
asset_scale, | ||
poll_frequency, | ||
connector_url, | ||
token_address, | ||
watch_incoming, | ||
)); | ||
} | ||
_ => app.print_help().unwrap(), | ||
fn collect(&self) -> Result<HashMap<String, Value, RandomState>, ConfigError> { | ||
let mut hash_map = HashMap::new(); | ||
hash_map.insert("port".to_string(), Value::new(None, self.port as i64)); | ||
hash_map.insert( | ||
"key".to_string(), | ||
Value::new(None, self.key.clone().unwrap_or(String::new())), | ||
); | ||
hash_map.insert( | ||
"ethereum_endpoint".to_string(), | ||
Value::new(None, self.ethereum_endpoint.to_string()), | ||
); | ||
hash_map.insert( | ||
"token_address".to_string(), | ||
Value::new(None, self.token_address.to_string()), | ||
); | ||
hash_map.insert( | ||
"connector_url".to_string(), | ||
Value::new(None, self.connector_url.to_string()), | ||
); | ||
hash_map.insert( | ||
"redis_uri".to_string(), | ||
Value::new(None, self.redis_uri.to_string()), | ||
); | ||
hash_map.insert( | ||
"chain_id".to_string(), | ||
Value::new(None, self.chain_id as i64), | ||
); | ||
hash_map.insert( | ||
"confirmations".to_string(), | ||
Value::new(None, self.confirmations as i64), | ||
); | ||
hash_map.insert( | ||
"asset_scale".to_string(), | ||
Value::new(None, self.asset_scale as i64), | ||
); | ||
hash_map.insert( | ||
"poll_frequency".to_string(), | ||
Value::new(None, self.poll_frequency as i64), | ||
); | ||
hash_map.insert( | ||
"without_incoming_watcher".to_string(), | ||
Value::new(None, self.without_incoming_watcher), | ||
); | ||
Ok(hash_map) | ||
} | ||
} | ||
|
||
#[derive(Debug, StructOpt)] | ||
#[structopt( | ||
name = "interledger-settlement-engines", | ||
about = "Interledger Settlement Engines CLI" | ||
)] | ||
struct CliOpt { | ||
#[structopt(subcommand)] | ||
sub_command: TopSubCommands, | ||
} | ||
|
||
#[derive(Debug, StructOpt)] | ||
enum TopSubCommands { | ||
#[structopt( | ||
name = "ethereum-ledger", | ||
about = "Ethereum settlement engine which performs ledger (layer 1) transactions" | ||
)] | ||
EthereumLedger(EthereumLedgerOpt), | ||
} | ||
|
||
#[derive(Debug, StructOpt, Clone)] | ||
struct EthereumLedgerOpt { | ||
#[structopt( | ||
short = "p", | ||
long = "port", | ||
default_value = "3000", | ||
help = "Port to listen for settlement requests on" | ||
)] | ||
port: u16, | ||
#[structopt(long = "key", help = "private key for settlement account")] | ||
key: Option<String>, | ||
#[structopt( | ||
long = "ethereum_endpoint", | ||
default_value = "http://127.0.0.1:8545", | ||
help = "Ethereum node endpoint" | ||
)] | ||
ethereum_endpoint: String, | ||
#[structopt( | ||
long = "token_address", | ||
default_value = "", | ||
help = "The address of the ERC20 token to be used for settlement (defaults to sending ETH if no token address is provided)" | ||
)] | ||
token_address: String, | ||
#[structopt( | ||
long = "connector_url", | ||
default_value = "http://127.0.0.1:7771", | ||
help = "Connector Settlement API endpoint" | ||
)] | ||
connector_url: String, | ||
#[structopt( | ||
long = "redis_uri", | ||
default_value = "redis://127.0.0.1:6379", | ||
help = "Redis database to add the account to" | ||
)] | ||
redis_uri: String, | ||
// Although the length of `chain_id` seems to be not limited on its specs, | ||
// u8 seems sufficient at this point. | ||
#[structopt( | ||
long = "chain_id", | ||
default_value = "1", | ||
help = "The chain id so that the signer calculates the v value of the sig appropriately" | ||
)] | ||
chain_id: u8, | ||
#[structopt( | ||
long = "confirmations", | ||
default_value = "6", | ||
help = "The number of confirmations the engine will wait for a transaction's inclusion before it notifies the node of its success" | ||
)] | ||
confirmations: u8, | ||
#[structopt( | ||
long = "asset_scale", | ||
default_value = "18", | ||
help = "The asset scale you want to use for your payments (default: 18)" | ||
)] | ||
asset_scale: u8, | ||
#[structopt( | ||
long = "poll_frequency", | ||
default_value = "5000", | ||
help = "The frequency in milliseconds at which the engine will check the blockchain about the confirmation status of a tx" | ||
)] | ||
poll_frequency: u64, | ||
#[structopt( | ||
long = "without_incoming_watcher", | ||
help = "Not launch a blockchain watcher that listens for incoming transactions and notifies the connector upon sufficient confirmations" | ||
)] | ||
without_incoming_watcher: bool, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters