diff --git a/Cargo.lock b/Cargo.lock index 73da37095..dceee7704 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,11 +26,6 @@ name = "approx" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "arrayvec" version = "0.4.11" @@ -77,21 +72,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.37" +version = "0.3.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -119,17 +114,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "block-buffer" -version = "0.3.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "block-buffer" @@ -170,11 +156,6 @@ dependencies = [ "safemem 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byte-tools" version = "0.3.1" @@ -182,7 +163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytecount" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -217,12 +198,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.26" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -261,7 +242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -270,21 +251,21 @@ dependencies = [ [[package]] name = "clarity" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytecount 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "num256 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde-rlp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -292,7 +273,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -376,7 +357,7 @@ name = "crc32fast" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -427,7 +408,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -447,7 +428,7 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -494,14 +475,6 @@ name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "digest" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "digest" version = "0.8.1" @@ -525,7 +498,7 @@ name = "encoding_rs" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -554,7 +527,7 @@ name = "error-chain" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -602,7 +575,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -673,7 +646,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -705,14 +678,6 @@ dependencies = [ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "generic-array" version = "0.12.3" @@ -726,7 +691,7 @@ name = "getrandom" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -770,7 +735,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "headers-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -914,6 +879,15 @@ dependencies = [ "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ilp-cli" +version = "0.0.1" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ilp-node" version = "0.4.1-beta.2" @@ -1208,7 +1182,7 @@ version = "0.1.1-beta.2" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clarity 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "clarity 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1238,7 +1212,7 @@ dependencies = [ "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "secrecy 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1465,7 +1439,7 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1527,7 +1501,7 @@ name = "miniz-sys" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1633,7 +1607,7 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1773,8 +1747,8 @@ name = "openssl" version = "0.10.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1792,7 +1766,7 @@ version = "0.9.49" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1869,7 +1843,7 @@ name = "parking_lot_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1884,7 +1858,7 @@ name = "parking_lot_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1998,7 +1972,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2039,7 +2013,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2347,7 +2321,7 @@ name = "ring" version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2435,10 +2409,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "secp256k1" -version = "0.12.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2532,7 +2507,7 @@ name = "serde_derive" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2609,17 +2584,6 @@ name = "sha1" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "sha3" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sha3" version = "0.8.2" @@ -2713,7 +2677,7 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2742,7 +2706,7 @@ name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3146,7 +3110,7 @@ name = "try_from" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3516,38 +3480,35 @@ dependencies = [ "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" "checksum assert-json-diff 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32946b6d31d50d0e35896c864907f9cb7e47b52bd875fa3c058618601cfdefb1" "checksum atoi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "baa5dc0129ce09c8c87e2714a0b67c095d4a5e3261a7bbb3d7ac44d43d5dd190" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2" -"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61" +"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5" +"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum buf_redux 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c" +"checksum bytecount 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "389803e36973d242e7fecb092b2de44a3d35ac62524b3b9339e51d577d668e02" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" "checksum checked 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e82b46c41844dee0195a9eb4691446e58848996aa3a70d97f4966b48790bae69" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum clarity 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c79ad42ad4a6254fa8c997650b669b766c2267dc801fb701c8c4fabe073b2823" +"checksum clarity 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "d1cb37bb4c73ac0c710e4f27cb8b378c4f369c4effb9792f9ecb4c57687aefad" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" @@ -3568,7 +3529,6 @@ dependencies = [ "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" @@ -3594,7 +3554,6 @@ dependencies = [ "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum futures-retry 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d79b1e875b3ab07ef294b5bd43ae509d0ed1be990389003ea5fcdecf2e62ec96" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum handlebars 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3623110a77811256820e92df1b3b286f6f44f99d1f77a94b75e262c28d5034f4" @@ -3690,7 +3649,7 @@ dependencies = [ "checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" "checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" "checksum publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" @@ -3739,7 +3698,7 @@ dependencies = [ "checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e" +"checksum secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4d311229f403d64002e9eed9964dfa5a0a0c1ac443344f7546bf48e916c6053a" "checksum secrecy 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fab03b6358129d49a63e1e5333349cf1da2432cf3464434a72bbab67818da06a" "checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" "checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" @@ -3759,7 +3718,6 @@ dependencies = [ "checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum sha3 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b64dcef59ed4290b9fb562b53df07f564690d6539e8ecdd4728cf392477530bc" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" diff --git a/Cargo.toml b/Cargo.toml index f3722cfbb..501766abf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ + "./crates/ilp-cli", "./crates/ilp-node", "./crates/interledger", "./crates/interledger-api", diff --git a/crates/ilp-cli/Cargo.toml b/crates/ilp-cli/Cargo.toml new file mode 100644 index 000000000..791c44607 --- /dev/null +++ b/crates/ilp-cli/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ilp-cli" +version = "0.0.1" +description = "Interledger.rs Command-Line Interface" +license = "Apache-2.0" +edition = "2018" +repository = "https://github.com/interledger-rs/interledger-rs" + +[dependencies] +clap = { version = "2.33.0", default-features = false } +reqwest = { version = "0.9.20", default-features = false, features = ["default-tls"] } +serde = "1.0.101" \ No newline at end of file diff --git a/crates/ilp-cli/src/interpreter.rs b/crates/ilp-cli/src/interpreter.rs new file mode 100644 index 000000000..5ab34bd02 --- /dev/null +++ b/crates/ilp-cli/src/interpreter.rs @@ -0,0 +1,316 @@ +use clap::ArgMatches; +use reqwest::{self, Client, Response}; +use std::collections::HashMap; + +#[derive(Debug)] +pub enum Error { + UsageErr(&'static str), + ClientErr(reqwest::Error), +} + +pub fn run(matches: &ArgMatches) -> Result { + let client = NodeClient { + client: Client::new(), + // `--node` has a a default value, so will never be None + url: matches.value_of("node_url").unwrap(), + }; + + // Dispatch based on parsed input + match matches.subcommand() { + // Execute the specified subcommand + (ilp_cli_subcommand, Some(ilp_cli_matches)) => { + // Send HTTP request + match ilp_cli_subcommand { + "accounts" => match ilp_cli_matches.subcommand() { + (accounts_subcommand, Some(accounts_matches)) => match accounts_subcommand { + "balance" => client.get_account_balance(accounts_matches), + "create" => client.post_accounts(accounts_matches), + "delete" => client.delete_account(accounts_matches), + "incoming-payments" => { + client.ws_account_payments_incoming(accounts_matches) + } + "info" => client.get_account(accounts_matches), + "list" => client.get_accounts(accounts_matches), + "update" => client.put_account(accounts_matches), + "update-settings" => client.put_account_settings(accounts_matches), + command => panic!("Unhandled `ilp-cli accounts` subcommand: {}", command), + }, + _ => Err(Error::UsageErr("ilp-cli help accounts")), + }, + "pay" => client.post_account_payments(ilp_cli_matches), + "rates" => match ilp_cli_matches.subcommand() { + (rates_subcommand, Some(rates_matches)) => match rates_subcommand { + "list" => client.get_rates(rates_matches), + "set-all" => client.put_rates(rates_matches), + command => panic!("Unhandled `ilp-cli rates` subcommand: {}", command), + }, + _ => Err(Error::UsageErr("ilp-cli help rates")), + }, + "routes" => match ilp_cli_matches.subcommand() { + (routes_subcommand, Some(routes_matches)) => match routes_subcommand { + "list" => client.get_routes(routes_matches), + "set" => client.put_route_static(routes_matches), + "set-all" => client.put_routes_static(routes_matches), + command => panic!("Unhandled `ilp-cli routes` subcommand: {}", command), + }, + _ => Err(Error::UsageErr("ilp-cli help routes")), + }, + "settlement-engines" => match ilp_cli_matches.subcommand() { + (settlement_engines_subcommand, Some(settlement_engines_matches)) => { + match settlement_engines_subcommand { + "set-all" => client.put_settlement_engines(settlement_engines_matches), + command => panic!( + "Unhandled `ilp-cli settlement-engines` subcommand: {}", + command + ), + } + } + _ => Err(Error::UsageErr("ilp-cli help settlement-engines")), + }, + "status" => client.get_root(ilp_cli_matches), + "testnet" => match ilp_cli_matches.subcommand() { + (testnet_subcommand, Some(testnet_matches)) => match testnet_subcommand { + "setup" => client.xpring_account(testnet_matches), + command => panic!("Unhandled `ilp-cli testnet` subcommand: {}", command), + }, + _ => Err(Error::UsageErr("ilp-cli help testnet")), + }, + command => panic!("Unhandled `ilp-cli` subcommand: {}", command), + } + } + _ => Err(Error::UsageErr("ilp-cli help")), + } +} + +struct NodeClient<'a> { + client: Client, + url: &'a str, +} + +impl NodeClient<'_> { + fn get_account_balance(&self, matches: &ArgMatches) -> Result { + let (auth, mut args) = extract_args(matches); + let user = args.remove("username").unwrap(); + self.client + .get(&format!("{}/accounts/{}/balance", self.url, user)) + .bearer_auth(auth) + .send() + .map_err(Error::ClientErr) + } + + fn post_accounts(&self, matches: &ArgMatches) -> Result { + let (auth, args) = extract_args(matches); + self.client + .post(&format!("{}/accounts/", self.url)) + .bearer_auth(auth) + .json(&args) + .send() + .map_err(Error::ClientErr) + } + + fn put_account(&self, matches: &ArgMatches) -> Result { + let (auth, args) = extract_args(matches); + self.client + .put(&format!("{}/accounts/{}", self.url, args["username"])) + .bearer_auth(auth) + .json(&args) + .send() + .map_err(Error::ClientErr) + } + + fn delete_account(&self, matches: &ArgMatches) -> Result { + let (auth, args) = extract_args(matches); + self.client + .delete(&format!("{}/accounts/{}", self.url, args["username"])) + .bearer_auth(auth) + .send() + .map_err(Error::ClientErr) + } + + fn ws_account_payments_incoming(&self, _matches: &ArgMatches) -> Result { + unimplemented!() + } + + fn get_account(&self, matches: &ArgMatches) -> Result { + let (auth, args) = extract_args(matches); + self.client + .get(&format!("{}/accounts/{}", self.url, args["username"])) + .bearer_auth(auth) + .send() + .map_err(Error::ClientErr) + } + + fn get_accounts(&self, matches: &ArgMatches) -> Result { + let (auth, _) = extract_args(matches); + self.client + .get(&format!("{}/accounts", self.url)) + .bearer_auth(auth) + .send() + .map_err(Error::ClientErr) + } + + fn put_account_settings(&self, matches: &ArgMatches) -> Result { + let (auth, mut args) = extract_args(matches); + let user = args.remove("username").unwrap(); + self.client + .put(&format!("{}/accounts/{}/settings", self.url, user)) + .bearer_auth(auth) + .json(&args) + .send() + .map_err(Error::ClientErr) + } + + fn post_account_payments(&self, matches: &ArgMatches) -> Result { + let (auth, mut args) = extract_args(matches); + let user = args.remove("sender_username").unwrap(); + self.client + .post(&format!("{}/accounts/{}/payments", self.url, user)) + .bearer_auth(&format!("{}:{}", user, auth)) + .json(&args) + .send() + .map_err(Error::ClientErr) + } + + fn get_rates(&self, _matches: &ArgMatches) -> Result { + self.client + .get(&format!("{}/rates", self.url)) + .send() + .map_err(Error::ClientErr) + } + + fn put_rates(&self, matches: &ArgMatches) -> Result { + let (auth, rate_pairs) = unflatten_pairs(matches); + self.client + .put(&format!("{}/rates", self.url)) + .bearer_auth(auth) + .json(&rate_pairs) + .send() + .map_err(Error::ClientErr) + } + + fn get_routes(&self, _matches: &ArgMatches) -> Result { + self.client + .get(&format!("{}/routes", self.url)) + .send() + .map_err(Error::ClientErr) + } + + fn put_route_static(&self, matches: &ArgMatches) -> Result { + let (auth, args) = extract_args(matches); + self.client + .put(&format!("{}/routes/static/{}", self.url, args["prefix"])) + .bearer_auth(auth) + .body(args["destination"].to_string()) + .send() + .map_err(Error::ClientErr) + } + + fn put_routes_static(&self, matches: &ArgMatches) -> Result { + let (auth, route_pairs) = unflatten_pairs(matches); + self.client + .put(&format!("{}/routes/static", self.url)) + .bearer_auth(auth) + .json(&route_pairs) + .send() + .map_err(Error::ClientErr) + } + + fn put_settlement_engines(&self, matches: &ArgMatches) -> Result { + let (auth, engine_pairs) = unflatten_pairs(matches); + self.client + .put(&format!("{}/settlement/engines", self.url)) + .bearer_auth(auth) + .json(&engine_pairs) + .send() + .map_err(Error::ClientErr) + } + + fn get_root(&self, _matches: &ArgMatches) -> Result { + self.client + .get(&format!("{}/", self.url)) + .send() + .map_err(Error::ClientErr) + } + /* + {"http_endpoint": "https://rs3.xpring.dev/ilp", // ilp_over_http_url + "passkey": "b0i3q9tbvfgek", // ilp_over_http_outgoing_token = username:passkey + "btp_endpoint": "btp+wss://rs3.xpring.dev/ilp/btp", // ilp_over_btp_url + "asset_scale": 9, // asset_scale + "node": "rs3.xpring.dev", + "asset_code": "XRP", // asset_code + "username": "user_g31tuju4", // username + "payment_pointer": "$rs3.xpring.dev/accounts/user_g31tuju4/spsp"} + routing_relation Parent + */ + + fn xpring_account(&self, matches: &ArgMatches) -> Result { + let (auth, cli_args) = extract_args(matches); + let asset = cli_args["asset"]; + let foreign_args: XpringResponse = self + .client + .get(&format!("https://stage.xpring.io/api/accounts/{}", asset)) + .send() + .unwrap() + .json() + .unwrap(); + let mut args = HashMap::new(); + args.insert("ilp_over_http_url", foreign_args.http_endpoint.clone()); + args.insert( + "ilp_over_http_outgoing_token", + format!( + "{}:{}", + foreign_args.username.clone(), + foreign_args.passkey.clone() + ), + ); + args.insert("ilp_over_btp_url", foreign_args.btp_endpoint.clone()); + args.insert("asset_scale", foreign_args.asset_scale.to_string()); + args.insert("asset_code", foreign_args.asset_code.clone()); + args.insert("username", format!("xpring_{}", cli_args["asset"])); + args.insert("routing_relation", String::from("Parent")); // TODO: weird behavior when deleting and re-inserting accounts with this + dbg!(&args); + self.client + .post(&format!("{}/accounts/", self.url)) + .bearer_auth(auth) + .json(&args) + .send() + .map_err(Error::ClientErr) + } +} + +// This function takes the map of arguments parsed by Clap +// and extracts the values for each argument. +fn extract_args<'a>(matches: &'a ArgMatches) -> (&'a str, HashMap<&'a str, &'a str>) { + let mut args: HashMap<_, _> = matches // Contains data and metadata about the parsed command + .args // The hashmap containing each parameter along with its values and metadata + .iter() + .map(|(&key, val)| (key, val.vals.get(0))) // Extract raw key/value pairs + .filter(|(_, val)| val.is_some()) // Reject keys that don't have values + .map(|(key, val)| (key, val.unwrap().to_str().unwrap())) // Convert values from bytes to strings + .collect(); + let auth = args.remove("authorization_key").unwrap(); + (auth, args) +} + +fn unflatten_pairs<'a>(matches: &'a ArgMatches) -> (&'a str, HashMap<&'a str, &'a str>) { + let mut pairs = HashMap::new(); + if let Some(halve_matches) = matches.values_of("halve") { + let halves: Vec<&str> = halve_matches.collect(); + for pair in halves.windows(2).step_by(2) { + pairs.insert(pair[0], pair[1]); + } + } + (matches.value_of("authorization_key").unwrap(), pairs) +} + +#[derive(Debug, serde::Deserialize)] +struct XpringResponse { + http_endpoint: String, + passkey: String, + btp_endpoint: String, + asset_scale: u8, + node: String, + asset_code: String, + username: String, + payment_pointer: String, +} diff --git a/crates/ilp-cli/src/main.rs b/crates/ilp-cli/src/main.rs new file mode 100644 index 000000000..5571ea544 --- /dev/null +++ b/crates/ilp-cli/src/main.rs @@ -0,0 +1,204 @@ +mod interpreter; +mod parser; +use std::process::exit; + +pub fn main() { + // 1. Define the arguments to the CLI application + let app = parser::build(); + + // 2. Parse the command line + let matches = app.clone().get_matches(); + + // 3. Interpret this CLI invocation + let result = interpreter::run(&matches); + + // 4. Handle interpreter output + match result { + Err(interpreter::Error::UsageErr(s)) => { + // Clap doesn't seem to have a built-in way of manually printing the + // help text for an arbitrary subcommand, but this works just the same. + app.get_matches_from(s.split(' ')); + } + Err(interpreter::Error::ClientErr(e)) => { + eprintln!("ILP CLI error: failed to send request: {}", e); + exit(1); + } + Ok(mut response) => match response.text() { + Err(e) => { + eprintln!("ILP CLI error: Failed to parse HTTP response: {}", e); + exit(1); + } + Ok(body) => { + if response.status().is_success() { + if !matches.is_present("quiet") { + println!("{}", body); + } + } else { + eprintln!( + "ILP CLI error: Unexpected response from server: {}: {}", + response.status(), + body, + ); + exit(1); + } + } + }, + } +} + +#[cfg(test)] +// Note that this module contains interface tests, not integration tests. +// These exist to detect changes to the parser or interpreter that cause +// breakage to the tool's user-facing interface. +// Since this doesn't require a properly configured (or mocked) server, +// errors from the interpreter are entirely expected, though we still +// run the interpreter in order to detect panics. +// Conveniently this section also serves as a reference for example invocations. +mod interface_tests { + use crate::interpreter; + use crate::parser; + + #[test] + fn ilp_cli() { + should_parse(&[ + "ilp-cli --quiet status", // quiet + "ilp-cli --node bar status", // non-default node + ]); + } + + #[test] + fn accounts_balance() { + should_parse(&[ + "ilp-cli accounts balance alice --auth foo", // minimal + ]); + } + + #[test] + fn accounts_create() { + should_parse(&[ + "ilp-cli accounts create alice --auth foo --asset-code XYZ --asset-scale 6 --ilp-address bar --max-packet-amount 100 --min-balance 0 --ilp-over-http-url qux --ilp-over-http-incoming-token baz --ilp-over-http-outgoing-token qaz --ilp-over-btp-url spam --ilp-over-btp-outgoing-token ham --ilp-over-btp-incoming-token eggs --settle-threshold 0 --settle-to 0 --routing-relation foobar --round-trip-time 1000 --amount-per-minute-limit 42 --packets-per-minute-limit 4 --settlement-engine-url if_you_can_read_this_congratulations_youve_scrolled_too_far_right", // maximal + "ilp-cli accounts create alice --auth foo --asset-code ABC --asset-scale 3 --min-balance -1000 --settle-threshold -10", // negative numbers + ]); + } + + #[test] + fn accounts_update() { + should_parse(&[ + "ilp-cli accounts update alice --auth foo --asset-code ABC --asset-scale 9", // minimal + "ilp-cli accounts update alice --auth foo --asset-code XYZ --asset-scale 6 --ilp-address bar --max-packet-amount 100 --min-balance 0 --ilp-over-http-url qux --ilp-over-http-incoming-token baz --ilp-over-http-outgoing-token qaz --ilp-over-btp-url spam --ilp-over-btp-outgoing-token ham --ilp-over-btp-incoming-token eggs --settle-threshold 0 --settle-to 0 --routing-relation foobar --round-trip-time 1000 --amount-per-minute-limit 42 --packets-per-minute-limit 4 --settlement-engine-url if_you_can_read_this_congratulations_youve_scrolled_too_far_right", // maximal + ]); + } + + #[test] + fn accounts_delete() { + should_parse(&[ + "ilp-cli accounts delete alice --auth foo", // minimal + ]); + } + + #[test] + fn accounts_incoming_payments() {} + + #[test] + fn accounts_info() { + should_parse(&[ + "ilp-cli accounts info alice --auth foo", // minimal + ]); + } + + #[test] + fn accounts_list() { + should_parse(&[ + "ilp-cli accounts list --auth foo", // minimal + ]); + } + + #[test] + fn accounts_update_settings() { + should_parse(&[ + "ilp-cli accounts update-settings alice --auth foo", // minimal + "ilp-cli accounts update-settings alice --auth foo --ilp-over-http-incoming-token bar --ilp-over-btp-incoming-token qux --ilp-over-http-outgoing-token baz --ilp-over-btp-outgoing-token qaz --ilp-over-http-url spam --ilp-over-btp-url eggs --settle-threshold 0 --settle-to 0", // maximal + "ilp-cli accounts update-settings alice --auth foo --settle-threshold -1000 --settle-to -10", // negative numbers + ]); + } + + #[test] + fn pay() { + should_parse(&[ + "ilp-cli pay alice --auth foo --amount 500 --to bar", // minimal + ]); + } + + #[test] + fn rates_list() { + should_parse(&[ + "ilp-cli rates list", // minimal + ]); + } + + #[test] + fn rates_set_all() { + should_parse(&[ + "ilp-cli rates set-all --auth foo", // minimal + "ilp-cli rates set-all --auth foo --pair bar 1.0", // one + "ilp-cli rates set-all --auth foo --pair bar 1.0 --pair qux 2.0", // two + "ilp-cli rates set-all --auth foo --pair bar 1.0 --pair qux 2.0 --pair baz 3.0 --pair qaz 4.0 --pair spam 5.0 --pair ham 6.0 --pair eggs 7.0", // many + ]); + } + + #[test] + fn routes_list() { + should_parse(&[ + "ilp-cli routes list", // minimal + ]); + } + + #[test] + fn routes_set() { + should_parse(&[ + "ilp-cli routes set foo --destination bar --auth baz", // minimal + ]); + } + + #[test] + fn routes_set_all() { + should_parse(&[ + "ilp-cli routes set-all --auth foo", // minimal + "ilp-cli routes set-all --auth foo --pair bar qux", // one + "ilp-cli routes set-all --auth foo --pair bar qux --pair baz qaz", // two + "ilp-cli routes set-all --auth foo --pair bar qux --pair baz qaz --pair spam eggs --pair foobar foobaz", // many + ]) + } + + #[test] + fn settlement_engines_set_all() { + should_parse(&[ + "ilp-cli settlement-engines set-all --auth foo", // minimal + "ilp-cli settlement-engines set-all --auth foo --pair ABC bar", // one + "ilp-cli settlement-engines set-all --auth foo --pair ABC bar --pair DEF qux", // two + "ilp-cli settlement-engines set-all --auth foo --pair ABC bar --pair DEF qux --pair GHI baz --pair JKL qaz --pair MNO spam --pair PQR ham --pair STU eggs", // many + ]); + } + + #[test] + fn status() { + should_parse(&[ + "ilp-cli status", // minimal + ]); + } + + fn should_parse(examples: &[&str]) { + let mut app = parser::build(); + for example in examples { + let parser_result = app.get_matches_from_safe_borrow(example.split(' ')); + match parser_result { + Err(e) => panic!("Failure while parsing command `{}`: {}", example, e), + Ok(matches) => { + // Any unanticipated errors at this stage will result in a panic from + // within the interpreter, so no need to manually check the result. + let _interpreter_result = interpreter::run(&matches); + } + } + } + } +} diff --git a/crates/ilp-cli/src/parser.rs b/crates/ilp-cli/src/parser.rs new file mode 100644 index 000000000..2e33ee823 --- /dev/null +++ b/crates/ilp-cli/src/parser.rs @@ -0,0 +1,407 @@ +use clap::{crate_version, App, AppSettings, Arg, SubCommand}; + +pub fn build<'a, 'b>() -> App<'a, 'b> { + ilp_cli().subcommands(vec![ + accounts().subcommands(vec![ + accounts_balance(), + accounts_create(), + accounts_delete(), + accounts_incoming_payments(), + accounts_info(), + accounts_list(), + accounts_update(), + accounts_update_settings(), + ]), + pay(), + rates().subcommands(vec![rates_list(), rates_set_all()]), + routes().subcommands(vec![routes_list(), routes_set(), routes_set_all()]), + settlement_engines().subcommands(vec![settlement_engines_set_all()]), + status(), + testnet().subcommands(vec![testnet_setup()]), + ]) +} + +struct AuthorizedSubCommand; + +impl AuthorizedSubCommand { + fn with_name(name: &str) -> App { + SubCommand::with_name(name).arg( + Arg::with_name("authorization_key") + .long("auth") + .env("ILP_CLI_API_AUTH") + .required(true) + .help("An HTTP bearer authorization token permitting access to this operation"), + ) + } +} + +fn ilp_cli<'a, 'b>() -> App<'a, 'b> { + App::new("ilp-cli") + .about("Interledger.rs Command-Line Interface") + .version(crate_version!()) + .global_settings(&[ + AppSettings::AllowNegativeNumbers, + AppSettings::VersionlessSubcommands, + //AppSettings::SubcommandRequiredElseHelp, // TODO: re-enable this + ]) + // TODO remove this line once this issue is solved: + // https://github.com/clap-rs/clap/issues/1536 + .after_help("") + .args(&[ + Arg::with_name("node_url") + .long("node") + .env("ILP_CLI_NODE_URL") + .default_value("http://localhost:7770") + .help("The base URL of the node to connect to"), + Arg::with_name("quiet") + .short("q") + .long("quiet") + .help("Disable printing the bodies of successful HTTP responses upon receipt"), + ]) +} + +fn accounts<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("accounts").about("Operations for interacting with accounts") +} + +fn accounts_balance<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("balance") + .about("Returns the balance of an account") + .arg( + Arg::with_name("username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account whose balance to return"), + ) +} + +fn accounts_create<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("create") + .about("Creates a new account on this node") + .args(&[ + Arg::with_name("username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account"), + Arg::with_name("asset_code") + .long("asset-code") + .takes_value(true) + .required(true) + .help("The code of the asset associated with this account"), + Arg::with_name("asset_scale") + .long("asset-scale") + .takes_value(true) + .required(true) + .help("The scale of the asset associated with this account"), + // TODO: when we have a glossary of HTTP API options, add their descriptions to these + Arg::with_name("ilp_address") + .long("ilp-address") + .takes_value(true), + Arg::with_name("max_packet_amount") + .long("max-packet-amount") + .takes_value(true), + Arg::with_name("min_balance") + .long("min-balance") + .takes_value(true), + Arg::with_name("ilp_over_http_url") + .long("ilp-over-http-url") + .takes_value(true), + Arg::with_name("ilp_over_http_incoming_token") + .long("ilp-over-http-incoming-token") + .takes_value(true), + Arg::with_name("ilp_over_http_outgoing_token") + .long("ilp-over-http-outgoing-token") + .takes_value(true), + Arg::with_name("ilp_over_btp_url") + .long("ilp-over-btp-url") + .takes_value(true), + Arg::with_name("ilp_over_btp_outgoing_token") + .long("ilp-over-btp-outgoing-token") + .takes_value(true), + Arg::with_name("ilp_over_btp_incoming_token") + .long("ilp-over-btp-incoming-token") + .takes_value(true), + Arg::with_name("settle_threshold") + .long("settle-threshold") + .takes_value(true), + Arg::with_name("settle_to") + .long("settle-to") + .takes_value(true), + Arg::with_name("routing_relation") + .long("routing-relation") + .takes_value(true), + Arg::with_name("round_trip_time") + .long("round-trip-time") + .takes_value(true), + Arg::with_name("amount_per_minute_limit") + .long("amount-per-minute-limit") + .takes_value(true), + Arg::with_name("packets_per_minute_limit") + .long("packets-per-minute-limit") + .takes_value(true), + Arg::with_name("settlement_engine_url") + .long("settlement-engine-url") + .takes_value(true), + ]) +} + +fn accounts_update<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("update") + .about("Creates a new account on this node") + .args(&[ + Arg::with_name("username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account"), + Arg::with_name("asset_code") + .long("asset-code") + .takes_value(true) + .required(true) + .help("The code of the asset associated with this account"), + Arg::with_name("asset_scale") + .long("asset-scale") + .takes_value(true) + .required(true) + .help("The scale of the asset associated with this account"), + // TODO: when we have a glossary of HTTP API options, add their descriptions to these + Arg::with_name("ilp_address") + .long("ilp-address") + .takes_value(true), + Arg::with_name("max_packet_amount") + .long("max-packet-amount") + .takes_value(true), + Arg::with_name("min_balance") + .long("min-balance") + .takes_value(true), + Arg::with_name("ilp_over_http_url") + .long("ilp-over-http-url") + .takes_value(true), + Arg::with_name("ilp_over_http_incoming_token") + .long("ilp-over-http-incoming-token") + .takes_value(true), + Arg::with_name("ilp_over_http_outgoing_token") + .long("ilp-over-http-outgoing-token") + .takes_value(true), + Arg::with_name("ilp_over_btp_url") + .long("ilp-over-btp-url") + .takes_value(true), + Arg::with_name("ilp_over_btp_outgoing_token") + .long("ilp-over-btp-outgoing-token") + .takes_value(true), + Arg::with_name("ilp_over_btp_incoming_token") + .long("ilp-over-btp-incoming-token") + .takes_value(true), + Arg::with_name("settle_threshold") + .long("settle-threshold") + .takes_value(true), + Arg::with_name("settle_to") + .long("settle-to") + .takes_value(true), + Arg::with_name("routing_relation") + .long("routing-relation") + .takes_value(true), + Arg::with_name("round_trip_time") + .long("round-trip-time") + .takes_value(true), + Arg::with_name("amount_per_minute_limit") + .long("amount-per-minute-limit") + .takes_value(true), + Arg::with_name("packets_per_minute_limit") + .long("packets-per-minute-limit") + .takes_value(true), + Arg::with_name("settlement_engine_url") + .long("settlement-engine-url") + .takes_value(true), + ]) +} + +fn accounts_delete<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("delete") + .about("Delete the given account") + .arg( + Arg::with_name("username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account to delete"), + ) +} + +fn accounts_incoming_payments<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("incoming-payments") + .about("Open a persistent connection to a node for monitoring incoming payments to an account [COMING SOON]") +} + +fn accounts_info<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("info") + .about("View details of a given account") + .arg( + Arg::with_name("username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account to view"), + ) +} + +fn accounts_list<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("list").about("List all accounts on this node") +} + +fn accounts_update_settings<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("update-settings") + .about("Overwrite the details of an account on this node") + .args(&[ + Arg::with_name("username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account"), + Arg::with_name("ilp_over_http_url") + .long("ilp-over-http-url") + .takes_value(true), + Arg::with_name("ilp_over_http_incoming_token") + .long("ilp-over-http-incoming-token") + .takes_value(true), + Arg::with_name("ilp_over_http_outgoing_token") + .long("ilp-over-http-outgoing-token") + .takes_value(true), + Arg::with_name("ilp_over_btp_url") + .long("ilp-over-btp-url") + .takes_value(true), + Arg::with_name("ilp_over_btp_outgoing_token") + .long("ilp-over-btp-outgoing-token") + .takes_value(true), + Arg::with_name("ilp_over_btp_incoming_token") + .long("ilp-over-btp-incoming-token") + .takes_value(true), + Arg::with_name("settle_threshold") + .long("settle-threshold") + .takes_value(true), + Arg::with_name("settle_to") + .long("settle-to") + .takes_value(true), + ]) +} + +fn pay<'a, 'b>() -> App<'a, 'b> { + // TODO: this endpoint currently only works with user authorization, not admin authorization + AuthorizedSubCommand::with_name("pay") + .about("Send a payment from an account on this node") + .args(&[ + Arg::with_name("sender_username") + .index(1) + .takes_value(true) + .required(true) + .help("The username of the account on this node issuing the payment"), + Arg::with_name("source_amount") + .long("amount") + .takes_value(true) + .required(true) + .help("The amount to transfer from the sender to the receiver, denominated in units of the sender's assets"), + Arg::with_name("receiver") + .long("to") + .takes_value(true) + .required(true) + .help("The Payment Pointer or SPSP address of the account receiving the payment"), + ]) +} + +fn rates<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("rates").about("Operations for interacting with exchange rates") +} + +fn rates_list<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("list").about("List the current exchange rates known to this node") +} + +fn rates_set_all<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("set-all") + .about("Overwrite the list of exchange rates used by this node") + .arg( + Arg::with_name("halve") + .long("pair") + .number_of_values(2) + .multiple(true) + .help("A set of space-separated key/value pairs, representing an asset code and an exchange rate; may appear multiple times"), + ) +} + +fn routes<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("routes").about("Operations for interacting with the routing table") +} + +fn routes_list<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("list").about("View this node's routing table") +} + +fn routes_set<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("set") + .about("Configure a single static route on this node") + .args(&[ + Arg::with_name("prefix") + .index(1) + .takes_value(true) + .required(true) + .help("The routing prefix to configure"), + Arg::with_name("destination") + .long("destination") + .takes_value(true) + .required(true) + .help("The destination to associate with the provided prefix"), + ]) +} + +fn routes_set_all<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("set-all") + .about("Overwrite the list of static routes used by this node") + .arg( + Arg::with_name("halve") + .long("pair") + .number_of_values(2) + .multiple(true) + .help("A set of space-separated key/value pairs, representing a route and its destination; may appear multiple times"), + ) +} + +fn settlement_engines<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("settlement-engines") + .about("Interact with the settlement engine configurations") +} + +fn settlement_engines_set_all<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("set-all") + .about("Configure the default settlement engines for given asset codes") + .arg( + Arg::with_name("halve") + .long("pair") + .number_of_values(2) + .multiple(true) + .help("A set of space-separated key/value pairs, representing an asset code and a settlement engine; may appear multiple times"), + ) +} + +fn status<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("status").about("Query the status of the server") +} + +fn testnet<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("testnet").about("Easily access the testnet") +} + +fn testnet_setup<'a, 'b>() -> App<'a, 'b> { + AuthorizedSubCommand::with_name("setup") + .about("Create a local account peered with a remote node on the testnet") + .arg( + Arg::with_name("asset") + .index(1) + .required(true) + .takes_value(true) + .possible_values(&["xrp", "eth"]) + .case_insensitive(true) + .help("The asset that will be tied to the new testnet account"), + ) +} diff --git a/crates/interledger-api/src/lib.rs b/crates/interledger-api/src/lib.rs index 4ba07fcf0..d21c52e60 100644 --- a/crates/interledger-api/src/lib.rs +++ b/crates/interledger-api/src/lib.rs @@ -131,10 +131,12 @@ pub struct AccountSettings { pub ilp_over_btp_outgoing_token: Option, pub ilp_over_http_url: Option, pub ilp_over_btp_url: Option, + #[serde(default, deserialize_with = "optional_number_or_string")] pub settle_threshold: Option, // Note that this is intentionally an unsigned integer because users should // not be able to set the settle_to value to be negative (meaning the node // would pre-fund with the user) + #[serde(default, deserialize_with = "optional_number_or_string")] pub settle_to: Option, } diff --git a/crates/interledger-settlement-engines/Cargo.toml b/crates/interledger-settlement-engines/Cargo.toml index 9c1328627..98ffd0e18 100644 --- a/crates/interledger-settlement-engines/Cargo.toml +++ b/crates/interledger-settlement-engines/Cargo.toml @@ -44,7 +44,7 @@ parking_lot = "0.9.0" config = { version = "0.9.3", features = [ "json", "yaml" ] } libc = "0.2.62" tiny-keccak= {version = "1.4.2", optional = true } -secp256k1 = {version = "0.12", optional = true } +secp256k1 = { version = "0.15.5", optional = true } rlp = { version = "0.4.2", optional = true } ethereum-types = { version = "0.6.0", optional = true } diff --git a/examples/eth-settlement/README.md b/examples/eth-settlement/README.md index d5fb659eb..69073365b 100644 --- a/examples/eth-settlement/README.md +++ b/examples/eth-settlement/README.md @@ -99,6 +99,9 @@ else fi done fi + +# later on we create a symlink, here make sure it's deleted +rm ilp-cli &> /dev/null --> ### 1. Build interledger.rs @@ -410,77 +413,60 @@ else --> ```bash +ln -s ../../target/debug/ilp-cli ilp-cli +export ILP_CLI_API_AUTH=hi_alice # Adding settlement accounts should be done at the same time because it checks each other printf "Adding Alice's account...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_alice" \ - -d '{ - "username": "alice", - "ilp_address": "example.alice", - "asset_code": "ETH", - "asset_scale": 18, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "in_alice", - "ilp_over_http_url": "http://localhost:7770/ilp", - "settle_to" : 0}' \ - http://localhost:7770/accounts > logs/account-alice-alice.log 2>/dev/null +./ilp-cli accounts create alice \ + --ilp-address example.alice \ + --asset-code ETH \ + --asset-scale 18 \ + --max-packet-amount 100 \ + --ilp-over-http-incoming-token in_alice \ + --ilp-over-http-url http://localhost:7770/ilp \ + --settle-to 0 > logs/account-alice-alice.log printf "Adding Bob's Account...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_bob" \ - -d '{ - "username": "bob", - "ilp_address": "example.bob", - "asset_code": "ETH", - "asset_scale": 18, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "in_bob", - "ilp_over_http_url": "http://localhost:8770/ilp", - "settle_to" : 0}' \ - http://localhost:8770/accounts > logs/account-bob-bob.log 2>/dev/null +./ilp-cli --node http://localhost:8770 accounts create bob \ + --auth hi_bob \ + --ilp-address example.bob \ + --asset-code ETH \ + --asset-scale 18 \ + --max-packet-amount 100 \ + --ilp-over-http-incoming-token in_bob \ + --ilp-over-http-url http://localhost:8770/ilp \ + --settle-to 0 > logs/account-bob-bob.log printf "Adding Bob's account on Alice's node...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_alice" \ - -d '{ - "ilp_address": "example.bob", - "username": "bob", - "asset_code": "ETH", - "asset_scale": 18, - "max_packet_amount": 100, - "settlement_engine_url": "http://localhost:3000", - "ilp_over_http_incoming_token": "bob_password", - "ilp_over_http_outgoing_token": "alice:alice_password", - "ilp_over_http_url": "http://localhost:8770/ilp", - "settle_threshold": 500, - "min_balance": -1000, - "settle_to" : 0, - "routing_relation": "Peer"}' \ - http://localhost:7770/accounts > logs/account-alice-bob.log 2>/dev/null & +./ilp-cli accounts create bob \ + --ilp-address example.bob \ + --asset-code ETH \ + --asset-scale 18 \ + --max-packet-amount 100 \ + --settlement-engine-url http://localhost:3000 \ + --ilp-over-http-incoming-token bob_password \ + --ilp-over-http-outgoing-token alice:alice_password \ + --ilp-over-http-url http://localhost:8770/ilp \ + --settle-threshold 500 \ + --min-balance -1000 \ + --settle-to 0 \ + --routing-relation Peer > logs/account-alice-bob.log & printf "Adding Alice's account on Bob's node...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_bob" \ - -d '{ - "ilp_address": "example.alice", - "username": "alice", - "asset_code": "ETH", - "asset_scale": 18, - "max_packet_amount": 100, - "settlement_engine_url": "http://localhost:3001", - "ilp_over_http_incoming_token": "alice_password", - "ilp_over_http_outgoing_token": "bob:bob_password", - "ilp_over_http_url": "http://localhost:7770/ilp", - "settle_threshold": 500, - "min_balance": -1000, - "settle_to" : 0, - "routing_relation": "Peer"}' \ - http://localhost:8770/accounts > logs/account-bob-alice.log 2>/dev/null & +./ilp-cli --node http://localhost:8770 accounts create alice \ + --auth hi_bob \ + --ilp-address example.alice \ + --asset-code ETH \ + --asset-scale 18 \ + --max-packet-amount 100 \ + --settlement-engine-url http://localhost:3000 \ + --ilp-over-http-incoming-token alice_password \ + --ilp-over-http-outgoing-token bob:bob_password \ + --ilp-over-http-url http://localhost:7770/ilp \ + --settle-threshold 500 \ + --settle-to 0 \ + --routing-relation Peer > logs/account-bob-alice.log & sleep 2 ``` @@ -500,24 +486,18 @@ The `settle_threshold` and `settle_to` parameters control when settlements are t printf "\nChecking balances...\n" printf "\nAlice's balance on Alice's node: " -curl \ --H "Authorization: Bearer alice:in_alice" \ -http://localhost:7770/accounts/alice/balance +./ilp-cli accounts balance alice printf "\nBob's balance on Alice's node: " -curl \ --H "Authorization: Bearer bob:bob_password" \ -http://localhost:7770/accounts/bob/balance +./ilp-cli accounts balance bob printf "\nAlice's balance on Bob's node: " -curl \ --H "Authorization: Bearer alice:alice_password" \ -http://localhost:8770/accounts/alice/balance +./ilp-cli --node http://localhost:8770 accounts balance alice \ + --auth alice:alice_password printf "\nBob's balance on Bob's node: " -curl \ --H "Authorization: Bearer bob:in_bob" \ -http://localhost:8770/accounts/bob/balance +./ilp-cli --node http://localhost:8770 accounts balance bob \ + --auth bob:in_bob printf "\n\n" --> @@ -536,11 +516,9 @@ if [ "$USE_DOCKER" -eq 1 ]; then else --> ```bash -curl \ - -H "Authorization: Bearer alice:in_alice" \ - -H "Content-Type: application/json" \ - -d "{\"receiver\":\"http://localhost:8770/accounts/bob/spsp\",\"source_amount\":500}" \ - http://localhost:7770/accounts/alice/payments +./ilp-cli pay alice --auth in_alice \ + --amount 500 \ + --to http://localhost:8770/accounts/bob/spsp ``` @@ -88,10 +91,10 @@ if [ "$USE_DOCKER" -eq 1 ]; then $CMD_DOCKER network create interledger fi else - printf "Building interledger.rs... (This may take a couple of minutes)\n" + printf "\nBuilding interledger.rs... (This may take a couple of minutes)\n\n" --> ```bash -cargo build --bin ilp-node +cargo build --bin ilp-node --bin ilp-cli ``` Now the Interledger.rs nodes are up and running! @@ -211,10 +214,12 @@ You can also watch the logs with: `tail -f logs/node_a.log` or `tail -f logs/nod Let's create accounts on both nodes. The following script sets up accounts for two users, Alice and Bob. It also creates accounts that represent the connection between Nodes A and B. +Now that the nodes are up and running, we'll be using the `ilp-cli` command-line tool to work with them. This tool comes with the Interledger.rs repo, and offers a convenient way for developers to inspect and interact with live nodes. Note that `ilp-cli` speaks to Interledger.rs nodes via the normal HTTP API, so you could also use any other HTTP client (such as `curl`, for example) to perform the same operations. + See the [HTTP API docs](../../docs/api.md) for the full list of fields that can be set on an account. ```bash +# We merely use this symbolic link here to pretend that ilp-cli is installed +ln -s ../../target/debug/ilp-cli ilp-cli + +# For authenticating to nodes, we can set credentials as an environment variable or a CLI argument +export ILP_CLI_API_AUTH=admin-a + # Insert accounts on Node A # One account represents Alice and the other represents Node B's account with Node A -printf "Alice's account:\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer admin-a" \ - -d '{ - "ilp_address": "example.node_a.alice", - "username" : "alice", - "asset_code": "ABC", - "asset_scale": 9, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "alice-password"}' \ - http://localhost:7770/accounts - -printf "\nNode B's account on Node A:\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer admin-a" \ - -d '{ - "ilp_address": "example.node_b", - "username" : "node_b", - "asset_code": "ABC", - "asset_scale": 9, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "node_b-password", - "ilp_over_http_outgoing_token": "node_a:node_a-password", - "ilp_over_http_url": "http://localhost:8770/ilp", - "min_balance": -100000, - "routing_relation": "Peer"}' \ - http://localhost:7770/accounts +printf "Creating Alice's account on Node A...\n" +./ilp-cli --quiet accounts create alice \ + --asset-code ABC \ + --asset-scale 9 \ + --ilp-over-http-incoming-token alice-password + +printf "Creating Node B's account on Node A...\n" +./ilp-cli --quiet accounts create node_b \ + --asset-code ABC \ + --asset-scale 9 \ + --ilp-address example.node_b \ + --ilp-over-http-outgoing-token node_a:node_a-password \ + --ilp-over-http-url 'http://localhost:8770/ilp' # Insert accounts on Node B # One account represents Bob and the other represents Node A's account with Node B -printf "\nBob's Account:\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer admin-b" \ - -d '{ - "ilp_address": "example.node_b.bob", - "username" : "bob", - "asset_code": "ABC", - "asset_scale": 9, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "bob"}' \ - http://localhost:8770/accounts - -printf "\nNode A's account on Node B:\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer admin-b" \ - -d '{ - "ilp_address": "example.node_a", - "username" : "node_a", - "asset_code": "ABC", - "asset_scale": 9, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "node_a-password", - "ilp_over_http_outgoing_token": "node_b:node_b-password", - "ilp_over_http_url": "http://localhost:7770/ilp", - "min_balance": -100000, - "routing_relation": "Peer"}' \ - http://localhost:8770/accounts +printf "Creating Bob's account on Node B...\n" +./ilp-cli --quiet --node http://localhost:8770 accounts create bob \ + --auth admin-b \ + --asset-code ABC \ + --asset-scale 9 + +printf "Creating Node A's account on Node B...\n" +./ilp-cli --quiet --node http://localhost:8770 accounts create node_a \ + --auth admin-b \ + --asset-code ABC \ + --asset-scale 9 \ + --ilp-over-http-incoming-token node_a-password ``` ### 5. Sending a Payment -The following script sends a payment from Alice to Bob that is routed from Node A to Node B. +The following command sends a payment from Alice to Bob that is routed from Node A to Node B. + ```bash printf "\nAlice's balance: " -curl \ --H "Authorization: Bearer admin-a" \ -http://localhost:7770/accounts/alice/balance - -printf "\nNode B's balance on Node A: " -curl \ --H "Authorization: Bearer admin-a" \ -http://localhost:7770/accounts/node_b/balance - -printf "\nNode A's balance on Node B: " -curl \ --H "Authorization: Bearer admin-b" \ -http://localhost:8770/accounts/node_a/balance - -printf "\nBob's balance: " -curl \ --H "Authorization: Bearer admin-b" \ -http://localhost:8770/accounts/bob/balance +./ilp-cli accounts balance alice + +printf "Node B's balance on Node A: " +./ilp-cli accounts balance node_b + +printf "Node A's balance on Node B: " +./ilp-cli --node http://localhost:8770 accounts balance node_a --auth admin-b + +printf "Bob's balance: " +./ilp-cli --node http://localhost:8770 accounts balance bob --auth admin-b ``` ### 1. Build interledger.rs @@ -120,11 +124,11 @@ if [ "$USE_DOCKER" -eq 1 ]; then $CMD_DOCKER network create interledger fi else - printf "Building interledger.rs... (This may take a couple of minutes)\n" + printf "\nBuilding interledger.rs... (This may take a couple of minutes)\n\n" --> ```bash -cargo build --bin ilp-node +cargo build --bin ilp-node --bin ilp-cli ``` ### 5. Configure the Nodes @@ -381,77 +385,62 @@ else --> ```bash +ln -s ../../target/debug/ilp-cli ilp-cli +export ILP_CLI_API_AUTH=hi_alice + # Adding settlement accounts should be done at the same time because it checks each other printf "Adding Alice's account...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_alice" \ - -d '{ - "username": "alice", - "ilp_address": "example.alice", - "asset_code": "XRP", - "asset_scale": 6, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "in_alice", - "ilp_over_http_url": "http://localhost:7770/ilp", - "settle_to" : 0}' \ - http://localhost:7770/accounts > logs/account-alice-alice.log 2>/dev/null +./ilp-cli accounts create alice \ + --ilp-address example.alice \ + --asset-code XRP \ + --asset-scale 6 \ + --max-packet-amount 100 \ + --ilp-over-http-incoming-token in_alice \ + --ilp-over-http-url http://localhost:7770/ilp \ + --settle-to 0 > logs/account-alice-alice.log printf "Adding Bob's Account...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_bob" \ - -d '{ - "username": "bob", - "ilp_address": "example.bob", - "asset_code": "XRP", - "asset_scale": 6, - "max_packet_amount": 100, - "ilp_over_http_incoming_token": "in_bob", - "ilp_over_http_url": "http://localhost:8770/ilp", - "settle_to" : 0}' \ - http://localhost:8770/accounts > logs/account-bob-bob.log 2>/dev/null +./ilp-cli --node http://localhost:8770 accounts create bob \ + --auth hi_bob \ + --ilp-address example.bob \ + --asset-code XRP \ + --asset-scale 6 \ + --max-packet-amount 100 \ + --ilp-over-http-incoming-token in_bob \ + --ilp-over-http-url http://localhost:8770/ilp \ + --settle-to 0 > logs/account-bob-bob.log printf "Adding Bob's account on Alice's node...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_alice" \ - -d '{ - "ilp_address": "example.bob", - "username": "bob", - "asset_code": "XRP", - "asset_scale": 6, - "max_packet_amount": 100, - "settlement_engine_url": "http://localhost:3000", - "ilp_over_http_incoming_token": "bob_password", - "ilp_over_http_outgoing_token": "alice:alice_password", - "ilp_over_http_url": "http://localhost:8770/ilp", - "settle_threshold": 500, - "min_balance": -1000, - "settle_to" : 0, - "routing_relation": "Peer"}' \ - http://localhost:7770/accounts > logs/account-alice-bob.log 2>/dev/null & +./ilp-cli accounts create bob \ + --ilp-address example.bob \ + --asset-code XRP \ + --asset-scale 6 \ + --max-packet-amount 100 \ + --settlement-engine-url http://localhost:3000 \ + --ilp-over-http-incoming-token bob_password \ + --ilp-over-http-outgoing-token alice:alice_password \ + --ilp-over-http-url http://localhost:8770/ilp \ + --settle-threshold 500 \ + --min-balance -1000 \ + --settle-to 0 \ + --routing-relation Peer > logs/account-alice-bob.log & printf "Adding Alice's account on Bob's node...\n" -curl \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer hi_bob" \ - -d '{ - "ilp_address": "example.alice", - "username": "alice", - "asset_code": "XRP", - "asset_scale": 6, - "max_packet_amount": 100, - "settlement_engine_url": "http://localhost:3001", - "ilp_over_http_incoming_token": "alice_password", - "ilp_over_http_outgoing_token": "bob:bob_password", - "ilp_over_http_url": "http://localhost:7770/ilp", - "settle_threshold": 500, - "min_balance": -1000, - "settle_to" : 0, - "routing_relation": "Peer"}' \ - http://localhost:8770/accounts > logs/account-bob-alice.log 2>/dev/null & +./ilp-cli --node http://localhost:8770 accounts create alice \ + --auth hi_bob \ + --ilp-address example.alice \ + --asset-code XRP \ + --asset-scale 6 \ + --max-packet-amount 100 \ + --settlement-engine-url http://localhost:3001 \ + --ilp-over-http-incoming-token alice_password \ + --ilp-over-http-outgoing-token bob:bob_password \ + --ilp-over-http-url http://localhost:7770/ilp \ + --settle-threshold 500 \ + --min-balance -1000 \ + --settle-to 0 \ + --routing-relation Peer > logs/account-bob-alice.log & sleep 2 ``` @@ -469,27 +458,19 @@ The `settle_threshold` and `settle_to` parameters control when settlements are t ### 6. Sending a Payment @@ -509,11 +490,10 @@ else --> ```bash -curl \ - -H "Authorization: Bearer alice:in_alice" \ - -H "Content-Type: application/json" \ - -d "{\"receiver\":\"http://localhost:8770/accounts/bob/spsp\",\"source_amount\":500}" \ - http://localhost:7770/accounts/alice/payments +./ilp-cli pay alice \ + --auth in_alice \ + --amount 500 \ + --to http://localhost:8770/accounts/bob/spsp ``` + +```bash printf "\nAlice's balance on Alice's node: " -curl \ --H "Authorization: Bearer alice:in_alice" \ -http://localhost:7770/accounts/alice/balance +./ilp-cli accounts balance alice printf "\nBob's balance on Alice's node: " -curl \ --H "Authorization: Bearer bob:bob_password" \ -http://localhost:7770/accounts/bob/balance +./ilp-cli accounts balance bob printf "\nAlice's balance on Bob's node: " -curl \ --H "Authorization: Bearer alice:alice_password" \ -http://localhost:8770/accounts/alice/balance +./ilp-cli --node http://localhost:8770 accounts balance alice --auth hi_bob printf "\nBob's balance on Bob's node: " -curl \ --H "Authorization: Bearer bob:in_bob" \ -http://localhost:8770/accounts/bob/balance ---> +./ilp-cli --node http://localhost:8770 accounts balance bob --auth hi_bob +``` ### 8. Kill All the Services @@ -637,7 +590,7 @@ fi printf "\n" run_hook_before_kill if [ $TEST_MODE -ne 1 ]; then - prompt_yn "Do you want to kill the services? [Y/n]" "y" + prompt_yn "Do you want to kill the services? [Y/n] " "y" fi printf "\n" if [ "$PROMPT_ANSWER" = "y" ] || [ $TEST_MODE -eq 1 ] ; then