From 9d9cd707c9bf24a3c4c39966bb29b33a53b4d1ff Mon Sep 17 00:00:00 2001 From: Artem Pikulin Date: Thu, 28 Jan 2021 17:59:09 +0700 Subject: [PATCH] Additional filters support in my_recent_swaps #784. (#796) * WIP. Try rusqlite crate. * WIP. Try rusqlite crate. * WIP. Fix clippy. * WIP. Added SQLite DB init and migration. TODO: insert swaps data into DB. * WIP. Indexed existing swaps to SQLite on DB migration. * WIP. Insert new started swaps data to SQLite. * WIP. Added SQL selection of uuids depending on MyRecentSwapsReq. * WIP. Refactor recent swaps uuids select to named params. * Added from_uuid support for SQLite. Refactoring. Feature finished. * Remove +nightly from cargo commands. * Fixes after review. * Set page_number to 1 in my_recent_swaps response when page_number and from_uuid are not set in request. --- Cargo.lock | 75 +- Cargo.toml | 1 + azure-pipelines-build-stage-job.yml | 9 +- azure-pipelines-release-stage-job.yml | 4 +- etomic_build/client/coins | 2881 ---------------------- etomic_build/client/enable_MORTY | 3 + etomic_build/client/enable_RICK | 3 + etomic_build/client/my_recent_swaps | 10 + etomic_build/client/setprice_ONE_ANOTHER | 12 + etomic_build/coins | 3 - mm2src/common/Cargo.toml | 2 +- mm2src/common/common.rs | 3 +- mm2src/common/mm_ctx.rs | 102 +- mm2src/database.rs | 82 + mm2src/database/my_swaps.rs | 223 ++ mm2src/lp_native_dex.rs | 10 +- mm2src/lp_ordermatch.rs | 25 +- mm2src/lp_swap.rs | 156 +- mm2src/mm2.rs | 1 + mm2src/mm2_tests.rs | 35 +- 20 files changed, 543 insertions(+), 3097 deletions(-) delete mode 100644 etomic_build/client/coins create mode 100755 etomic_build/client/enable_MORTY create mode 100755 etomic_build/client/enable_RICK create mode 100755 etomic_build/client/my_recent_swaps create mode 100755 etomic_build/client/setprice_ONE_ANOTHER delete mode 100755 etomic_build/coins create mode 100644 mm2src/database.rs create mode 100644 mm2src/database/my_swaps.rs diff --git a/Cargo.lock b/Cargo.lock index b14a301008..4c5a23c0b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + [[package]] name = "aho-corasick" version = "0.7.12" @@ -844,8 +850,8 @@ dependencies = [ "primitives", "rand 0.7.3", "regex", + "rusqlite", "serde", - "serde_bencode", "serde_bytes 0.11.5", "serde_derive", "serde_json", @@ -1483,6 +1489,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "1.2.4" @@ -1933,6 +1951,24 @@ dependencies = [ "autocfg 1.0.0", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + +[[package]] +name = "hashlink" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +dependencies = [ + "hashbrown 0.9.1", +] + [[package]] name = "hdrhistogram" version = "6.3.4" @@ -2688,6 +2724,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "libsqlite3-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.0.25" @@ -3077,6 +3124,7 @@ dependencies = [ "serialization", "serialization_derive", "sp-trie", + "sql-builder", "term 0.5.1", "testcontainers", "tokio", @@ -4173,6 +4221,21 @@ dependencies = [ "serialization", ] +[[package]] +name = "rusqlite" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38ee71cbab2c827ec0ac24e76f82eca723cee92c509a65f67dee393c25112" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "memchr", + "smallvec 1.4.0", +] + [[package]] name = "rust-argon2" version = "0.7.0" @@ -4913,6 +4976,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "sql-builder" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1008d95d2ec2d062959352527be30e10fec42a1aa5e5a48d990a5ff0fb9bdc0" +dependencies = [ + "anyhow", + "thiserror", +] + [[package]] name = "stable_deref_trait" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index 183bf44e3c..d7a4e5db9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,6 +111,7 @@ serde_derive = "1.0" serialization = { git = "https://github.com/artemii235/parity-bitcoin.git" } serialization_derive = { git = "https://github.com/artemii235/parity-bitcoin.git" } sp-trie = "2.0.0" +sql-builder = "3.1.1" # Pin `term` to 0.5.1 because `dirs` is not portable, cf. # https://github.com/Stebalien/term/commit/84cfdb51775b327fedf21784749d862fdffa10b4#diff-80398c5faae3c069e4e6aa2ed11b28c0 diff --git a/azure-pipelines-build-stage-job.yml b/azure-pipelines-build-stage-job.yml index fadcb4ea8f..a2a39ae4c2 100644 --- a/azure-pipelines-build-stage-job.yml +++ b/azure-pipelines-build-stage-job.yml @@ -35,11 +35,11 @@ jobs: mkdir upload echo 2.1.$(Build.BuildId)_$(Build.SourceBranchName)_$(COMMIT_HASH)_$(Agent.OS)_Release > MM_VERSION cat MM_VERSION - cargo +nightly build --features native --release + cargo build --features native --release displayName: 'Build MM2 Release' # Explicit --test-threads=16 makes testing process slightly faster on agents that have <16 CPU cores. - bash: | - cargo +nightly test --features native --all -- --test-threads=16 + cargo test --features native --all -- --test-threads=16 displayName: 'Test MM2' timeoutInMinutes: 22 env: @@ -47,12 +47,13 @@ jobs: BOB_USERPASS: $(${{ parameters.bob_userpass }}) ALICE_PASSPHRASE: $(${{ parameters.alice_passphrase }}) ALICE_USERPASS: $(${{ parameters.alice_userpass }}) + RUST_LOG: debug - bash: | - cargo +nightly clippy --features native -- -D warnings + cargo clippy --features native -- -D warnings displayName: 'Check Clippy warnings' condition: eq( variables['Agent.OS'], 'Linux' ) - bash: | - cargo +nightly fmt -- --check + cargo fmt -- --check displayName: 'Check rustfmt warnings' condition: eq( variables['Agent.OS'], 'Linux' ) - bash: | diff --git a/azure-pipelines-release-stage-job.yml b/azure-pipelines-release-stage-job.yml index fb66fd50a7..2ae8b50a88 100644 --- a/azure-pipelines-release-stage-job.yml +++ b/azure-pipelines-release-stage-job.yml @@ -58,7 +58,7 @@ jobs: mm2_builder \ /bin/bash -c "source /root/.cargo/env && cargo build --features native -vv --target-dir target-xenial" else - cargo +nightly build --features native -vv + cargo build --features native -vv fi displayName: 'Build MM2 Debug' condition: eq( variables['DEBUG_UPLOADED'], '' ) @@ -95,7 +95,7 @@ jobs: mm2_builder \ /bin/bash -c "source /root/.cargo/env && cargo build --features native --release -vv --target-dir target-xenial" else - cargo +nightly build --features native --release -vv + cargo build --features native --release -vv fi displayName: 'Build MM2 Release' condition: eq( variables['RELEASE_UPLOADED'], '' ) diff --git a/etomic_build/client/coins b/etomic_build/client/coins deleted file mode 100644 index 3d2de3fde7..0000000000 --- a/etomic_build/client/coins +++ /dev/null @@ -1,2881 +0,0 @@ -[ - { - "coin":"KMDICE", - "asset":"KMDICE", - "fname": "KMDice", - "rpcport":30177 - }, - { - "coin":"CHAIN", - "asset":"CHAIN", - "fname": "Chainmakers", - "rpcport":15587 - }, - { - "coin":"GLXT", - "asset":"GLXT", - "fname": "GLX Token", - "rpcport":13109 - }, - { - "coin": "CC", - "asset": "CCL", - "fname": "CoinCollect", - "rpcport": 20849, - "txversion": 4 - }, - { - "coin": "KOIN", - "asset": "KOIN", - "fname": "Koinon", - "rpcport": 10702 - }, - { - "coin": "COLX", - "name": "ColossusXT", - "fname": "ColossusXT", - "rpcport": 51473, - "pubtype": 30, - "p2shtype": 13, - "wiftype": 212, - "txfee": 1000000000 - }, - { - "coin": "SPK", - "name": "sparks", - "fname": "Sparks", - "rpcport": 8892, - "pubtype": 38, - "p2shtype": 10, - "wiftype": 198, - "txfee": 10000, - "confpath": "USERHOME/.sparkscore/sparks.conf" - }, - { - "coin":"ORE", - "name":"galactrum", - "fname": "Galactrum", - "rpcport":6269, - "pubtype":38, - "p2shtype":16, - "wiftype":204, - "txfee":10000 - }, - { - "coin":"EQLI", - "asset":"EQL", - "fname": "Equaliser", - "rpcport":10306 - }, - { - "coin": "AYWA", - "name": "aywa", - "fname": "AYWA", - "rpcport": 2778, - "pubtype": 23, - "p2shtype": 83, - "wiftype": 150, - "txfee": 10000, - "confpath": "USERHOME/.aywacore/aywa.conf" - }, - { - "coin":"PAC", - "name":"paccoin", - "fname":"PACcoin", - "rpcport":7111, - "pubtype":55, - "p2shtype":10, - "wiftype":204, - "txfee":10000, - "confpath":"USERHOME/.paccoincore/paccoin.conf" - }, - { - "coin":"PEW", - "name":"brofist", - "fname": "Brofist", - "rpcport":12454, - "pubtype":55, - "p2shtype":10, - "wiftype":198, - "txfee":10000, - "confpath":"USERHOME/.brofistcore/brofist.conf" - }, - { - "coin": "SUN", - "name": "suncoin", - "fname": "SunCoin", - "rpcport": 10332, - "pubtype": 63, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000, - "confpath": "USERHOME/.suncoincore/suncoin.conf" - }, - { - "coin":"WAVI", - "name":"wavi", - "fname": "Wavi", - "rpcport":9984, - "pubtype":73, - "p2shtype":15, - "wiftype":133, - "txfee":10000, - "confpath":"USERHOME/.wavicore/wavi.conf" - }, - { - "coin":"ATB", - "name":"atbcoin", - "fname": "ATBCoin", - "rpcport":8332, - "pubtype":23, - "p2shtype":83, - "wiftype":128, - "txfee":10000, - "confpath":"USERHOME/.ATBCoinWallet/atbcoin.conf" - }, - { - "coin":"BTNX", - "name":"bitnexus", - "fname":"BitNexus", - "rpcport":9191, - "pubtype":25, - "p2shtype":10, - "wiftype":198, - "txfee":10000, - "confpath":"USERHOME/.bitcoinnodecore/bitnexus.conf" - }, - { - "coin": "CHC", - "name": "chaincoin", - "fname": "ChainCoin", - "rpcport": 11995, - "pubtype": 28, - "p2shtype": 4, - "wiftype": 156, - "txfee": 10000, - "confpath": "USERHOME/.chaincoincore/chaincoin.conf" - }, - { - "coin":"DOPE", - "name":"dopecoin", - "fname":"DopeCoin", - "isPoS": 1, - "rpcport":40421, - "pubtype":30, - "p2shtype":5, - "wiftype":158, - "txfee":10000 - }, - { - "coin": "ECA", - "name": "electra", - "fname": "Electra", - "rpcport": 5788, - "pubtype": 33, - "p2shtype": 40, - "wiftype": 161, - "txfee": 10000, - "txversion": 7 - }, - { - "coin":"POLIS", - "name":"polis", - "fname":"Polis", - "rpcport":24127, - "pubtype":55, - "p2shtype":56, - "wiftype":60, - "txfee":10000, - "confpath":"USERHOME/.poliscore/polis.conf" - }, - { - "coin":"PYRO", - "name":"pyro", - "fname": "Pyro", - "rpcport":9696, - "pubtype":55, - "p2shtype":10, - "wiftype":198, - "txfee":10000, - "confpath":"USERHOME/.pyrocore/pyro.conf" - }, - { - "coin":"XSN", - "name":"xsn", - "fname": "Stakenet", - "rpcport":51473, - "pubtype":76, - "p2shtype":16, - "wiftype":204, - "txfee":10000, - "confpath":"USERHOME/.xsncore/xsn.conf" - }, - { - "coin":"GRLC", - "name":"garlicoin", - "fname": "Garlicoin", - "rpcport":42068, - "pubtype":38, - "p2shtype":5, - "wiftype":176, - "txfee":100000 - }, - { - "coin":"HXX", - "name":"hexxcoin", - "fname": "Hexx", - "rpcport":29200, - "pubtype":40, - "p2shtype":10, - "wiftype":210, - "txfee":100000 - }, - { - "coin":"CRDS", - "name":"credits", - "fname": "Credits", - "rpcport":31050, - "pubtype":28, - "p2shtype":10, - "wiftype":140, - "txfee":10000 - }, - { - "coin":"DIN", - "name":"dinero", - "fname": "Dinero", - "rpcport":9998, - "pubtype":30, - "p2shtype":13, - "wiftype":204, - "txfee":10000, - "confpath":"USERHOME/.dinerocore/dinero.conf" - }, - { - "coin": "AXE", - "name": "axe", - "fname": "Axe", - "rpcport": 9337, - "pubtype": 55, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000, - "confpath":"USERHOME/.axecore/axe.conf" - }, - { - "coin": "BCBC", - "name": "bitcoin@cbc", - "fname": "Bitcoin@CBC", - "rpcport": 8340, - "pubtype": 0, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000, - "confpath":"USERHOME/.bitcoin@cbc/bitcoin.conf" - }, - { - "coin": "BUCK", - "name": "buck", - "fname": "Buck", - "rpcport": 5739, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "CMM", - "name": "commercium", - "fname": "Commercium", - "rpcport": 9657, - "pubtype": 28, - "p2shtype": 50, - "wiftype": 140, - "txfee": 10000 - }, - { - "coin": "GIN", - "name": "gincoin", - "fname": "GINcoin", - "rpcport": 10211, - "pubtype": 38, - "p2shtype": 10, - "wiftype": 198, - "txfee": 10000, - "confpath":"USERHOME/.gincoincore/gincoin.conf" - }, - { - "coin": "LUX", - "name": "lux", - "fname": "LUXCoin", - "rpcport": 9888, - "isPoS": 1, - "pubtype": 48, - "p2shtype": 63, - "wiftype": 155, - "txfee": 10000 - }, - { - "coin": "RAP", - "fname": "Rapture", - "name": "rapture", - "rpcport": 14476, - "pubtype": 60, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000, - "confpath": "USERHOME/.rapturecore/rapture.conf" - }, - { - "coin": "SUDO", - "fname": "CryptoSudo", - "name": "sudo", - "rpcport": 3935, - "pubtype": 63, - "p2shtype": 13, - "wiftype": 39, - "txfee": 10000, - "confpath": "USERHOME/.sudocore/sudo.conf" - }, - { - "coin": "RADIUS", - "name": "radius", - "fname": "Radius", - "rpcport": 4089, - "pubtype": 60, - "p2shtype": 16, - "wiftype": 15, - "txfee": 10000, - "confpath": "USERHOME/.radiuscore/radius.conf" - }, - { - "coin": "SEQ", - "name": "sequence", - "fname": "Sequence", - "rpcport": 16663, - "isPoS": 1, - "pubtype": 63, - "p2shtype": 64, - "wiftype": 170, - "txfee": 10000 - }, - { - "coin": "DYN", - "name": "dynamic", - "fname": "Dynamic", - "rpcport": 33350, - "pubtype": 30, - "p2shtype": 10, - "wiftype": 140, - "txfee": 10000 - }, - { - "coin": "SBTC", - "name": "superbitcoin", - "fname": "Super Bitcoin", - "rpcport": 28282, - "pubtype": 0, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000, - "confpath": "USERHOME/.sbtc/sbtc.conf" - }, - { - "coin": "FJC", - "name": "fujicoin", - "fname": "FujiCoin", - "rpcport": 3776, - "pubtype": 36, - "p2shtype": 16, - "wiftype": 164, - "txfee": 100000 - }, - { - "coin": "VRT", - "name": "virtus", - "fname": "Virtus", - "confpath": "USERHOME/.virtuscore/virtus.conf", - "rpcport": 13880, - "pubtype": 70, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "X0Z", - "name": "zerozed", - "fname": "Zerozed", - "rpcport": 2600, - "pubtype": 28, - "p2shtype": 5, - "wiftype": 156, - "txfee": 100000 - }, - { - "coin": "XBC", - "name": "bitcoinplus", - "fname": "Bitcoin Plus", - "rpcport": 8885, - "isPoS": 1, - "pubtype": 25, - "p2shtype": 85, - "wiftype": 153, - "txfee": 100000 - }, - { - "coin":"AE", - "name":"aeternity", - "fname": "Aeternity", - "etomic":"0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d", - "rpcport":80 - }, - { - "coin":"AION", - "name":"aion", - "fname": "Aion", - "etomic":"0x4CEdA7906a5Ed2179785Cd3A40A69ee8bc99C466", - "rpcport":80 - }, - { - "coin":"ANN", - "name":"agentnotneeded", - "fname": "Agent Not Needed", - "etomic":"0xe0e73E8fc3a0fA161695be1D75E1Bc3E558957c4", - "rpcport":80 - }, - { - "coin": "BFT", - "name": "bnktothefuture", - "fname": "BnkToTheFuture", - "etomic": "0x01ff50f8b7f74e4f00580d9596cd3d0d6d6e326f", - "rpcport": 80 - }, - { - "coin": "BIO", - "name": "biocrypt", - "fname": "BioCrypt", - "etomic": "0xf18432ef894ef4b2a5726f933718f5a8cf9ff831", - "rpcport": 80 - }, - { - "coin":"BITSOKO", - "name":"bitsoko", - "fname":"Bitsoko", - "etomic":"0xb72627650f1149ea5e54834b2f468e5d430e67bf", - "rpcport":80 - }, - { - "coin": "BLZ", - "name": "bluzelle", - "fname": "Bluzelle", - "etomic": "0x5732046a883704404f284ce41ffadd5b007fd668", - "rpcport": 80 - }, - { - "coin":"BOX", - "name":"beonbox", - "fname":"Beonbox", - "etomic":"0x01e579be97433f861340268521a7a2ab9829082c", - "rpcport":80 - }, - { - "coin":"BTCL", - "name":"btclite", - "fname": "BTC Lite", - "etomic":"0x5acd19b9c91e596b1f062f18e3d02da7ed8d1e50", - "rpcport":80 - }, - { - "coin":"BTM", - "name":"bytom", - "fname": "Bytom", - "etomic":"0xcB97e65F07DA24D46BcDD078EBebd7C6E6E3d750", - "rpcport":80 - }, - { - "coin": "BTO", - "name": "bottos", - "fname": "Bottos", - "etomic": "0x36905fc93280f52362a1cbab151f25dc46742fb5", - "rpcport": 80 - }, - { - "coin":"CENNZ", - "name":"centrality", - "fname": "Centrality", - "etomic":"0x1122b6a0e00dce0563082b6e2953f3a943855c1f", - "rpcport":80 - }, - { - "coin": "CLF", - "name": "cryptoleaf", - "fname": "CryptoLeaf", - "etomic": "0x07241118626a7bbb604be4b9ef8ef12e78fd0871", - "rpcport": 80 - }, - { - "coin": "CMT", - "name": "cybermiles", - "fname": "CyberMiles", - "etomic": "0xf85feea2fdd81d51177f6b8f35f0e6734ce45f5f", - "rpcport": 80 - }, - { - "coin":"CS", - "name":"credits", - "fname":"Credits", - "etomic":"0x46b9ad944d1059450da1163511069c718f699d31", - "rpcport":80 - }, - { - "coin": "CYFR", - "name": "cyphrcoin", - "fname": "CyphrCoin", - "etomic": "0xc68d6276eb43f2433f30500d74f155031606e249", - "rpcport": 80 - }, - { - "coin":"DATA", - "name":"streamr-datacoin", - "fname":"Streamr DATAcoin", - "etomic":"0x0cf0ee63788a0849fe5297f3407f701e122cc023", - "rpcport":80 - }, - { - "coin":"ELD", - "name":"electrumdark", - "fname": "Electrum Dark", - "etomic":"0xaaf7d4cd097317d68174215395eb02c2cca81e31", - "rpcport":80 - }, - { - "coin":"ENG", - "name":"enigma-project", - "fname":"Enigma", - "etomic":"0xf0ee6b27b759c9893ce4f094b49ad28fd15a23e4", - "rpcport":80 - }, - { - "coin": "ETA", - "name": "etheera", - "fname": "Etheera", - "etomic": "0x9195e00402abe385f2d00a32af40b271f2e87925", - "rpcport": 80 - }, - { - "coin": "ETK", - "name": "energitoken", - "fname": "EnergiToken", - "etomic": "0x3c4a3ffd813a107febd57b2f01bc344264d90fde", - "rpcport": 80 - }, - { - "coin": "FOOD", - "name": "foodcoin", - "fname": "FoodCoin", - "etomic": "0x2a093bcf0c98ef744bb6f69d74f2f85605324290", - "rpcport": 80 - }, - { - "coin": "GMBEL", - "name": "gmbel", - "fname": "G-Mbel", - "etomic": "0xf3cfbca4e083b1418f89545754c7da90d2418b10", - "rpcport": 80 - }, - { - "coin":"GPN", - "name":"gpncoin", - "fname": "GPN Coin", - "etomic":"0xE2b407160AAd5540eAc0e80338b9a5085C60F25B", - "rpcport":80 - }, - { - "coin": "GROW", - "name": "grow", - "fname": "Grow", - "etomic": "0x11b57f39f5a42eff60144b333a4d7d58e40297a4", - "rpcport": 80 - }, - { - "coin": "GTC", - "name": "game", - "fname": "Game.com", - "etomic": "0xB70835D7822eBB9426B56543E391846C107bd32C", - "rpcport": 80 - }, - { - "coin": "GTO", - "name": "gifto", - "fname": "Gifto", - "etomic":"0xc5bbae50781be1669306b9e001eff57a2957b09d", - "rpcport":80 - }, - { - "coin": "HT", - "name": "huobi-token", - "fname": "Huobi Token", - "etomic": "0x6f259637dcd74c767781e37bc6133cd6a68aa161", - "rpcport": 80 - }, - { - "coin": "HTS", - "name": "hostingicos", - "fname": "Hostingicos", - "etomic": "0x20871ef4fc0b8c5ee4fb03f698c4f4f752dda6e5", - "rpcport": 80 - }, - { - "coin": "ITL", - "name": "italian-lira", - "fname": "Italian Lira", - "etomic": "0x122A86b5DFF2D085AfB49600b4cd7375D0d94A5f", - "rpcport": 80 - }, - { - "coin":"JOI", - "name":"jointedu", - "fname":"JointEDU", - "etomic":"0x58ded6994124b4fff298f1416aca3fc9cdba37b2", - "rpcport":80 - }, - { - "coin": "KEA", - "name": "keacoin", - "fname": "KEA Coin", - "etomic": "0x390d6673c1fa9dbb8000db1ae89252b7d531ab75", - "rpcport": 80 - }, - { - "coin": "KICK", - "name": "kickico", - "fname": "KickCoin", - "etomic": "0x27695e09149adc738a978e9a678f99e4c39e9eb9", - "rpcport": 80 - }, - { - "coin":"LIKE", - "name":"likecoin", - "fname":"LikeCoin", - "etomic":"0x02f61fd266da6e8b102d4121f5ce7b992640cf98", - "rpcport":80 - }, - { - "coin":"LINK", - "name":"chainlink", - "fname":"ChainLink", - "etomic":"0x514910771af9ca656af840dff83e8264ecf986ca", - "rpcport":80 - }, - { - "coin": "LTR", - "name": "labtorum", - "fname": "Labtorum", - "etomic": "0x1bd4e709a076fb71ea1014293a739f2b19ca565d", - "rpcport": 80 - }, - { - "coin":"LYS", - "name":"lightyears", - "fname": "Lightyears", - "etomic":"0xdd41fbd1ae95c5d9b198174a28e04be6b3d1aa27", - "rpcport":80 - }, - { - "coin":"MAN", - "name":"matrix-ai-network", - "fname":"Matrix AI Network", - "etomic":"0xe25bcec5d3801ce3a794079bf94adf1b8ccd802d", - "rpcport":80 - }, - { - "coin":"MMX", - "name":"mechanix", - "fname":"Mechanix Token", - "etomic":"0xe7c33a0e04f2316bb321c4ad2976873d09538b56", - "rpcport":80 - }, - { - "coin": "MRPH", - "name": "morpheusnetwork", - "fname": "Morpheus Network", - "etomic": "0x7b0c06043468469967dba22d1af33d77d44056c8", - "rpcport": 80 - }, - { - "coin": "MTF", - "name": "mintflint", - "fname": "MintFlint Token", - "etomic": "0xf3b98d8c425c76e0c7abadffddc1a26ce3107e45", - "rpcport": 80 - }, - { - "coin":"MYB", - "name":"mybit-token", - "fname": "MyBit Token", - "etomic":"0x5d60d8d7ef6d37e16ebabc324de3be57f135e0bc", - "rpcport":80 - }, - { - "coin": "NOAH", - "name": "noah-coin", - "fname": "Noah Coin", - "etomic": "0x58a4884182d9e835597f405e5f258290e46ae7c2", - "rpcport": 80 - }, - { - "coin": "NPXS", - "name": "pundi-x", - "fname": "Pundi X", - "etomic": "0xa15c7ebe1f07caf6bff097d8a589fb8ac49ae5b3", - "rpcport": 80 - }, - { - "coin": "NS21", - "name": "peachcoin", - "fname": "PeachCoin", - "etomic": "0xcf2450b25b52406bdab999fe7816079f7fd88cd3", - "rpcport": 80 - }, - { - "coin":"NULS", - "name":"nuls", - "fname":"Nuls", - "etomic":"0xb91318f35bdb262e9423bc7c7c2a3a93dd93c92c", - "rpcport":80 - }, - { - "coin":"OCC", - "name":"originalcryptocoin", - "fname": "Original Crypto Coin", - "etomic":"0x0235fe624e044a05eed7a43e16e3083bc8a4287a", - "rpcport":80 - }, - { - "coin": "OVAL", - "name": "oval", - "fname": "OVAL Token", - "etomic": "0x6b1700cc6bce603922cbbc5c45fdb77ee08a74d1", - "rpcport": 80 - }, - { - "coin": "PAO", - "name": "pacificocean", - "fname": "Pacific Ocean", - "etomic": "0x4b6509423371d35e022a2915be0edeffa9147f5a", - "rpcport": 80 - }, - { - "coin":"PCL", - "name":"peculium", - "fname": "Peculium", - "etomic":"0x3618516f45cd3c913f81f9987af41077932bc40d", - "rpcport":80 - }, - { - "coin": "PCNC", - "name": "pcncoin", - "fname": "PCN Coin", - "etomic": "0x090b60abc45e2af60eb058a4c7f25574a1c6ae4a", - "rpcport": 80 - }, - { - "coin": "PEP", - "name": "pesapepe", - "fname": "PesaPepe", - "etomic": "0x61630fd1f65a7b72af8e9faa6e2646080131f501", - "rpcport": 80 - }, - { - "coin": "PGT", - "name": "puregold", - "fname": "Puregold Token", - "etomic": "0x9b3e946e1a8ea0112b147af4e6e020752f2446bc", - "rpcport": 80 - }, - { - "coin":"POLY", - "name":"polymath-network", - "fname":"Polymath", - "etomic":"0x9992ec3cf6a55b00978cddf2b27bc6882d88d1ec", - "rpcport":80 - }, - { - "coin":"PURC", - "name":"peurcoin", - "fname":"Peurcoin", - "etomic":"0x7148b80b38278853ca8263cfc0b57d4478ae6a6e", - "rpcport":80 - }, - { - "coin":"QBIT", - "name":"qubitica", - "fname":"Qubitica", - "etomic":"0xcb5ea3c190d8f82deadf7ce5af855ddbf33e3962", - "rpcport":80 - }, - { - "coin": "QKC", - "name": "quarkchain", - "fname": "QuarkChain", - "etomic": "0xea26c4ac16d4a5a106820bc8aee85fd0b7b2b664", - "rpcport": 80 - }, - { - "coin": "RUFF", - "name": "ruff", - "fname": "Ruff", - "etomic": "0xf278c1ca969095ffddded020290cf8b5c424ace2", - "rpcport": 80 - }, - { - "coin":"RVT", - "name":"rivetz", - "fname": "Rivetz", - "etomic":"0x3d1ba9be9f66b8ee101911bc36d3fb562eac2244", - "rpcport":80 - }, - { - "coin":"SPANK", - "name":"spankchain", - "fname": "SpankChain", - "etomic":"0x42d6622dece394b54999fbd73d108123806f6a18", - "rpcport":80 - }, - { - "coin":"STRM41", - "name":"stream41", - "fname":"Stream41", - "etomic":"0xbad7a7f7ba71ce3659fe6dcad34af86b9de2a4b2", - "rpcport":80 - }, - { - "coin":"SUB", - "name":"substratum", - "fname":"Substratum", - "etomic":"0x12480e24eb5bec1a9d4369cab6a80cad3c0a377a", - "rpcport":80 - }, - { - "coin": "SVD", - "name": "savedroid", - "fname": "Savedroid", - "etomic": "0xbdeb4b83251fb146687fa19d1c660f99411eefe3", - "decimals": 18, - "rpcport": 80 - }, - { - "coin":"THETA", - "name":"theta-token", - "fname":"Theta Token", - "etomic":"0x3883f5e181fccaF8410FA61e12b59BAd963fb645", - "rpcport":80 - }, - { - "coin": "TILE", - "name": "loomiatile", - "fname": "Loomia Tile", - "etomic": "0x25f735b108b4273fb0aceb87599ed8bba10065de", - "rpcport": 80 - }, - { - "coin": "TRAT", - "name": "tratok", - "fname": "Tratok", - "etomic": "0x0cbc9b02b8628ae08688b5cc8134dc09e36c443b", - "rpcport": 80 - }, - { - "coin": "TRET", - "name": "touristreview", - "fname": "Tourist Review", - "etomic": "0xc6d603a9df53d1542552058c382bf115aace70c7", - "rpcport": 80 - }, - { - "coin":"CIX", - "name":"cryptonetix", - "fname": "Cryptonetix", - "etomic":"0x1175a66a5c3343Bbf06AA818BB482DdEc30858E0", - "rpcport":80 - }, - { - "coin":"DCN", - "name":"dentacoin", - "fname": "Dentacoin", - "etomic":"0x08d32b0da63e2C3bcF8019c9c5d849d7a9d791e6", - "rpcport":80 - }, - { - "coin": "ELY", - "name": "elysian", - "fname": "Elysian", - "etomic": "0xa95592dcffa3c080b4b40e459c5f5692f67db7f8", - "rpcport": 80 - }, - { - "coin":"DROP", - "name":"dropil", - "fname": "Dropil", - "etomic":"0x4672bad527107471cb5067a887f4656d585a8a31", - "rpcport":80 - }, - { - "coin":"DRT", - "name":"domraider", - "fname": "DomRaider", - "etomic":"0x9af4f26941677c706cfecf6d3379ff01bb85d5ab", - "rpcport":80 - }, - { - "coin":"ELF", - "name":"aelf", - "fname": "aelf", - "etomic":"0xbf2179859fc6D5BEE9Bf9158632Dc51678a4100e", - "rpcport":80 - }, - { - "coin":"RLTY", - "name":"smartrealty", - "fname": "SMARTRealty", - "etomic":"0xbe99b09709fc753b09bcf557a992f6605d5997b0", - "rpcport":80 - }, - { - "coin": "FTC", - "name": "feathercoin", - "fname": "Feather Coin", - "rpcport": 9337, - "pubtype": 14, - "p2shtype": 5, - "wiftype": 142, - "txfee": 1000000 - }, - { - "coin": "PXT", - "name": "populous-xbrl-token", - "fname": "Populous XBRL Token", - "etomic": "0xc14830e53aa344e8c14603a91229a0b925b0b262", - "rpcport": 80 - }, - { - "coin": "STORM", - "name": "storm", - "fname": "Storm", - "etomic": "0xd0a4b8946cb52f0661273bfbc6fd0e0c75fc6433", - "rpcport": 80 - }, - { - "coin": "TUSD", - "name": "trueusd", - "fname": "TrueUSD", - "etomic": "0x8dd5fbce2f6a956c3022ba3663759011dd51e73e", - "rpcport": 80 - }, - { - "coin": "WAX", - "name": "wax", - "fname": "WAX", - "etomic": "0x39Bb259F66E1C59d5ABEF88375979b4D20D98022", - "rpcport": 80 - }, - { - "coin": "KIN", - "name": "kin", - "fname": "Kin", - "etomic": "0x818fc6c2ec5986bc6e2cbf00939d90556ab12ce5", - "rpcport": 80 - }, - { - "coin": "LALA", - "name": "lala-world", - "fname": "LALA World", - "etomic": "0xfd107b473ab90e8fbd89872144a3dc92c40fa8c9", - "rpcport": 80 - }, - { - "coin": "ONNI", - "name": "misericordae", - "fname": "Misericordae", - "etomic": "0xbd9c6028e1132a6b52f1ca15c0933a2fd342e21f", - "rpcport": 80 - }, - { - "coin": "PAT", - "name": "pat", - "fname": "Pangea Arbitration Token", - "etomic": "0xBB1fA4FdEB3459733bF67EbC6f893003fA976a82", - "rpcport": 80 - }, - { - "coin": "USDT", - "name": "tether", - "fname": "Tether", - "etomic": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "rpcport": 80 - }, - { - "coin": "BBT", - "name": "bitboost", - "fname": "Bitboost", - "etomic": "0x1500205f50bf3fd976466d0662905c9ff254fc9c", - "rpcport": 80 - }, - { - "coin": "OCT", - "name": "octus", - "fname": "Octus", - "etomic": "0x7e9d365C0C97Fe5FcAdcc1B513Af974b768C5867", - "rpcport": 80 - }, - { - "coin": "OMG", - "name": "omisego", - "fname": "OmiseGo", - "etomic": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", - "rpcport": 80 - }, - { - "coin": "R", - "name": "revain", - "fname": "Revain", - "etomic": "0x48f775efbe4f5ece6e0df2f7b5932df56823b990", - "rpcport": 80 - }, - { - "coin": "UCASH", - "name": "ucash", - "fname": "U.CASH", - "etomic": "0x92e52a1a235d9a103d970901066ce910aacefd37", - "rpcport": 80 - }, - { - "coin": "ICX", - "name": "icon", - "fname": "ICON", - "etomic": "0xb5a5f22694352c15b00323844ad545abb2b11028", - "decimals": 18, - "rpcport": 80 - }, - { - "coin": "BNB", - "name": "binance-coin", - "fname": "Binance Coin", - "etomic": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "rpcport": 80 - }, - { - "coin": "BTK", - "name": "bitcointoken", - "fname": "BitcoinToken", - "etomic": "0xdb8646F5b487B5Dd979FAC618350e85018F557d4", - "rpcport": 80 - }, - { - "coin": "DAI", - "name": "dai", - "fname": "Dai", - "etomic": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "rpcport": 80 - }, - { - "coin": "DDD", - "name": "scryinfo", - "fname": "Scry.info", - "etomic": "0x9F5F3CFD7a32700C93F971637407ff17b91c7342", - "rpcport": 80 - }, - { - "coin": "DGD", - "name": "digixdao", - "fname": "DigixDAO", - "etomic": "0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A", - "decimals": 9, - "rpcport": 80 - }, - { - "coin": "DGPT", - "name": "digipulse", - "fname": "DigiPulse", - "etomic": "0xf6cFe53d6FEbaEEA051f400ff5fc14F0cBBDacA1", - "rpcport": 80 - }, - { - "coin": "DRGN", - "name": "dragonchain", - "fname": "Dragonchain", - "etomic": "0x419c4db4b9e25d6db2ad9691ccb832c8d9fda05e", - "rpcport": 80 - }, - { - "coin": "FLLW", - "name": "followcoin", - "fname": "FollowCoin", - "etomic": "0x0200412995f1bafef0d3f97c4e28ac2515ec1ece", - "rpcport": 80 - }, - { - "coin": "FSN", - "name": "fusion", - "fname": "Fusion", - "etomic": "0xd0352a019e9ab9d757776f532377aaebd36fd541", - "rpcport": 80 - }, - { - "coin": "HYD", - "name": "hydra", - "fname": "Hydra", - "etomic": "0xD233495C48EB0143661fFC8458EAfc21b633f97f", - "rpcport": 80 - }, - { - "coin": "IOST", - "name": "iostoken", - "fname": "IOST", - "etomic": "0xfa1a856cfa3409cfa145fa4e20eb270df3eb21ab", - "rpcport": 80 - }, - { - "coin": "PPT", - "name": "populous", - "fname": "Populous", - "etomic": "0xd4fa1460F537bb9085d22C7bcCB5DD450Ef28e3a", - "rpcport": 80 - }, - { - "coin": "LRC", - "name": "loopring", - "fname": "Loopring", - "etomic": "0xEF68e7C694F40c8202821eDF525dE3782458639f", - "decimals": 18, - "rpcport": 80 - }, - { - "coin": "MDS", - "name": "medishares", - "fname": "MediShares", - "etomic": "0x66186008C1050627F979d464eABb258860563dbE", - "rpcport": 80 - }, - { - "coin": "MKR", - "name": "maker", - "fname": "Maker", - "etomic": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", - "rpcport": 80 - }, - { - "coin": "SNT", - "name": "status", - "fname": "Status", - "etomic": "0x744d70FDBE2Ba4CF95131626614a1763DF805B9E", - "rpcport": 80 - }, - { - "coin": "REP", - "name": "augur", - "fname": "Augur", - "etomic": "0x1985365e9f78359a9B6AD760e32412f4a445E862", - "rpcport": 80 - }, - { - "coin": "SRN", - "name": "sirin-labs-token", - "fname": "SIRIN LABS Token", - "etomic": "0x68d57c9a1c35f63e2c83ee8e49a64e9d70528d25", - "rpcport": 80 - }, - { - "coin": "YLC", - "name": "yolocash", - "fname": "YoloCash", - "etomic": "0x21d5678A62DFe63a47062469Ebb2fAc2817D8832", - "rpcport": 80 - }, - { - "coin": "ZRX", - "name": "0x", - "fname": "0x", - "etomic": "0xE41d2489571d322189246DaFA5ebDe1F4699F498", - "rpcport": 80 - }, - { - "coin": "BAT", - "name": "basic-attention-token", - "fname": "Basic Attention Token", - "etomic": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "rpcport": 80 - }, - { - "coin": "ETHOS", - "name": "ethos", - "fname": "Ethos", - "etomic": "0x5Af2Be193a6ABCa9c8817001F45744777Db30756", - "rpcport": 80 - }, - { - "coin": "QASH", - "name": "qash", - "fname": "Qash", - "etomic": "0x618E75Ac90b12c6049Ba3b27f5d5F8651b0037F6", - "rpcport": 80 - }, - { - "coin": "FUN", - "name": "funfair", - "fname": "FunFair", - "etomic": "0x419D0d8BdD9aF5e606Ae2232ed285Aff190E711b", - "rpcport": 80 - }, - { - "coin": "KNC", - "name": "kyber-network", - "fname": "Kyber Network", - "etomic": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - "rpcport": 80 - }, - { - "coin": "SALT", - "name": "salt", - "fname": "Salt", - "etomic": "0x4156D3342D5c385a87D264F90653733592000581", - "rpcport": 80 - }, - { - "coin": "BNT", - "name": "bancor", - "fname": "Bancor", - "etomic": "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C", - "rpcport": 80 - }, - { - "coin": "ICN", - "name": "iconomi", - "fname": "Iconomi", - "etomic": "0x888666CA69E0f178DED6D75b5726Cee99A87D698", - "rpcport": 80 - }, - { - "coin": "LUPX", - "name": "lupecoin", - "fname": "Lupecoin", - "etomic": "0x49C67AE22c334D0123dD6DBDc44F5302e130a88b", - "rpcport": 80 - }, - { - "coin": "NAS", - "name": "nebulas-token", - "fname": "Nebulas", - "etomic": "0x5d65d971895edc438f465c17db6992698a52318d", - "rpcport": 80 - }, - { - "coin": "PAY", - "name": "tenx", - "fname": "TenX", - "etomic": "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280", - "rpcport": 80 - }, - { - "coin": "REQ", - "name": "request-network", - "fname": "Request Network", - "etomic": "0x8f8221aFbB33998d8584A2B05749bA73c37a938a", - "rpcport": 80 - }, - { - "coin": "STORJ", - "name": "storj", - "fname": "Storj", - "etomic": "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC", - "rpcport": 80 - }, - { - "coin": "STWY", - "name": "storweeytoken", - "fname": "StorweeyToken", - "etomic": "0x8a8c71f032362fca2994f75d854f911ec381ac5a", - "rpcport": 80 - }, - { - "coin": "GNO", - "name": "gnosis-gno", - "fname": "Gnosis", - "etomic": "0x6810e776880C02933D47DB1b9fc05908e5386b96", - "rpcport": 80 - }, - { - "coin": "RLC", - "name": "rlc", - "fname": "iExec RLC", - "etomic": "0x607F4C5BB672230e8672085532f7e901544a7375", - "rpcport": 80 - }, - { - "coin": "ENJ", - "name": "enjin-coin", - "fname": "Enjin Coin", - "etomic": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", - "rpcport": 80 - }, - { - "coin": "QSP", - "name": "quantstamp", - "fname": "Quantstamp", - "etomic": "0x99ea4dB9EE77ACD40B119BD1dC4E33e1C070b80d", - "rpcport": 80 - }, - { - "coin": "RDN", - "name": "raiden-network-token", - "fname": "Raiden Network Token", - "etomic": "0x255Aa6DF07540Cb5d3d297f0D0D4D84cb52bc8e6", - "rpcport": 80 - }, - { - "coin": "WTC", - "name": "waltonchain", - "fname": "Waltonchain", - "etomic": "0xb7cb1c96db6b22b0d3d9536e0108d062bd488f74", - "rpcport": 80 - }, - { - "coin": "CVC", - "name": "civic", - "fname": "Civic", - "etomic": "0x41e5560054824eA6B0732E656E3Ad64E20e94E45", - "rpcport": 80 - }, - { - "coin": "SAN", - "name": "santiment", - "fname": "Santiment", - "etomic": "0x7C5A0CE9267ED19B22F8cae653F198e3E8daf098", - "rpcport": 80 - }, - { - "coin": "ANT", - "name": "aragon", - "fname": "Aragon", - "etomic": "0x960b236A07cf122663c4303350609A66A7B288C0", - "rpcport": 80 - }, - { - "coin": "LOOM", - "name": "loom-network", - "fname": "Loom Network", - "etomic": "0xa4e8c3ec456107ea67d3075bf9e3df3a75823db0", - "rpcport": 80 - }, - { - "coin": "MANA", - "name": "decentraland", - "fname": "Decentraland", - "etomic": "0x0F5D2fB29fb7d3CFeE444a200298f468908cC942", - "rpcport": 80 - }, - { - "coin": "MCO", - "name": "monaco", - "fname": "Monaco", - "etomic": "0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d", - "rpcport": 80 - }, - { - "coin": "MGO", - "name": "mobilego", - "fname": "MobileGo", - "etomic": "0x40395044Ac3c0C57051906dA938B54BD6557F212", - "rpcport": 80 - }, - { - "coin": "MTL", - "name": "metal", - "fname": "Metal", - "etomic": "0xF433089366899D83a9f26A773D59ec7eCF30355e", - "rpcport": 80 - }, - { - "coin": "EDG", - "name": "edgeless", - "fname": "Edgeless", - "etomic": "0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c", - "rpcport": 80 - }, - { - "coin": "MLN", - "name": "melon", - "fname": "Melon", - "etomic": "0xBEB9eF514a379B997e0798FDcC901Ee474B6D9A1", - "rpcport": 80 - }, - { - "coin": "AMB", - "name": "amber", - "fname": "Ambrosus", - "etomic": "0x4DC3643DbC642b72C158E7F3d2ff232df61cb6CE", - "rpcport": 80 - }, - { - "coin": "WINGS", - "name": "wings", - "fname": "Wings", - "etomic": "0x667088b212ce3d06a1b553a7221E1fD19000d9aF", - "rpcport": 80 - }, - { - "coin": "POWR", - "name": "power-ledger", - "fname": "Power Ledger", - "etomic": "0x595832f8fc6bf59c85c527fec3740a1b7a361269", - "rpcport": 80 - }, - { - "coin": "PRL", - "name": "oyster", - "fname": "Oyster", - "etomic": "0x1844b21593262668b7248d0f57a220caaba46ab9", - "rpcport": 80 - }, - { - "coin": "RHOC", - "name": "rchain", - "fname": "RChain", - "etomic": "0x168296bb09e24a88805cb9c33356536b980d3fc5", - "rpcport": 80 - }, - { - "coin": "RCN", - "name": "ripio-credit-network", - "fname": "Ripio Credit Network", - "etomic": "0xF970b8E36e23F7fC3FD752EeA86f8Be8D83375A6", - "rpcport": 80 - }, - { - "coin": "SANC", - "name": "sancoj", - "fname": "Sancoj", - "etomic": "0x03ec7bb59be036870ef696a2abf124f496d6735a", - "rpcport": 80 - }, - { - "coin": "SNGLS", - "name": "singulardtv", - "fname": "SingularDTV", - "etomic": "0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009", - "rpcport": 80 - }, - { - "coin": "TAAS", - "name": "taas", - "fname": "TaaS", - "etomic": "0xE7775A6e9Bcf904eb39DA2b68c5efb4F9360e08C", - "rpcport": 80 - }, - { - "coin": "DNT", - "name": "district0x", - "fname": "District0x", - "etomic": "0x0AbdAce70D3790235af448C88547603b945604ea", - "rpcport": 80 - }, - { - "coin": "CFI", - "name": "cofound-it", - "fname": "Cofound.it", - "etomic": "0x12FEF5e57bF45873Cd9B62E9DBd7BFb99e32D73e", - "rpcport": 80 - }, - { - "coin": "LUN", - "name": "lunyr", - "fname": "Lunyr", - "etomic": "0xfa05A73FfE78ef8f1a739473e462c54bae6567D9", - "rpcport": 80 - }, - { - "coin": "ADT", - "name": "adtoken", - "fname": "adToken", - "etomic": "0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD", - "rpcport": 80 - }, - { - "coin": "AST", - "name": "airswap", - "fname": "AirSwap", - "etomic": "0x27054b13b1B798B345b591a4d22e6562d47eA75a", - "rpcport": 80 - }, - { - "coin": "CDT", - "name": "blox", - "fname": "Blox", - "etomic": "0x177d39AC676ED1C67A2b268AD7F1E58826E5B0af", - "rpcport": 80 - }, - { - "coin": "TKN", - "name": "tokencard", - "fname": "TokenCard", - "etomic": "0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a", - "rpcport": 80 - }, - { - "coin": "HMQ", - "name": "humaniq", - "fname": "Humaniq", - "etomic": "0xcbCC0F036ED4788F63FC0fEE32873d6A7487b908", - "rpcport": 80 - }, - { - "coin": "BCAP", - "name": "bcap", - "fname": "Bcap", - "etomic": "0xFf3519eeeEA3e76F1F699CCcE5E23ee0bdDa41aC", - "rpcport": 80 - }, - { - "coin": "NMR", - "name": "numeraire", - "fname": "Numeraire", - "etomic": "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671", - "rpcport": 80 - }, - { - "coin": "NET", - "name": "nimiq", - "fname": "Nimiq", - "etomic": "0xcfb98637bcae43C13323EAa1731cED2B716962fD", - "rpcport": 80 - }, - { - "coin": "TRST", - "name": "trust", - "fname": "Trust", - "etomic": "0xCb94be6f13A1182E4A4B6140cb7bf2025d28e41B", - "rpcport": 80 - }, - { - "coin": "GUP", - "name": "guppy", - "fname": "Matchpool", - "etomic": "0xf7B098298f7C69Fc14610bf71d5e02c60792894C", - "rpcport": 80 - }, - { - "coin": "1ST", - "name": "firstblood", - "fname": "FirstBlood", - "etomic": "0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7", - "rpcport": 80 - }, - { - "coin": "TIME", - "name": "chronobank", - "fname": "Chronobank", - "etomic": "0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53", - "rpcport": 80 - }, - { - "coin": "SWT", - "name": "swarm-city", - "fname": "Swarm City", - "etomic": "0xB9e7F8568e08d5659f5D29C4997173d84CdF2607", - "rpcport": 80 - }, - { - "coin": "DICE", - "name": "etheroll", - "fname": "Etheroll", - "etomic": "0x2e071D2966Aa7D8dECB1005885bA1977D6038A65", - "rpcport": 80 - }, - { - "coin": "XAUR", - "name": "xaurum", - "fname": "Xarum", - "etomic": "0x4DF812F6064def1e5e029f1ca858777CC98D2D81", - "rpcport": 80 - }, - { - "coin": "XOV", - "name": "xovbank", - "fname": "XOVBank", - "etomic": "0x153eD9CC1b792979d2Bde0BBF45CC2A7e436a5F9", - "rpcport": 80 - }, - { - "coin": "PLU", - "name": "pluton", - "fname": "Pluton", - "etomic": "0xD8912C10681D8B21Fd3742244f44658dBA12264E", - "rpcport": 80 - }, - { - "coin": "HGT", - "name": "hellogold", - "fname": "HelloGold", - "etomic": "0xba2184520A1cC49a6159c57e61E1844E085615B6", - "rpcport": 80 - }, - { - "coin": "VSL", - "name": "vslice", - "fname": "vSlice", - "etomic": "0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170", - "decimals": 18, - "rpcport": 80 - }, - { - "coin": "IND", - "name": "indorse-token", - "fname": "Indorse Token", - "etomic": "0xf8e386EDa857484f5a12e4B5DAa9984E06E73705", - "rpcport": 80 - }, - { - "coin": "FYN", - "name": "fundyourselfnow", - "fname": "FundYourselfNow", - "etomic": "0x88FCFBc22C6d3dBaa25aF478C578978339BDe77a", - "rpcport": 80 - }, - { - "coin": "JST", - "name": "JST", - "fname": "JST (TESTCOIN)", - "etomic": "0xc0eb7AeD740E1796992A08962c15661bDEB58003", - "rpcport": 80 - }, - { - "coin": "DEC8", - "name": "DEC8", - "fname": "DEC8 (TESTCOIN)", - "etomic": "0x3ab100442484dc2414aa75b2952a0a6f03f8abfd", - "rpcport": 80 - }, - { - "coin": "ETH", - "name": "ethereum", - "fname": "Ethereum", - "etomic": "0x0000000000000000000000000000000000000000", - "rpcport": 80 - }, - { - "coin": "ZIL", - "name": "zilliqa", - "fname": "Zilliqa", - "etomic": "0x05f4a42e251f2d52b8ed15e9fedaacfcef1fad27", - "rpcport": 80 - }, - { - "coin": "BITS", - "name": "bitstar", - "fname": "Bitstar", - "rpcport": 15715, - "isPoS": 1, - "pubtype": 25, - "p2shtype": 8, - "wiftype": 153, - "txfee": 10000 - }, - { - "coin": "ELI", - "name": "elicoin", - "fname": "Elicoin", - "rpcport": 9332, - "pubtype": 33, - "p2shtype": 102, - "wiftype": 205, - "txfee": 10000 - }, - { - "coin": "SCRIV", - "name": "scriv", - "fname": "Scriv", - "confpath": "USERHOME/.scrivcore/scriv.conf", - "rpcport": 7998, - "pubtype": 125, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "SMART", - "name": "smartcash", - "fname": "SmartCash", - "rpcport": 9679, - "pubtype": 63, - "p2shtype": 18, - "wiftype": 191, - "txfee": 200000 - }, - { - "coin": "ELP", - "name": "ellerium", - "fname": "Ellerium", - "rpcport": 61020, - "pubtype": 23, - "p2shtype": 13, - "wiftype": 212, - "txfee": 10000 - }, - { - "coin": "XCOIN", - "name": "xcoin", - "fname": "xCoin", - "rpcport": 22717, - "pubtype": 137, - "p2shtype": 15, - "wiftype": 75, - "txfee": 100000 - }, - { - "coin": "ROI", - "name": "ROIcoin", - "fname": "ROICoin", - "rpcport": 3376, - "pubtype": 60, - "p2shtype": 122, - "wiftype": 128, - "txfee": 200000 - }, - { - "coin": "BTCP", - "name": "btcprivate", - "fname": "BitcoinPrivate", - "rpcport": 7932, - "taddr": 19, - "pubtype": 37, - "p2shtype": 175, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "DNR", - "name": "denarius", - "fname": "Denarius", - "rpcport": 32339, - "isPoS": 1, - "pubtype": 30, - "p2shtype": 90, - "wiftype": 158, - "txfee": 10000 - }, - { - "coin": "RVN", - "name": "raven", - "fname": "Raven", - "rpcport": 8766, - "pubtype": 60, - "p2shtype": 122, - "wiftype": 128, - "txfee": 100000 - }, - { - "coin": "VIVO", - "name": "vivo", - "fname": "Vivo", - "confpath": "USERHOME/.vivocore/vivo.conf", - "rpcport": 9998, - "pubtype": 70, - "p2shtype": 10, - "wiftype": 198, - "txfee": 10000 - }, - { - "coin": "KNG", - "name": "kings", - "fname": "Kings", - "rpcport": 44888, - "pubtype": 75, - "p2shtype": 125, - "wiftype": 203, - "txfee": 10000 - }, - { - "coin": "UFO", - "name": "ufocoin", - "fname": "Uniform Fiscal Object", - "confpath": "USERHOME/.ufo/ufocoin.conf", - "rpcport": 9888, - "pubtype": 27, - "p2shtype": 5, - "wiftype": 155, - "txfee": 100000 - }, - { - "coin": "KREDS", - "name": "kreds", - "fname": "Kreds", - "rpcport": 3850, - "pubtype": 45, - "p2shtype": 5, - "wiftype": 195, - "txfee": 10000 - }, - { - "coin": "XSG", - "name": "snowgem", - "fname": "SnowGem", - "rpcport": 16112, - "taddr": 28, - "pubtype": 40, - "p2shtype": 45, - "wiftype": 128, - "txversion": 4, - "txfee": 10000 - }, - { - "coin": "ZEL", - "name": "zelcash", - "fname": "Zelcash", - "rpcport": 16124, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "OOT", - "asset": "OOT", - "fname": "Utrum", - "rpcport": 12467 - }, - { - "coin": "PIVX", - "name": "pivx", - "fname": "PivX", - "rpcport": 51473, - "pubtype": 30, - "p2shtype": 13, - "wiftype": 212, - "txfee": 10000 - }, - { - "coin": "HTML", - "name": "htmlcoin", - "fname": "HTML Coin", - "rpcport": 4889, - "pubtype": 41, - "p2shtype": 100, - "wiftype": 169, - "txfee": 400000 - }, - { - "coin": "MNX", - "name": "Minexcoin", - "fname": "Minexcoin", - "rpcport": 17786, - "pubtype": 75, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "LTZ", - "name": "litecoinz", - "fname": "Litecoinz", - "rpcport": 29332, - "taddr": 10, - "pubtype": 179, - "p2shtype": 184, - "wiftype": 128, - "txversion": 4, - "txfee": 1000 - }, - { - "coin": "MLM", - "name": "mktcoin", - "fname": "MktCoin", - "rpcport": 9276, - "pubtype": 110, - "p2shtype": 115, - "wiftype": 238, - "txfee": 10000 - }, - { - "coin": "BAY", - "name": "bitbay", - "fname": "Bitbay", - "isPoS": 1, - "rpcport": 19915, - "pubtype": 25, - "p2shtype": 85, - "wiftype": 153, - "txfee": 10000 - }, - { - "coin": "CRC", - "name": "crowdcoin", - "fname": "Crowdcoin", - "confpath": "USERHOME/.crowdcoincore/crowdcoin.conf", - "rpcport": 11998, - "pubtype": 28, - "p2shtype": 88, - "wiftype": 0, - "txfee": 10000 - }, - { - "coin": "NOR", - "name": "noir", - "fname": "Noir", - "rpcport": 8255, - "pubtype": 80, - "p2shtype": 7, - "wiftype": 208, - "txfee": 1000 - }, - { - "coin": "PIZZA", - "asset": "PIZZA", - "fname": "PIZZA (TESTCOIN)", - "rpcport": 11116 - }, - { - "coin": "BEER", - "asset": "BEER", - "fname": "BEER (TESTCOIN)", - "rpcport": 8923 - }, - { - "coin": "GRS", - "name": "groestlcoin", - "fname": "Groestlcoin", - "rpcport": 1441, - "pubtype": 36, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "VOT", - "name": "votecoin", - "fname": "Votecoin", - "rpcport": 8232, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txversion": 4, - "txfee": 10000 - }, - { - "coin": "BZC", - "name": "bitzec", - "fname": "Bitzec", - "rpcport": 8732, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txversion": 4, - "txfee": 10000 - }, - { - "coin": "XMCC", - "name": "monoeci", - "fname": "Monoeci", - "confpath": "USERHOME/.monoeciCore/monoeci.conf", - "rpcport": 24156, - "pubtype": 50, - "p2shtype": 73, - "wiftype": 77, - "txfee": 10000 - }, - { - "coin": "ABY", - "name": "applebyte", - "fname": "ArtByte", - "rpcport": 8607, - "pubtype": 23, - "p2shtype": 5, - "wiftype": 151, - "txfee": 100000 - }, - { - "coin": "BTCH", - "asset": "BTCH", - "fname": "Bitcoin Hush", - "rpcport": 8800 - }, - { - "coin": "ETOMIC", - "asset": "ETOMIC", - "fname": "ETOMIC", - "rpcport": 10271 - }, - { - "coin": "AXO", - "asset": "AXO", - "fname": "AXO", - "rpcport": 12927 - }, - { - "coin": "INN", - "name": "innova", - "fname": "Innova", - "confpath": "USERHOME/.innovacore/innova.conf", - "rpcport": 8818, - "pubtype": 102, - "p2shtype": 20, - "wiftype": 195, - "txfee": 10000 - }, - { - "coin": "MOON", - "name": "mooncoin", - "fname": "Mooncoin", - "rpcport": 44663, - "pubtype": 3, - "p2shtype": 22, - "wiftype": 131, - "txfee": 100000 - }, - { - "coin": "CRW", - "name": "crown", - "fname": "Crown", - "rpcport": 9341, - "pubtype": 0, - "p2shtype": 28, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "EFL", - "name": "egulden", - "fname": "Egulden", - "confpath": "USERHOME/.egulden/coin.conf", - "rpcport": 21015, - "pubtype": 48, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "GBX", - "name": "gobyte", - "fname": "gobyte", - "confpath": "USERHOME/.gobytecore/gobyte.conf", - "rpcport": 12454, - "pubtype": 38, - "p2shtype": 10, - "wiftype": 198, - "txfee": 10000 - }, - { - "coin": "BCO", - "name": "bridgecoin", - "fname": "Bridgecoin", - "rpcport": 6332, - "pubtype": 27, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "XZC", - "name": "zcoin", - "fname": "Zcoin", - "rpcport": 8888, - "pubtype": 82, - "p2shtype": 7, - "wiftype": 210, - "txfee": 10000 - }, - { - "coin": "BTG", - "name": "bitcoingold", - "fname": "BitcoinGold", - "rpcport": 12332, - "pubtype": 38, - "p2shtype": 23, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "BLK", - "name": "lore", - "fname": "Blackcoin", - "isPoS": 1, - "rpcport": 15715, - "pubtype": 25, - "p2shtype": 85, - "wiftype": 153, - "txfee": 100000 - }, - { - "coin": "BCH", - "name": "bch", - "fname": "Bitcoin Cash", - "rpcport": 33333, - "pubtype": 0, - "p2shtype": 5, - "wiftype": 128, - "txfee": 1000 - }, - { - "coin": "QMC", - "name": "qmc2", - "fname": "QMCoin", - "rpcport": 55777, - "pubtype": 58, - "p2shtype": 120, - "wiftype": 1, - "txfee": 10000 - }, - { - "coin": "QTUM", - "name": "qtum", - "fname": "Qtum", - "rpcport": 3889, - "pubtype": 58, - "p2shtype": 50, - "wiftype": 128, - "txfee": 400000 - }, - { - "coin": "PGN", - "name": "pigeon", - "fname": "Pigeon", - "rpcport": 8756, - "pubtype": 55, - "p2shtype": 122, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "PURA", - "name": "pura", - "fname": "Pura", - "rpcport": 55555, - "pubtype": 55, - "p2shtype": 16, - "wiftype": 150, - "txfee": 10000 - }, - { - "coin": "DSR", - "name": "desire", - "fname": "Desire", - "confpath": "USERHOME/.desirecore/desire.conf", - "rpcport": 9918, - "pubtype": 30, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "MNZ", - "asset": "MNZ", - "fname": "Monaize", - "rpcport": 14337 - }, - { - "coin": "BTCZ", - "name": "bitcoinz", - "fname": "BitcoinZ", - "rpcport": 1979, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "MAGA", - "name": "magacoin", - "fname": "Magacoin", - "rpcport": 5332, - "pubtype": 23, - "p2shtype": 50, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "BSD", - "name": "bitsend", - "fname": "Bitsend", - "rpcport": 8800, - "pubtype": 102, - "p2shtype": 5, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "IOP", - "name": "iop", - "fname": "IoP", - "rpcport": 8337, - "pubtype": 117, - "p2shtype": 174, - "wiftype": 49, - "txfee": 10000 - }, - { - "coin": "BLOCK", - "name": "blocknetdx", - "fname": "BlocknetDX", - "rpcport": 41414, - "pubtype": 26, - "p2shtype": 28, - "wiftype": 154, - "txfee": 10000 - }, - { - "coin": "CHIPS", - "name": "chips", - "fname": "Chips", - "rpcport": 57776, - "pubtype": 60, - "p2shtype": 85, - "wiftype": 188, - "txfee": 10000 - }, - { - "coin": "888", - "name": "octocoin", - "fname": "Octocoin", - "rpcport": 22888, - "pubtype": 18, - "p2shtype": 5, - "wiftype": 176, - "txfee": 2000000 - }, - { - "coin": "ARG", - "name": "argentum", - "fname": "Argentum", - "rpcport": 13581, - "pubtype": 23, - "p2shtype": 5, - "wiftype": 151, - "txfee": 50000 - }, - { - "coin": "GLD", - "name": "goldcoin", - "fname": "GoldCoin", - "rpcport": 9332, - "pubtype": 32, - "p2shtype": 5, - "wiftype": 160, - "txfee": 100000 - }, - { - "coin": "GLT", - "name": "globaltoken", - "fname": "GlobalToken", - "rpcport": 9320, - "pubtype": 38, - "p2shtype": 5, - "wiftype": 166, - "txfee": 10000 - }, - { - "coin": "ZER", - "name": "zero", - "fname": "Zero", - "rpcport": 23801, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txfee": 1000 - }, - { - "coin": "HODLC", - "name": "hodlcoin", - "fname": "Hodlcoin", - "rpcport": 11989, - "pubtype": 40, - "p2shtype": 5, - "wiftype": 168, - "txfee": 5000 - }, - { - "coin": "UIS", - "name": "unitus", - "fname": "Unitus", - "rpcport": 50604, - "pubtype": 68, - "p2shtype": 10, - "wiftype": 132, - "txfee": 2000000 - }, - { - "coin": "HUC", - "name": "huntercoin", - "fname": "Huntercoin", - "rpcport": 8399, - "pubtype": 40, - "p2shtype": 13, - "wiftype": 168, - "txfee": 100000 - }, - { - "coin": "BDL", - "name": "bitdeal", - "fname": "Bitdeal", - "rpcport": 9332, - "pubtype": 38, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "ARC", - "name": "arcticcoin", - "fname": "Advanced Technology Coin", - "confpath": "USERHOME/.arcticcore/arcticcoin.conf", - "rpcport": 7208, - "pubtype": 23, - "p2shtype": 8, - "wiftype": 176, - "txfee": 10000 - }, - { - "coin": "ZCL", - "name": "zclassic", - "fname": "ZClassic", - "rpcport": 8023, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txfee": 1000 - }, - { - "coin": "VIA", - "name": "viacoin", - "fname": "Viacoin", - "rpcport": 5222, - "pubtype": 71, - "p2shtype": 33, - "wiftype": 199, - "txfee": 100000 - }, - { - "coin": "ERC", - "name": "europecoin", - "fname": "Europecoin", - "rpcport": 11989, - "pubtype": 33, - "p2shtype": 5, - "wiftype": 168, - "txfee": 10000 - }, - { - "coin": "FAIR", - "name": "faircoin", - "fname": "Faircoin", - "confpath": "USERHOME/.faircoin2/faircoin.conf", - "rpcport": 40405, - "pubtype": 95, - "p2shtype": 36, - "wiftype": 223, - "txfee": 2000000 - }, - { - "coin": "FLO", - "name": "flo", - "fname": "Florincoin", - "rpcport": 7313, - "pubtype": 35, - "p2shtype": 8, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "SXC", - "name": "sexcoin", - "fname": "Sexcoin", - "rpcport": 9561, - "pubtype": 62, - "p2shtype": 5, - "wiftype": 190, - "txfee": 100000 - }, - { - "coin": "CREA", - "name": "creativecoin", - "fname": "Creativecoin", - "rpcport": 17711, - "pubtype": 28, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "TRC", - "name": "terracoin", - "fname": "Terracoin", - "confpath": "USERHOME/.terracoincore/terracoin.conf", - "rpcport": 13332, - "pubtype": 0, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "BTA", - "name": "bata", - "fname": "Beta", - "rpcport": 5493, - "pubtype": 25, - "p2shtype": 5, - "wiftype": 188, - "txfee": 100000 - }, - { - "coin": "SMC", - "name": "smartcoin", - "fname": "Smartcoin", - "rpcport": 58583, - "pubtype": 63, - "p2shtype": 5, - "wiftype": 191, - "txfee": 1000000 - }, - { - "coin": "NMC", - "name": "namecoin", - "fname": "Namecoin", - "rpcport": 8336, - "pubtype": 52, - "p2shtype": 13, - "wiftype": 180, - "txfee": 100000 - }, - { - "coin": "NAV", - "name": "navcoin", - "fname": "Navcoin", - "isPoS": 1, - "confpath": "USERHOME/.navcoin4/navcoin.conf", - "rpcport": 44444, - "pubtype": 53, - "p2shtype": 85, - "wiftype": 150, - "txfee": 10000 - }, - { - "coin": "NIX", - "name": "nix", - "fname": "NIX", - "rpcport": 6215, - "pubtype": 38, - "p2shtype": 53, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "EMC2", - "name": "einsteinium", - "fname": "Einsteinim", - "rpcport": 41879, - "pubtype": 33, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "SYS", - "name": "syscoin", - "fname": "Syscoin", - "confpath": "USERHOME/.syscoincore/syscoin.conf", - "rpcport": 8370, - "pubtype": 63, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "I0C", - "name": "i0coin", - "fname": "I0Coin", - "rpcport": 7332, - "pubtype": 105, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "DASH", - "name": "dashcore", - "fname": "Dash", - "confpath": "USERHOME/.dashcore/dash.conf", - "rpcport": 9998, - "pubtype": 76, - "p2shtype": 16, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "STRAT", - "name": "stratis", - "fname": "Stratis", - "rpcport": 16174, - "pubtype": 63, - "p2shtype": 125, - "wiftype": 191, - "txfee": 10000 - }, - { - "coin": "MUE", - "name": "monetaryunit", - "fname": "MonetaryUnit", - "rpcport": 19688, - "pubtype": 16, - "p2shtype": 76, - "wiftype": 126, - "txfee": 10000 - }, - { - "coin": "MONA", - "name": "monacoin", - "fname": "Monacoin", - "rpcport": 9402, - "pubtype": 50, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "XMY", - "name": "myriadcoin", - "fname": "Myriadcoin", - "rpcport": 10889, - "pubtype": 50, - "p2shtype": 9, - "wiftype": 178, - "txfee": 5000 - }, - { - "coin": "MAC", - "name": "machinecoin", - "fname": "Machinecoin", - "rpcport": 40332, - "pubtype": 50, - "p2shtype": 5, - "wiftype": 178, - "txfee": 50000 - }, - { - "coin": "BTX", - "name": "bitcore", - "fname": "Bitcore", - "rpcport": 8556, - "pubtype": 3, - "p2shtype": 125, - "wiftype": 128, - "txfee": 50000 - }, - { - "coin": "XRE", - "name": "revolvercoin", - "fname": "Revolvercoin", - "rpcport": 8775, - "pubtype": 0, - "p2shtype": 5, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "LBC", - "name": "lbrycrd", - "fname": "Lbrycrd", - "rpcport": 9245, - "pubtype": 85, - "p2shtype": 122, - "wiftype": 28, - "txfee": 10000 - }, - { - "coin": "SIB", - "name": "sibcoin", - "fname": "SIBcoin", - "rpcport": 1944, - "pubtype": 63, - "p2shtype": 40, - "wiftype": 128, - "txfee": 10000 - }, - { - "coin": "VTC", - "name": "vertcoin", - "fname": "Vertcoin", - "rpcport": 5888, - "pubtype": 71, - "p2shtype": 5, - "wiftype": 128, - "txfee": 100000 - }, - { - "coin": "REVS", - "asset": "REVS", - "fname": "REVS", - "rpcport": 10196 - }, - { - "coin": "VRSC", - "asset": "VRSC", - "fname": "VerusCoin", - "txversion": 4, - "rpcport": 27486 - }, - { - "coin": "ZILLA", - "asset": "ZILLA", - "fname": "ChainZilla", - "rpcport": 10041 - }, - { - "coin": "JUMBLR", - "asset": "JUMBLR", - "fname": "JUMBLR", - "rpcport": 15106 - }, - { - "coin": "DOGE", - "name": "dogecoin", - "fname": "Dogecoin", - "rpcport": 22555, - "pubtype": 30, - "p2shtype": 22, - "wiftype": 158, - "txfee": 100000000 - }, - { - "coin": "HUSH", - "name": "hush", - "fname": "Hush", - "rpcport": 8822, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txfee": 1000 - }, - { - "coin": "ZEC", - "name": "zcash", - "fname": "Zcash", - "rpcport": 8232, - "taddr": 28, - "pubtype": 184, - "p2shtype": 189, - "wiftype": 128, - "txversion": 4, - "txfee": 10000 - }, - { - "coin": "DGB", - "name": "digibyte", - "fname": "Digibyte", - "rpcport": 14022, - "pubtype": 30, - "p2shtype": 5, - "wiftype": 128, - "txfee": 100000 - }, - { - "coin": "ZET", - "name": "zetacoin", - "fname": "Zetacoin", - "pubtype": 80, - "p2shtype": 9, - "rpcport": 8332, - "wiftype": 224, - "txfee": 10000 - }, - { - "coin": "GAME", - "rpcport": 40001, - "name": "gamecredits", - "fname": "GameCredits", - "pubtype": 38, - "p2shtype": 5, - "wiftype": 166, - "txfee": 1000000 - }, - { - "coin": "LTC", - "name": "litecoin", - "fname": "Litecoin", - "rpcport": 9332, - "pubtype": 48, - "p2shtype": 5, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "SUPERNET", - "asset": "SUPERNET", - "fname": "SUPERNET", - "rpcport": 11341 - }, - { - "coin": "WLC", - "asset": "WLC", - "fname": "Wireless Coin", - "rpcport": 12167 - }, - { - "coin": "PANGEA", - "asset": "PANGEA", - "fname": "Pangea Poker", - "rpcport": 14068 - }, - { - "coin": "DEX", - "asset": "DEX", - "fname": "InstantDEX", - "rpcport": 11890 - }, - { - "coin": "DSEC", - "asset": "DSEC", - "fname": "DSEC", - "rpcport": 11557 - }, - { - "coin": "BET", - "asset": "BET", - "fname": "BET", - "rpcport": 14250 - }, - { - "coin": "CRYPTO", - "asset": "CRYPTO", - "fname": "Crypto777", - "rpcport": 8516 - }, - { - "coin": "HODL", - "asset": "HODL", - "fname": "HODL", - "rpcport": 14431 - }, - { - "coin": "MSHARK", - "asset": "MSHARK", - "fname": "MiliShark", - "rpcport": 8846 - }, - { - "coin": "BOTS", - "asset": "BOTS", - "fname": "BOTS", - "rpcport": 11964 - }, - { - "coin": "MGW", - "asset": "MGW", - "fname": "MultiGateway", - "rpcport": 12386 - }, - { - "coin": "COQUI", - "asset": "COQUI", - "fname": "Coqui Cash", - "rpcport": 14276 - }, - { - "coin": "KV", - "asset": "KV", - "fname": "KeyValue", - "rpcport": 8299 - }, - { - "coin": "CEAL", - "asset": "CEAL", - "fname": "Ceal.io", - "rpcport": 11116 - }, - { - "coin": "MESH", - "asset": "MESH", - "fname": "SuperMESH", - "rpcport": 9455 - }, - { - "coin": "ROGER", - "name": "theholyroger", - "fname": "TheHolyRoger", - "rpcport": 9662, - "pubtype": 61, - "p2shtype": 70, - "wiftype": 176, - "txfee": 100000 - }, - { - "coin": "STAK", - "name": "straks", - "fname": "Starks", - "rpcport": 7574, - "pubtype": 63, - "p2shtype": 5, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "IMG", - "name": "ImageCoin", - "fname": "ImageCoin", - "rpcport": 6999, - "pubtype": 63, - "p2shtype": 5, - "wiftype": 204, - "txfee": 10000 - }, - { - "coin": "MGNX", - "asset": "MGNX", - "fname": "MagnaX", - "rpcport": 20731 - }, - { - "coin": "DION", - "asset": "DION", - "fname": "DionPay", - "rpcport": 23895 - }, - { - "coin": "ZEX", - "asset": "ZEX", - "fname": "Zaddex", - "rpcport": 26477 - }, - { - "coin":"ABP", - "name": "ABP Network", - "rpcport":5426, - "pubtype":30, - "p2shtype":15, - "wiftype":212, - "txfee":10000 - }, - { - "coin": "PUNGO", - "asset": "PGT", - "fname": "Pungo Token", - "rpcport": 46705 - }, - { - "coin": "PTX", - "asset": "PTX", - "fname": "PatentTX", - "rpcport": 61939 - }, - { - "coin": "LUMBER", - "asset": "LUMBER", - "fname": "Lumberscout", - "rpcport": 26301 - } -] diff --git a/etomic_build/client/enable_MORTY b/etomic_build/client/enable_MORTY new file mode 100755 index 0000000000..71f6787808 --- /dev/null +++ b/etomic_build/client/enable_MORTY @@ -0,0 +1,3 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"electrum\",\"coin\":\"MORTY\",\"servers\":[{\"url\":\"electrum1.cipig.net:10018\"},{\"url\":\"electrum2.cipig.net:10018\"},{\"url\":\"electrum3.cipig.net:10018\"}]}" diff --git a/etomic_build/client/enable_RICK b/etomic_build/client/enable_RICK new file mode 100755 index 0000000000..2931b1d07c --- /dev/null +++ b/etomic_build/client/enable_RICK @@ -0,0 +1,3 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"electrum\",\"coin\":\"RICK\",\"servers\":[{\"url\":\"electrum1.cipig.net:10017\"},{\"url\":\"electrum2.cipig.net:10017\"},{\"url\":\"electrum3.cipig.net:10017\"}]}" diff --git a/etomic_build/client/my_recent_swaps b/etomic_build/client/my_recent_swaps new file mode 100755 index 0000000000..c06734c84f --- /dev/null +++ b/etomic_build/client/my_recent_swaps @@ -0,0 +1,10 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data ' +{ + "userpass":"'$userpass'", + "method":"my_recent_swaps", + "limit":2, + "page_number":2 +} +' diff --git a/etomic_build/client/setprice_ONE_ANOTHER b/etomic_build/client/setprice_ONE_ANOTHER new file mode 100755 index 0000000000..2d10588c97 --- /dev/null +++ b/etomic_build/client/setprice_ONE_ANOTHER @@ -0,0 +1,12 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data ' +{ + "userpass":"'$userpass'", + "method":"setprice", + "base":"'$1'", + "rel":"'$2'", + "volume":"1", + "price":"0.5" +} +' diff --git a/etomic_build/coins b/etomic_build/coins deleted file mode 100755 index cf9aaf8987..0000000000 --- a/etomic_build/coins +++ /dev/null @@ -1,3 +0,0 @@ -export coins="[{\"coin\":\"OOT\",\"asset\":\"OOT\",\"rpcport\":12467}, {\"coin\":\"ETH\",\"name\":\"ethereum\",\"etomic\":\"0x0000000000000000000000000000000000000000\",\"rpcport\":80}, {\"coin\":\"EOS\",\"name\":\"EOS\",\"etomic\":\"0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0\",\"rpcport\":80},{\"coin\":\"JST\", \"name\":\"JST\",\"etomic\":\"0xc0eb7AeD740E1796992A08962c15661bDEB58003\",\"rpcport\":80},{\"coin\":\"NODEC\",\"name\":\"NODEC\",\"etomic\":\"0x05beb0a9ead354283041a6d35f3b833450fb5680\",\"rpcport\":80,\"decimals\":18},{\"coin\":\"ZOI\",\"name\":\"zoin\",\"rpcport\":8255,\"pubtype\":80,\"p2shtype\":7,\"wiftype\":208,\"txfee\":1000}, {\"coin\": \"PIZZA\",\"asset\": \"PIZZA\",\"rpcport\": 11608,\"txversion\":4},{\"coin\": \"BEER\",\"asset\": \"BEER\",\"rpcport\": 8923,\"txversion\":4}, {\"coin\":\"GRS\",\"name\":\"groestlcoin\",\"rpcport\":1441,\"pubtype\":36,\"p2shtype\":5,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"XMCC\",\"name\":\"monoeci\",\"confpath\":\"${HOME#}/.monoeciCore/monoeci.conf\",\"rpcport\":24156,\"pubtype\":50,\"p2shtype\":73,\"wiftype\":77,\"txfee\":10000}, {\"coin\":\"BTCH\",\"asset\":\"BTCH\",\"rpcport\":8800},{\"coin\":\"ETOMIC\",\"asset\":\"ETOMIC\",\"rpcport\":10271,\"txversion\":4},{\"coin\":\"AXO\",\"asset\":\"AXO\",\"rpcport\":12927},{\"coin\":\"CRC\",\"name\":\"crowdcoin\",\"confpath\":\"${HOME#}/.crowdcoincore/crowdcoin.conf\",\"rpcport\":11998,\"pubtype\":28,\"p2shtype\":88,\"wiftype\":0,\"txfee\":10000}, {\"coin\":\"VOT\",\"name\":\"votecoin\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"INN\",\"name\":\"innova\",\"confpath\":\"${HOME#}/.innovacore/innova.conf\",\"rpcport\":8818,\"pubtype\":102,\"p2shtype\":20,\"wiftype\":195,\"txfee\":10000}, {\"coin\":\"MOON\",\"name\":\"mooncoin\",\"rpcport\":44663,\"pubtype\":3,\"p2shtype\":22,\"wiftype\":131,\"txfee\":100000}, {\"coin\":\"CRW\",\"name\":\"crown\",\"rpcport\":9341,\"pubtype\":0,\"p2shtype\":28,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"EFL\",\"name\":\"egulden\",\"confpath\":\"${HOME#}/.egulden/coin.conf\",\"rpcport\":21015,\"pubtype\":48,\"p2shtype\":5,\"wiftype\":176,\"txfee\":100000}, {\"coin\":\"GBX\",\"name\":\"gobyte\",\"confpath\":\"${HOME#}/.gobytecore/gobyte.conf\",\"rpcport\":12454,\"pubtype\":38,\"p2shtype\":10,\"wiftype\":198,\"txfee\":10000}, {\"coin\":\"BCO\",\"name\":\"bridgecoin\",\"rpcport\":6332,\"pubtype\":27,\"p2shtype\":5,\"wiftype\":176,\"txfee\":100000}, {\"coin\":\"BLK\",\"name\":\"blackcoin\",\"confpath\":\"${HOME#}/.lore/blackcoin.conf\",\"isPoS\":1,\"rpcport\":15715,\"pubtype\":25,\"p2shtype\":85,\"wiftype\":153,\"txfee\":100000}, {\"coin\":\"BTG\",\"name\":\"bitcoingold\",\"rpcport\":8332,\"pubtype\":38,\"p2shtype\":23,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"BCH\",\"name\":\"bch\",\"rpcport\":33333,\"pubtype\":0,\"p2shtype\":5,\"wiftype\":128,\"txfee\":1000}, {\"coin\":\"ABY\",\"name\":\"applebyte\",\"rpcport\":8607,\"pubtype\":23,\"p2shtype\":5,\"wiftype\":151,\"txfee\":100000}, {\"coin\":\"STAK\",\"name\":\"straks\",\"rpcport\":7574,\"pubtype\":63,\"p2shtype\":5,\"wiftype\":204,\"txfee\":10000}, {\"coin\":\"XZC\",\"name\":\"zcoin\",\"rpcport\":8888,\"pubtype\":82,\"p2shtype\":7,\"wiftype\":210,\"txfee\":10000}, {\"coin\":\"QTUM\",\"name\":\"qtum\",\"rpcport\":3889,\"pubtype\":58,\"p2shtype\":50,\"wiftype\":128,\"txfee\":400000}, {\"coin\":\"PURA\",\"name\":\"pura\",\"rpcport\":55555,\"pubtype\":55,\"p2shtype\":16,\"wiftype\":150,\"txfee\":10000}, {\"coin\":\"DSR\",\"name\":\"desire\",\"confpath\":\"${HOME#}/.desirecore/desire.conf\",\"rpcport\":9918,\"pubtype\":30,\"p2shtype\":16,\"wiftype\":204,\"txfee\":10000}, {\"coin\":\"MNZ\",\"asset\":\"MNZ\",\"rpcport\":14337},{\"coin\":\"BTCZ\",\"name\":\"bitcoinz\",\"rpcport\":1979,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"MAGA\",\"name\":\"magacoin\",\"rpcport\":5332,\"pubtype\":23,\"p2shtype\":50,\"wiftype\":176,\"txfee\":100000}, {\"coin\":\"BSD\",\"name\":\"bitsend\",\"rpcport\":8800,\"pubtype\":102,\"p2shtype\":5,\"wiftype\":204,\"txfee\":10000}, {\"coin\":\"IOP\",\"name\":\"IoP\",\"rpcport\":8337,\"pubtype\":117,\"p2shtype\":174,\"wiftype\":49,\"txfee\":10000}, {\"coin\":\"BLOCK\",\"name\":\"blocknetdx\",\"rpcport\":41414,\"pubtype\":26,\"p2shtype\":28,\"wiftype\":154,\"txfee\":10000}, {\"coin\":\"CHIPS\", \"name\": \"chips\", \"rpcport\":57776,\"pubtype\":60, \"p2shtype\":85, \"wiftype\":188, \"txfee\":10000}, {\"coin\":\"888\",\"name\":\"octocoin\",\"rpcport\":22888,\"pubtype\":18,\"p2shtype\":5,\"wiftype\":176,\"txfee\":2000000}, {\"coin\":\"ARG\",\"name\":\"argentum\",\"rpcport\":13581,\"pubtype\":23,\"p2shtype\":5,\"wiftype\":151,\"txfee\":50000}, {\"coin\":\"GLT\",\"name\":\"globaltoken\",\"rpcport\":9320,\"pubtype\":38,\"p2shtype\":5,\"wiftype\":166,\"txfee\":10000}, {\"coin\":\"ZER\",\"name\":\"zero\",\"rpcport\":23801,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":1000}, {\"coin\":\"HODLC\",\"name\":\"hodlcoin\",\"rpcport\":11989,\"pubtype\":40,\"p2shtype\":5,\"wiftype\":168,\"txfee\":5000}, {\"coin\":\"UIS\",\"name\":\"unitus\",\"rpcport\":50604,\"pubtype\":68,\"p2shtype\":10,\"wiftype\":132,\"txfee\":2000000}, {\"coin\":\"HUC\",\"name\":\"huntercoin\",\"rpcport\":8399,\"pubtype\":40,\"p2shtype\":13,\"wiftype\":168,\"txfee\":100000}, {\"coin\":\"BDL\",\"name\":\"bitdeal\",\"rpcport\":9332,\"pubtype\":38,\"p2shtype\":5,\"wiftype\":176,\"txfee\":100000}, {\"coin\":\"ARC\",\"name\":\"arcticcoin\",\"confpath\":\"${HOME#}/.arcticcore/arcticcoin.conf\",\"rpcport\":7208,\"pubtype\":23,\"p2shtype\":8,\"wiftype\":176,\"txfee\":10000}, {\"coin\":\"ZCL\",\"name\":\"zclassic\",\"rpcport\":8023,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":1000}, {\"coin\":\"VIA\",\"name\":\"viacoin\",\"rpcport\":5222,\"pubtype\":71,\"p2shtype\":33,\"wiftype\":199,\"txfee\":100000}, {\"coin\":\"ERC\",\"name\":\"europecoin\",\"rpcport\":11989,\"pubtype\":33,\"p2shtype\":5,\"wiftype\":168,\"txfee\":10000},{\"coin\":\"FAIR\",\"name\":\"faircoin\",\"confpath\":\"${HOME#}/.faircoin2/faircoin.conf\",\"rpcport\":40405,\"pubtype\":95,\"p2shtype\":36,\"wiftype\":223,\"txfee\":1000000}, {\"coin\":\"FLO\",\"name\":\"florincoin\",\"rpcport\":7313,\"pubtype\":35,\"p2shtype\":8,\"wiftype\":176,\"txfee\":100000}, {\"coin\":\"SXC\",\"name\":\"sexcoin\",\"rpcport\":9561,\"pubtype\":62,\"p2shtype\":5,\"wiftype\":190,\"txfee\":100000}, {\"coin\":\"CREA\",\"name\":\"creativecoin\",\"rpcport\":17711,\"pubtype\":28,\"p2shtype\":5,\"wiftype\":176,\"txfee\":100000}, {\"coin\":\"TRC\",\"name\":\"terracoin\",\"confpath\":\"${HOME#}/.terracoincore/terracoin.conf\",\"rpcport\":13332,\"pubtype\":0,\"p2shtype\":5,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"BTA\",\"name\":\"bata\",\"rpcport\":5493,\"pubtype\":25,\"p2shtype\":5,\"wiftype\":188,\"txfee\":100000}, {\"coin\":\"SMC\",\"name\":\"smartcoin\",\"rpcport\":58583,\"pubtype\":63,\"p2shtype\":5,\"wiftype\":191,\"txfee\":1000000}, {\"coin\":\"NMC\",\"name\":\"namecoin\",\"rpcport\":8336,\"pubtype\":52,\"p2shtype\":13,\"wiftype\":180,\"txfee\":100000}, {\"coin\":\"NAV\",\"name\":\"navcoin\",\"isPoS\":1,\"confpath\":\"${HOME#}/.navcoin4/navcoin.conf\",\"rpcport\":44444,\"pubtype\":53,\"p2shtype\":85,\"wiftype\":150,\"txfee\":10000}, {\"coin\":\"EMC2\",\"name\":\"einsteinium\",\"rpcport\":41879,\"pubtype\":33,\"p2shtype\":5,\"wiftype\":176,\"txfee\":100000},{\"coin\":\"SYS\",\"name\":\"syscoin\",\"rpcport\":8370,\"pubtype\":0,\"p2shtype\":5,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"I0C\",\"name\":\"i0coin\",\"rpcport\":7332,\"pubtype\":105,\"p2shtype\":5,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"DASH\",\"confpath\":\"${HOME#}/.dashcore/dash.conf\",\"name\":\"dashcore\",\"rpcport\":9998,\"pubtype\":76,\"p2shtype\":16,\"wiftype\":204,\"txfee\":10000}, {\"coin\":\"STRAT\", \"name\": \"stratis\", \"active\":0, \"rpcport\":16174,\"pubtype\":63, \"p2shtype\":125, \"wiftype\":191, \"txfee\":10000}, {\"confpath\":\"${HOME#}/.muecore/mue.conf\",\"coin\":\"MUE\",\"name\":\"muecore\",\"rpcport\":29683,\"pubtype\":16,\"p2shtype\":76,\"wiftype\":126,\"txfee\":10000}, {\"coin\":\"MONA\",\"name\":\"monacoin\",\"rpcport\":9402,\"pubtype\":50,\"p2shtype\":5,\"wiftype\":176,\"txfee\":100000},{\"coin\":\"XMY\",\"name\":\"myriadcoin\",\"rpcport\":10889,\"pubtype\":50,\"p2shtype\":9,\"wiftype\":178,\"txfee\":5000}, {\"coin\":\"MAC\",\"name\":\"machinecoin\",\"rpcport\":40332,\"pubtype\":50,\"p2shtype\":5,\"wiftype\":178,\"txfee\":100000}, {\"coin\":\"BTX\",\"name\":\"bitcore\",\"rpcport\":8556,\"pubtype\":0,\"p2shtype\":5,\"wiftype\":128,\"txfee\":50000}, {\"coin\":\"XRE\",\"name\":\"revolvercoin\",\"rpcport\":8775,\"pubtype\":0,\"p2shtype\":5,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"LBC\",\"name\":\"lbrycrd\",\"rpcport\":9245,\"pubtype\":85,\"p2shtype\":122,\"wiftype\":28,\"txfee\":10000}, {\"coin\":\"SIB\",\"name\":\"sibcoin\",\"rpcport\":1944,\"pubtype\":63,\"p2shtype\":40,\"wiftype\":128,\"txfee\":10000}, {\"coin\":\"VTC\", \"name\":\"vertcoin\", \"rpcport\":5888, \"pubtype\":71, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000 }, {\"coin\":\"REVS\",\"active\":0, \"asset\":\"REVS\",\"rpcport\":10196}, {\"coin\":\"JUMBLR\",\"active\":0, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\",\"name\":\"dogecoin\",\"rpcport\":22555,\"pubtype\":30,\"p2shtype\":22,\"wiftype\":158,\"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":1000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\",\"name\":\"digibyte\",\"rpcport\":14022,\"pubtype\":30,\"p2shtype\":5,\"wiftype\":128,\"txfee\":100000}, {\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9,\"rpcport\":8332, \"wiftype\":224, \"txfee\":10000}, {\"coin\":\"GAME\", \"rpcport\":40001, \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, {\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341}, {\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167}, {\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068}, {\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890}, {\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250}, {\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516}, {\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431}, {\"coin\":\"MSHARK\",\"asset\":\"MSHARK\",\"rpcport\":8846}, {\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964}, {\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386}, {\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276}, {\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299}, {\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116}, {\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455}]" -#, {\"coin\":\"AUD\",\"asset\":\"AUD\",\"rpcport\":8045}, {\"coin\":\"BGN\",\"asset\":\"BGN\",\"rpcport\":9110}, {\"coin\":\"CAD\",\"asset\":\"CAD\",\"rpcport\":8720}, {\"coin\":\"CHF\",\"asset\":\"CHF\",\"rpcport\":15312}, {\"coin\":\"CNY\",\"asset\":\"CNY\",\"rpcport\":10384}, {\"coin\":\"CZK\",\"asset\":\"CZK\",\"rpcport\":9482}, {\"coin\":\"DKK\",\"asset\":\"DKK\",\"rpcport\":13830}, {\"coin\":\"EUR\",\"asset\":\"EUR\",\"rpcport\":8065}, {\"coin\":\"GBP\",\"asset\":\"GBP\",\"rpcport\":11505}, {\"coin\":\"HKD\",\"asset\":\"HKD\",\"rpcport\":15409}, {\"coin\":\"HRK\",\"asset\":\"HRK\",\"rpcport\":12617}, {\"coin\":\"HUF\",\"asset\":\"HUF\",\"rpcport\":13699}, {\"coin\":\"IDR\",\"asset\":\"IDR\",\"rpcport\":14459}, {\"coin\":\"ILS\",\"asset\":\"ILS\",\"rpcport\":14638}, {\"coin\":\"INR\",\"asset\":\"INR\",\"rpcport\":10536}, {\"coin\":\"JPY\",\"asset\":\"JPY\",\"rpcport\":13145}, {\"coin\":\"KRW\",\"asset\":\"KRW\",\"rpcport\":14020}, {\"coin\":\"MXN\",\"asset\":\"MXN\",\"rpcport\":13970}, {\"coin\":\"MYR\",\"asset\":\"MYR\",\"rpcport\":10688}, {\"coin\":\"NOK\",\"asset\":\"NOK\",\"rpcport\":11588}, {\"coin\":\"NZD\",\"asset\":\"NZD\",\"rpcport\":10915}, {\"coin\":\"PHP\",\"asset\":\"PHP\",\"rpcport\":11181}, {\"coin\":\"PLN\",\"asset\":\"PLN\",\"rpcport\":13493}, {\"coin\":\"BRL\",\"asset\":\"BRL\",\"rpcport\":9914}, {\"coin\":\"RON\",\"asset\":\"RON\",\"rpcport\":8675}, {\"coin\":\"RUB\",\"asset\":\"RUB\",\"rpcport\":8199}, {\"coin\":\"SEK\",\"asset\":\"SEK\",\"rpcport\":11447}, {\"coin\":\"SGD\",\"asset\":\"SGD\",\"rpcport\":14475}, {\"coin\":\"THB\",\"asset\":\"THB\",\"rpcport\":11847}, {\"coin\":\"TRY\",\"asset\":\"TRY\",\"rpcport\":13924}, {\"coin\":\"USD\",\"asset\":\"USD\",\"rpcport\":13967}, {\"coin\":\"ZAR\",\"asset\":\"ZAR\",\"rpcport\":15160}]" -#{\"coin\":\"PIVX\",\"name\":\"pivx\",\"rpcport\":51473,\"pubtype\":30,\"p2shtype\":13,\"wiftype\":212,\"txfee\":10000}, diff --git a/mm2src/common/Cargo.toml b/mm2src/common/Cargo.toml index 1a54578cea..f8c49db874 100644 --- a/mm2src/common/Cargo.toml +++ b/mm2src/common/Cargo.toml @@ -59,8 +59,8 @@ parking_lot_core = { version = "0.6", features = ["nightly"] } primitives = { git = "https://github.com/artemii235/parity-bitcoin.git" } rand = { version = "0.7", features = ["std", "small_rng"] } regex = "1" +rusqlite = { version = "0.24.2", features = ["bundled"] } serde = "1" -serde_bencode = "0.2" serde_bytes = "0.11" serde_derive = "1" serde_json = { version = "1.0", features = ["raw_value", "preserve_order"] } diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index 88efdca37c..4656038349 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -104,8 +104,6 @@ use http::{HeaderMap, Request, Response, StatusCode}; use parking_lot::{Mutex as PaMutex, MutexGuard as PaMutexGuard}; use rand::{rngs::SmallRng, SeedableRng}; use serde::{de, ser}; -#[cfg(not(feature = "native"))] -use serde_bencode::de::from_bytes as bdecode; use serde_bytes::ByteBuf; use serde_json::{self as json, Value as Json}; use std::collections::HashMap; @@ -131,6 +129,7 @@ use uuid::Uuid; #[cfg(feature = "w-bindgen")] use wasm_bindgen::prelude::*; pub use num_bigint::BigInt; +pub use rusqlite; pub const MM_DATETIME: &str = env!("MM_DATETIME"); pub const MM_VERSION: &str = env!("MM_VERSION"); diff --git a/mm2src/common/mm_ctx.rs b/mm2src/common/mm_ctx.rs index 16a7724cae..b4e663ea92 100644 --- a/mm2src/common/mm_ctx.rs +++ b/mm2src/common/mm_ctx.rs @@ -1,11 +1,9 @@ -use bytes::Bytes; use gstuff::Constructible; #[cfg(not(feature = "native"))] use http::Response; -use keys::{DisplayLayout, KeyPair, Private}; +use keys::KeyPair; use primitives::hash::H160; use rand::Rng; -use serde_bencode::de::from_bytes as bdecode; -use serde_bencode::ser::to_bytes as bencode; +use rusqlite::Connection; use serde_bytes::ByteBuf; use serde_json::{self as json, Value as Json}; use std::any::Any; @@ -69,34 +67,22 @@ pub struct MmCtx { pub ffi_handle: Constructible, /// Callbacks to invoke from `fn stop`. pub stop_listeners: Mutex>, - /// The context belonging to the `portfolio` crate: `PortfolioContext`. - pub portfolio_ctx: Mutex>>, /// The context belonging to the `ordermatch` mod: `OrdermatchContext`. pub ordermatch_ctx: Mutex>>, - /// The context belonging to the `peers` crate: `PeersContext`. - pub peers_ctx: Mutex>>, pub p2p_ctx: Mutex>>, pub peer_id: Constructible, - /// The context belonging to the `http_fallback` mod: `HttpFallbackContext`. - pub http_fallback_ctx: Mutex>>, /// The context belonging to the `coins` crate: `CoinsContext`. pub coins_ctx: Mutex>>, - /// The context belonging to the `prices` mod: `PricesContext`. - pub prices_ctx: Mutex>>, /// RIPEMD160(SHA256(x)) where x is secp256k1 pubkey derived from passphrase. - /// Replacement of `lp::G.LP_myrmd160`. pub rmd160: Constructible, - /// Seed node IPs, initialized in `fn lp_initpeers`. - pub seeds: Mutex>, /// secp256k1 key pair derived from passphrase. /// cf. `key_pair_from_seed`. - /// Replacement of `lp::G.LP_privkey`. pub secp256k1_key_pair: Constructible, /// Coins that should be enabled to kick start the interrupted swaps and orders. pub coins_needed_for_kick_start: Mutex>, /// The context belonging to the `lp_swap` mod: `SwapsContext`. pub swaps_ctx: Mutex>>, - pub gossipsub_ctx: Mutex>>, + pub sqlite_connection: Constructible, } impl MmCtx { pub fn with_log_state(log: LogState) -> MmCtx { @@ -109,20 +95,15 @@ impl MmCtx { stop: Constructible::default(), ffi_handle: Constructible::default(), stop_listeners: Mutex::new(Vec::new()), - portfolio_ctx: Mutex::new(None), ordermatch_ctx: Mutex::new(None), - peers_ctx: Mutex::new(None), p2p_ctx: Mutex::new(None), peer_id: Constructible::default(), - http_fallback_ctx: Mutex::new(None), coins_ctx: Mutex::new(None), - prices_ctx: Mutex::new(None), rmd160: Constructible::default(), - seeds: Mutex::new(Vec::new()), secp256k1_key_pair: Constructible::default(), coins_needed_for_kick_start: Mutex::new(HashSet::new()), swaps_ctx: Mutex::new(None), - gossipsub_ctx: Mutex::new(None), + sqlite_connection: Constructible::default(), } } @@ -237,6 +218,19 @@ impl MmCtx { } pub fn gui(&self) -> Option<&str> { self.conf["gui"].as_str() } + + pub fn init_sqlite_connection(&self) -> Result<(), String> { + let sqlite_file_path = self.dbdir().join("MM2.db"); + log::debug!("Trying to open SQLite database file {}", sqlite_file_path.display()); + let connection = try_s!(Connection::open(sqlite_file_path)); + try_s!(self.sqlite_connection.pin(connection)); + Ok(()) + } + + pub fn sqlite_connection(&self) -> &Connection { + self.sqlite_connection + .or(&|| panic!("sqlite_connection is not initialized")) + } } impl Default for MmCtx { fn default() -> Self { Self::with_log_state(LogState::in_memory()) } @@ -430,68 +424,6 @@ impl MmArc { } } -/// Receives a subset of a portable context in order to recreate a native copy of it. -/// Can be invoked with the same context multiple times, synchronizing some of the fields. -/// As of now we're expecting a one-to-one pairing between the portable and the native versions of MM -/// so the uniqueness of the `ffi_handle` is not a concern yet. -#[cfg(feature = "native")] -pub async fn ctx2helpers(main_ctx: MmArc, req: Bytes) -> Result, String> { - let ctxʷ: PortableCtx = try_s!(bdecode(&req)); - let private = try_s!(Private::from_layout(&ctxʷ.secp256k1_key_pair[..])); - let main_key = try_s!(main_ctx.secp256k1_key_pair.as_option().ok_or("No key")); - - if *main_key.private() == private { - // We have a match with the primary native context, the one configured on the command line. - let res = try_s!(bencode(&NativeCtx { - ffi_handle: try_s!(main_ctx.ffi_handle()) - })); - return Ok(res); - } - - if let Some(ffi_handle) = ctxʷ.ffi_handle { - if let Ok(ctx) = MmArc::from_ffi_handle(ffi_handle) { - let key = try_s!(ctx.secp256k1_key_pair.as_option().ok_or("No key")); - if *key.private() != private { - return ERR!("key mismatch"); - } - let res = try_s!(bencode(&NativeCtx { - ffi_handle: try_s!(ctx.ffi_handle()) - })); - return Ok(res); - } - } - - // Create a native copy of the portable context. - - let pair: Option = if ctxʷ.secp256k1_key_pair.is_empty() { - None - } else { - let private = try_s!(Private::from_layout(&ctxʷ.secp256k1_key_pair[..])); - Some(try_s!(KeyPair::from_private(private))) - }; - - let ctx = MmCtx { - conf: try_s!(json::from_str(&ctxʷ.conf)), - secp256k1_key_pair: pair.into(), - ffi_handle: ctxʷ.ffi_handle.into(), - ..MmCtx::with_log_state(LogState::in_memory()) - }; - let ctx = MmArc(Arc::new(ctx)); - if let Some(ffi_handle) = ctxʷ.ffi_handle { - let mut ctx_ffi = try_s!(MM_CTX_FFI.lock()); - if ctx_ffi.contains_key(&ffi_handle) { - return ERR!("ID race"); - } - ctx_ffi.insert(ffi_handle, ctx.weak()); - } - let res = try_s!(bencode(&NativeCtx { - ffi_handle: try_s!(ctx.ffi_handle()) - })); - Arc::into_raw(ctx.0); // Leak. - - Ok(res) -} - /// Helps getting a crate context from a corresponding `MmCtx` field. /// /// * `ctx_field` - A dedicated crate context field in `MmCtx`, such as the `MmCtx::portfolio_ctx`. diff --git a/mm2src/database.rs b/mm2src/database.rs new file mode 100644 index 0000000000..293c50d7ba --- /dev/null +++ b/mm2src/database.rs @@ -0,0 +1,82 @@ +/// The module responsible to work with SQLite database + +#[path = "database/my_swaps.rs"] +pub mod my_swaps; +use crate::CREATE_MY_SWAPS_TABLE; +use common::{log::{debug, error, info}, + mm_ctx::MmArc, + rusqlite::{Connection, Result as SqlResult, NO_PARAMS}}; + +use my_swaps::fill_my_swaps_from_json_statements; + +const SELECT_MIGRATION: &str = "SELECT * FROM migration ORDER BY current_migration DESC LIMIT 1;"; + +fn get_current_migration(conn: &Connection) -> SqlResult { + conn.query_row(SELECT_MIGRATION, NO_PARAMS, |row| row.get(0)) +} + +pub fn init_and_migrate_db(ctx: &MmArc, conn: &Connection) -> SqlResult<()> { + info!("Checking the current SQLite migration"); + match get_current_migration(conn) { + Ok(current_migration) => { + if current_migration >= 1 { + info!( + "Current migration is {}, skipping the init, trying to migrate", + current_migration + ); + migrate_sqlite_database(ctx, conn, current_migration)?; + return Ok(()); + } + }, + Err(e) => { + debug!("Error {} on getting current migration. The database is either empty or corrupted, trying to clean it first", e); + if let Err(e) = conn.execute_batch( + "DROP TABLE migration; + DROP TABLE my_swaps;", + ) { + error!("Error {} on SQLite database cleanup", e); + } + }, + }; + + info!("Trying to initialize the SQLite database"); + + let init_batch = concat!( + "BEGIN; + CREATE TABLE IF NOT EXISTS migration (current_migration INTEGER NOT_NULL UNIQUE); + INSERT INTO migration (current_migration) VALUES (1);", + CREATE_MY_SWAPS_TABLE!(), + "COMMIT;" + ); + conn.execute_batch(init_batch)?; + migrate_sqlite_database(ctx, conn, 1)?; + info!("SQLite database initialization is successful"); + Ok(()) +} + +fn migration_1(ctx: &MmArc) -> Vec<(&'static str, Vec)> { fill_my_swaps_from_json_statements(ctx) } + +fn statements_for_migration(ctx: &MmArc, current_migration: i64) -> Option)>> { + match current_migration { + 1 => Some(migration_1(ctx)), + _ => None, + } +} + +pub fn migrate_sqlite_database(ctx: &MmArc, conn: &Connection, mut current_migration: i64) -> SqlResult<()> { + info!("migrate_sqlite_database, current migration {}", current_migration); + let transaction = conn.unchecked_transaction()?; + while let Some(statements_with_params) = statements_for_migration(ctx, current_migration) { + for (statement, params) in statements_with_params { + debug!("Executing SQL statement {:?} with params {:?}", statement, params); + transaction.execute(&statement, params)?; + } + current_migration += 1; + transaction.execute("INSERT INTO migration (current_migration) VALUES (?1);", &[ + current_migration, + ])?; + } + transaction.commit()?; + info!("migrate_sqlite_database complete, migrated to {}", current_migration); + Ok(()) +} diff --git a/mm2src/database/my_swaps.rs b/mm2src/database/my_swaps.rs new file mode 100644 index 0000000000..25b09d75ad --- /dev/null +++ b/mm2src/database/my_swaps.rs @@ -0,0 +1,223 @@ +/// This module contains code to work with my_swaps table in MM2 SQLite DB +use crate::mm2::lp_swap::{my_swaps_dir, MyRecentSwapsReq, SavedSwap}; +use common::{log::{debug, error}, + mm_ctx::MmArc, + read_dir, + rusqlite::{Connection, Error as SqlError, Result as SqlResult, ToSql}, + slurp}; +use serde_json::{self as json}; +use sql_builder::SqlBuilder; +use std::convert::TryInto; +use uuid::Uuid; + +const MY_SWAPS_TABLE: &str = "my_swaps"; + +// Using a macro because static variable can't be passed to concat! +// https://stackoverflow.com/a/39024422 +#[macro_export] +macro_rules! CREATE_MY_SWAPS_TABLE { + () => { + "CREATE TABLE IF NOT EXISTS my_swaps ( + id INTEGER NOT NULL PRIMARY KEY, + my_coin VARCHAR(255) NOT NULL, + other_coin VARCHAR(255) NOT NULL, + uuid VARCHAR(255) NOT NULL UNIQUE, + started_at INTEGER NOT NULL + );" + }; +} +const INSERT_MY_SWAP: &str = "INSERT INTO my_swaps (my_coin, other_coin, uuid, started_at) VALUES (?1, ?2, ?3, ?4)"; + +pub fn insert_new_swap(ctx: &MmArc, my_coin: &str, other_coin: &str, uuid: &str, started_at: &str) -> SqlResult<()> { + debug!("Inserting new swap {} to the SQLite database", uuid); + let conn = ctx + .sqlite_connection + .as_option() + .expect("SQLite connection is not initialized"); + let params = [my_coin, other_coin, uuid, started_at]; + conn.execute(INSERT_MY_SWAP, ¶ms).map(|_| ()) +} + +/// Returns SQL statements to initially fill my_swaps table using existing DB with JSON files +pub fn fill_my_swaps_from_json_statements(ctx: &MmArc) -> Vec<(&'static str, Vec)> { + let swap_files = read_dir(&my_swaps_dir(&ctx)).expect("Reading swaps dir should not fail at this point"); + let mut result = vec![]; + for (_, file) in swap_files { + let content = slurp(&file).expect("slurp should not fail at this point"); + match json::from_slice::(&content) { + Ok(swap) => { + if let Some(sql_with_params) = insert_saved_swap_sql(swap) { + result.push(sql_with_params); + } + }, + Err(e) => error!( + "Error {} on file {} content {:?} deserialization to SavedSwap", + e, + file.display(), + content + ), + } + } + result +} + +fn insert_saved_swap_sql(swap: SavedSwap) -> Option<(&'static str, Vec)> { + let swap_info = match swap.get_my_info() { + Some(s) => s, + // get_my_info returning None means that swap did not even start - so we can keep it away from indexing. + None => return None, + }; + let params = vec![ + swap_info.my_coin, + swap_info.other_coin, + swap.uuid().to_string(), + swap_info.started_at.to_string(), + ]; + Some((INSERT_MY_SWAP, params)) +} + +#[derive(Debug)] +pub enum SelectRecentSwapsUuidsErr { + Sql(SqlError), + Parse(uuid::parser::ParseError), +} + +impl std::fmt::Display for SelectRecentSwapsUuidsErr { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{:?}", self) } +} + +impl From for SelectRecentSwapsUuidsErr { + fn from(err: SqlError) -> Self { SelectRecentSwapsUuidsErr::Sql(err) } +} + +impl From for SelectRecentSwapsUuidsErr { + fn from(err: uuid::parser::ParseError) -> Self { SelectRecentSwapsUuidsErr::Parse(err) } +} + +#[derive(Debug, Default)] +pub struct RecentSwapsSelectSqlResult { + /// UUIDs of swaps matching the query + pub uuids: Vec, + /// Total count of swaps matching the query + pub total_count: usize, + /// The number of skipped UUIDs + pub skipped: usize, +} + +/// Calculates the offset to skip records by uuid of swap. +/// Expects `query_builder` to have where clauses applied *before* calling this fn. +fn offset_by_uuid( + conn: &Connection, + query_builder: &SqlBuilder, + params: &[(&str, String)], + uuid: &Uuid, +) -> SqlResult { + // building following query to determine offset by from_uuid + // select row from ( + // select uuid, ROW_NUMBER() OVER (ORDER BY started_at DESC) AS row + // from my_swaps + // where ... filtering options here ... + // ) where uuid = "from_uuid"; + let subquery = query_builder + .clone() + .field("ROW_NUMBER() OVER (ORDER BY started_at DESC) AS row") + .field("uuid") + .subquery() + .expect("SQL query builder should never fail here"); + + let external_query = SqlBuilder::select_from(subquery) + .field("row") + .and_where("uuid = :uuid") + .sql() + .expect("SQL query builder should never fail here"); + + let mut params_for_offset = params.to_owned(); + params_for_offset.push((":uuid", uuid.to_string())); + let params_as_trait: Vec<_> = params_for_offset + .iter() + .map(|(key, value)| (*key, value as &dyn ToSql)) + .collect(); + debug!( + "Trying to execute SQL query {} with params {:?}", + external_query, params_for_offset + ); + let mut stmt = conn.prepare(&external_query)?; + let offset: isize = stmt.query_row_named(params_as_trait.as_slice(), |row| row.get(0))?; + Ok(offset.try_into().expect("row index should be always above zero")) +} + +/// Adds where clauses determined by MyRecentSwapsReq +fn apply_my_recent_swaps_filter(builder: &mut SqlBuilder, params: &mut Vec<(&str, String)>, req: &MyRecentSwapsReq) { + if let Some(my_coin) = &req.my_coin { + builder.and_where("my_coin = :my_coin"); + params.push((":my_coin", my_coin.clone())); + } + + if let Some(other_coin) = &req.other_coin { + builder.and_where("other_coin = :other_coin"); + params.push((":other_coin", other_coin.clone())); + } + + if let Some(from_timestamp) = &req.from_timestamp { + builder.and_where("started_at >= :from_timestamp"); + params.push((":from_timestamp", from_timestamp.to_string())); + } + + if let Some(to_timestamp) = &req.to_timestamp { + builder.and_where("started_at < :to_timestamp"); + params.push((":to_timestamp", to_timestamp.to_string())); + } +} + +pub fn select_uuids_for_recent_swaps_req( + conn: &Connection, + req: &MyRecentSwapsReq, +) -> SqlResult { + let mut query_builder = SqlBuilder::select_from(MY_SWAPS_TABLE); + let mut params = vec![]; + apply_my_recent_swaps_filter(&mut query_builder, &mut params, req); + + // count total records matching the filter + let mut count_builder = query_builder.clone(); + count_builder.count("id"); + + let count_query = count_builder.sql().expect("SQL query builder should never fail here"); + debug!("Trying to execute SQL query {} with params {:?}", count_query, params); + + let params_as_trait: Vec<_> = params.iter().map(|(key, value)| (*key, value as &dyn ToSql)).collect(); + let total_count: isize = conn.query_row_named(&count_query, params_as_trait.as_slice(), |row| row.get(0))?; + let total_count = total_count.try_into().expect("COUNT should always be >= 0"); + if total_count == 0 { + return Ok(RecentSwapsSelectSqlResult::default()); + } + + // calculate offset, page_number is ignored if from_uuid is set + let skipped = match req.from_uuid { + Some(uuid) => offset_by_uuid(conn, &query_builder, ¶ms, &uuid)?, + None => match req.page_number { + Some(page) => (page.get() - 1) * req.limit, + None => 0, + }, + }; + + // query the uuids finally + query_builder.field("uuid"); + query_builder.order_desc("started_at"); + query_builder.limit(req.limit); + query_builder.offset(skipped); + + let uuids_query = query_builder.sql().expect("SQL query builder should never fail here"); + debug!("Trying to execute SQL query {} with params {:?}", uuids_query, params); + let mut stmt = conn.prepare(&uuids_query)?; + let uuids = stmt + .query_map_named(params_as_trait.as_slice(), |row| row.get(0))? + .collect::>>()?; + let uuids: SqlResult, _> = uuids.into_iter().map(|uuid| uuid.parse()).collect(); + let uuids = uuids?; + + Ok(RecentSwapsSelectSqlResult { + uuids, + total_count, + skipped, + }) +} diff --git a/mm2src/lp_native_dex.rs b/mm2src/lp_native_dex.rs index 1a6485cc64..b4a49555ac 100644 --- a/mm2src/lp_native_dex.rs +++ b/mm2src/lp_native_dex.rs @@ -36,6 +36,7 @@ use crate::common::executor::{spawn, spawn_boxed, Timer}; use crate::common::mm_ctx::{MmArc, MmCtx}; use crate::common::privkey::key_pair_from_seed; use crate::common::{slurp_url, MM_DATETIME, MM_VERSION}; +use crate::mm2::database::init_and_migrate_db; use crate::mm2::lp_network::{p2p_event_process_loop, P2PContext}; use crate::mm2::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, lp_ordermatch_loop, orders_kick_start, BalanceUpdateOrdermatchHandler}; @@ -236,8 +237,7 @@ fn migration_1(_ctx: &MmArc) -> Result<(), String> { Ok(()) } /// AG: If possible, I think we should avoid calling this function on a working MM, using it for initialization only, /// in order to avoid the possibility of invalid state. /// AP: Totally agree, moreover maybe we even `must` deny calling this on a working MM as it's being refactored -#[allow(unused_unsafe)] -pub unsafe fn lp_passphrase_init(ctx: &MmArc) -> Result<(), String> { +pub fn lp_passphrase_init(ctx: &MmArc) -> Result<(), String> { let passphrase = ctx.conf["passphrase"].as_str(); let passphrase = match passphrase { None | Some("") => return ERR!("jeezy says we cant use the nullstring as passphrase and I agree"), @@ -328,9 +328,11 @@ fn seed_to_ipv4_string(seed: &str) -> Option { /// * `ctx_cb` - callback used to share the `MmCtx` ID with the call site. pub async fn lp_init(mypubport: u16, ctx: MmArc) -> Result<(), String> { log! ({"lp_init] version: {} DT {}", MM_VERSION, MM_DATETIME}); - unsafe { try_s!(lp_passphrase_init(&ctx)) } + try_s!(lp_passphrase_init(&ctx)); try_s!(fix_directories(&ctx)); + try_s!(ctx.init_sqlite_connection()); + try_s!(init_and_migrate_db(&ctx, ctx.sqlite_connection())); #[cfg(feature = "native")] { try_s!(migrate_db(&ctx)); @@ -450,8 +452,6 @@ pub async fn lp_init(mypubport: u16, ctx: MmArc) -> Result<(), String> { } }; - #[cfg(not(feature = "native"))] - try_s!(ctx.send_to_helpers().await); const NETID_7777_SEEDNODES: &[&str] = &["seed1.kmd.io:0", "seed2.kmd.io:0", "seed3.kmd.io:0"]; let seednodes: Option> = try_s!(json::from_value(ctx.conf["seednodes"].clone())); let seednodes = match seednodes { diff --git a/mm2src/lp_ordermatch.rs b/mm2src/lp_ordermatch.rs index cd1f02c1a3..6e5fcadaca 100644 --- a/mm2src/lp_ordermatch.rs +++ b/mm2src/lp_ordermatch.rs @@ -26,6 +26,7 @@ use blake2::VarBlake2b; use coins::utxo::{compressed_pub_key_from_priv_raw, ChecksumType}; use coins::{lp_coinfindᵃ, BalanceTradeFeeUpdatedHandler, MmCoinEnum, TradeFee}; use common::executor::{spawn, Timer}; +use common::log::error; use common::mm_ctx::{from_ctx, MmArc, MmWeak}; use common::mm_number::{Fraction, MmNumber}; use common::{bits256, json_dir_entries, log, new_uuid, now_ms, remove_file, write}; @@ -53,7 +54,8 @@ use std::sync::Arc; use trie_db::NodeCodec as NodeCodecT; use uuid::Uuid; -use crate::mm2::{lp_network::{broadcast_p2p_msg, request_any_relay, request_one_peer, subscribe_to_topic, P2PRequest}, +use crate::mm2::{database::my_swaps::insert_new_swap, + lp_network::{broadcast_p2p_msg, request_any_relay, request_one_peer, subscribe_to_topic, P2PRequest}, lp_swap::{calc_max_maker_vol, check_balance_for_maker_swap, check_balance_for_taker_swap, is_pubkey_banned, lp_atomic_locktime, run_maker_swap, run_taker_swap, AtomicLocktimeVersion, MakerSwap, RunMakerSwapInput, RunTakerSwapInput, @@ -2091,6 +2093,17 @@ fn lp_connect_start_bob(ctx: MmArc, maker_match: MakerMatch, maker_order: MakerO taker_coin.ticker(), uuid ); + + let now = now_ms() / 1000; + if let Err(e) = insert_new_swap( + &ctx, + maker_coin.ticker(), + taker_coin.ticker(), + &uuid.to_string(), + &now.to_string(), + ) { + error!("Error {} on new swap insertion", e); + } let maker_swap = MakerSwap::new( ctx.clone(), alice, @@ -2167,6 +2180,16 @@ fn lp_connected_alice(ctx: MmArc, taker_request: TakerRequest, taker_match: Take taker_coin.ticker(), uuid ); + let now = now_ms() / 1000; + if let Err(e) = insert_new_swap( + &ctx, + taker_coin.ticker(), + maker_coin.ticker(), + &uuid.to_string(), + &now.to_string(), + ) { + error!("Error {} on new swap insertion", e); + } let taker_swap = TakerSwap::new( ctx.clone(), maker, diff --git a/mm2src/lp_swap.rs b/mm2src/lp_swap.rs index 653cd87823..1fef766325 100644 --- a/mm2src/lp_swap.rs +++ b/mm2src/lp_swap.rs @@ -56,12 +56,14 @@ // #![cfg_attr(not(feature = "native"), allow(dead_code))] -use crate::mm2::lp_network::broadcast_p2p_msg; +use crate::mm2::{database::my_swaps::{insert_new_swap, select_uuids_for_recent_swaps_req}, + lp_network::broadcast_p2p_msg}; use async_std::sync as async_std_sync; use bigdecimal::BigDecimal; use coins::{lp_coinfind, TradeFee, TransactionEnum}; use common::{bits256, block_on, calc_total_pages, executor::{spawn, Timer}, + log::error, mm_ctx::{from_ctx, MmArc}, mm_number::MmNumber, now_ms, read_dir, rpc_response, slurp, write, HyRes}; @@ -177,22 +179,6 @@ pub fn process_msg(ctx: MmArc, topic: &str, msg: &[u8]) { pub fn swap_topic(uuid: &Uuid) -> String { pub_sub_topic(SWAP_PREFIX, &uuid.to_string()) } -/* -// NB: Using a macro instead of a function in order to preserve the line numbers in the log. -macro_rules! send { - ($ctx: expr, $subj: expr, $topic: expr, $payload: expr) => {{ - // Checksum here helps us visually verify the logistics between the Maker and Taker logs. - // let crc = crc32::checksum_ieee (&$payload); - // log!("Sending '" ($subj) "' (" ($payload.len()) " bytes, crc " (crc) ")"); - let msg = SwapMsg { - subject: $subj, - data: $payload, - }; - $ctx.broadcast_p2p_msg($topic, serialize(&msg).take()); - }}; -} -*/ - async fn recv_swap_msg( ctx: MmArc, mut getter: impl FnMut(&mut SwapMsgStore) -> Option, @@ -218,45 +204,6 @@ async fn recv_swap_msg( } } -/* -// NB: `$validator` is where we should put the decryption and verification in, -// in order for the bogus DHT input to disrupt communication less. -macro_rules! recv_ { - ($swap: expr, $subj: expr, $timeout_sec: expr, $ec: expr, $validator: expr) => {{ - let recv_subject = $subj$swap.uuid; - let recv_f = peers::recv ($swap.ctx.clone(), recv_subjectᵇ, fallback, $validator); - - let started = now_float(); - let timeout = (BASIC_COMM_TIMEOUT + $timeout_sec) as f64; - let timeoutᶠ = Timer::till (started + timeout); - (async move { - let r = match futures::future::select (Box::pin (recv_f), timeoutᶠ) .await { - Either::Left ((r, _)) => r, - Either::Right (_) => return ERR! ("timeout ({:.1} > {:.1})", now_float() - started, timeout) - }; - if let Ok (ref payload) = r { - // Checksum here helps us visually verify the logistics between the Maker and Taker logs. - let crc = crc32::checksum_ieee (&payload); - log! ("Received '" (recv_subject) "' (" (payload.len()) " bytes, crc " (crc) ")"); - } - r - }).await - }} -} - -macro_rules! recv { - ($selff: ident, $subj: expr, $timeout_sec: expr, $ec: expr, $validator: expr) => { - recv_!($selff, $subj, $timeout_sec, $ec, $validator) - }; - // Use this form if there's a sending future to terminate upon receiving the answer. - ($selff: ident, $sending_f: ident, $subj: expr, $timeout_sec: expr, $ec: expr, $validator: expr) => {{ - let payload = recv_!($selff, $subj, $timeout_sec, $ec, $validator); - drop($sending_f); - payload - }}; -} -*/ - #[path = "lp_swap/maker_swap.rs"] mod maker_swap; #[path = "lp_swap/taker_swap.rs"] mod taker_swap; @@ -580,7 +527,7 @@ pub struct TransactionIdentifier { tx_hash: BytesJson, } -fn my_swaps_dir(ctx: &MmArc) -> PathBuf { ctx.dbdir().join("SWAPS").join("MY") } +pub fn my_swaps_dir(ctx: &MmArc) -> PathBuf { ctx.dbdir().join("SWAPS").join("MY") } pub fn my_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { my_swaps_dir(ctx).join(format!("{}.json", uuid)) } @@ -601,7 +548,7 @@ fn save_stats_swap(ctx: &MmArc, swap: &SavedSwap) -> Result<(), String> { #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type")] -enum SavedSwap { +pub enum SavedSwap { Maker(MakerSavedSwap), Taker(TakerSavedSwap), } @@ -610,11 +557,11 @@ enum SavedSwap { /// They won't have to parse the events themselves handling possible errors, index out of bounds etc. #[derive(Debug, Serialize, Deserialize)] pub struct MySwapInfo { - my_coin: String, - other_coin: String, + pub my_coin: String, + pub other_coin: String, my_amount: BigDecimal, other_amount: BigDecimal, - started_at: u64, + pub started_at: u64, } impl SavedSwap { @@ -625,7 +572,7 @@ impl SavedSwap { } } - fn uuid(&self) -> &Uuid { + pub fn uuid(&self) -> &Uuid { match self { SavedSwap::Maker(swap) => &swap.uuid, SavedSwap::Taker(swap) => &swap.uuid, @@ -646,7 +593,7 @@ impl SavedSwap { } } - fn get_my_info(&self) -> Option { + pub fn get_my_info(&self) -> Option { match self { SavedSwap::Maker(swap) => swap.get_my_info(), SavedSwap::Taker(swap) => swap.get_my_info(), @@ -826,63 +773,59 @@ pub fn save_stats_swap_status(ctx: &MmArc, data: Json) { fn ten() -> usize { 10 } #[derive(Debug, Deserialize)] -struct MyRecentSwapsReq { +pub struct MyRecentSwapsReq { #[serde(default = "ten")] - limit: usize, - from_uuid: Option, - page_number: Option, + pub limit: usize, + pub from_uuid: Option, + pub page_number: Option, + pub my_coin: Option, + pub other_coin: Option, + pub from_timestamp: Option, + pub to_timestamp: Option, } /// Returns the data of recent swaps of `my` node. Returns no more than `limit` records (default: 10). /// Skips the first `skip` records (default: 0). pub fn my_recent_swaps(ctx: MmArc, req: Json) -> HyRes { let req: MyRecentSwapsReq = try_h!(json::from_value(req)); - let mut entries: Vec<(u64, PathBuf)> = try_h!(read_dir(&my_swaps_dir(&ctx))); - // sort by m_time in descending order - entries.sort_by(|(a, _), (b, _)| b.cmp(&a)); - - let skip = match &req.from_uuid { - Some(uuid) => { - let swap_path = my_swap_file_path(&ctx, uuid); - try_h!(entries - .iter() - .position(|(_, path)| *path == swap_path) - .ok_or(format!("from_uuid {} swap is not found", uuid))) - + 1 - }, - None => match req.page_number { - Some(page_n) => (page_n.get() - 1) * req.limit, - None => 0, - }, - }; + let db_result = try_h!(select_uuids_for_recent_swaps_req(ctx.sqlite_connection(), &req)); - // iterate over file entries trying to parse the file contents and add to result vector - let swaps: Vec = entries + // iterate over uuids trying to parse the corresponding files content and add to result vector + let swaps: Vec = db_result + .uuids .iter() - .skip(skip) - .take(req.limit) - .map( - |(_, path)| match json::from_slice::(&unwrap!(slurp(&path))) { + .map(|uuid| { + let path = my_swap_file_path(&ctx, uuid); + match json::from_slice::(&unwrap!(slurp(&path))) { Ok(swap) => unwrap!(json::to_value(MySwapStatusResponse::from(&swap))), Err(e) => { log!("Error " (e) " parsing JSON from " (path.display())); Json::Null }, - }, - ) + } + }) .collect(); + let page_number = match req.page_number { + Some(number) => Json::from(number.get()), + None => match req.from_uuid { + Some(_) => Json::Null, + None => Json::from(1), + }, + }; + rpc_response( 200, json!({ "result": { "swaps": swaps, "from_uuid": req.from_uuid, - "skipped": skip, + "skipped": db_result.skipped, "limit": req.limit, - "total": entries.len(), - "page_number": req.page_number, - "total_pages": calc_total_pages(entries.len(), req.limit), + "total": db_result.total_count, + "page_number": page_number, + "total_pages": calc_total_pages(db_result.total_count, req.limit), + "found_records": db_result.uuids.len(), }, }) .to_string(), @@ -1013,7 +956,20 @@ pub async fn import_swaps(ctx: MmArc, req: Json) -> Result>, St let mut skipped = HashMap::new(); for swap in swaps { match swap.save_to_db(&ctx) { - Ok(_) => imported.push(swap.uuid().to_owned()), + Ok(_) => { + if let Some(info) = swap.get_my_info() { + if let Err(e) = insert_new_swap( + &ctx, + &info.my_coin, + &info.other_coin, + &swap.uuid().to_string(), + &info.started_at.to_string(), + ) { + error!("Error {} on new swap insertion", e); + } + } + imported.push(swap.uuid().to_owned()); + }, Err(e) => { skipped.insert(swap.uuid().to_owned(), e); }, @@ -1096,7 +1052,7 @@ pub async fn active_swaps_rpc(ctx: MmArc, req: Json) -> Result> let content = match slurp(&path) { Ok(c) => c, Err(e) => { - common::log::error!("Error {} on slurp({})", e, path.display()); + error!("Error {} on slurp({})", e, path.display()); continue; }, }; @@ -1106,7 +1062,7 @@ pub async fn active_swaps_rpc(ctx: MmArc, req: Json) -> Result> let status: SavedSwap = match json::from_slice(&content) { Ok(s) => s, Err(e) => { - common::log::error!("Error {} on deserializing the content {:?}", e, content); + error!("Error {} on deserializing the content {:?}", e, content); continue; }, }; diff --git a/mm2src/mm2.rs b/mm2src/mm2.rs index 5e7ee6736c..19962230dd 100644 --- a/mm2src/mm2.rs +++ b/mm2src/mm2.rs @@ -42,6 +42,7 @@ use std::str; use self::lp_native_dex::{lp_init, lp_ports}; use coins::update_coins_config; +#[path = "database.rs"] pub mod database; #[path = "lp_network.rs"] pub mod lp_network; #[path = "lp_ordermatch.rs"] pub mod lp_ordermatch; diff --git a/mm2src/mm2_tests.rs b/mm2src/mm2_tests.rs index 9f1f08adbd..65d9b9345a 100644 --- a/mm2src/mm2_tests.rs +++ b/mm2src/mm2_tests.rs @@ -853,18 +853,29 @@ async fn trade_base_rel_electrum(pairs: Vec<(&'static str, &'static str)>) { for (base, rel) in pairs.iter() { // ensure the swaps are started - unwrap!( - mm_alice - .wait_for_log(5., |log| log - .contains(&format!("Entering the taker_swap_loop {}/{}", base, rel))) - .await - ); - unwrap!( - mm_bob - .wait_for_log(5., |log| log - .contains(&format!("Entering the maker_swap_loop {}/{}", base, rel))) - .await - ); + let expected_log = format!("Entering the taker_swap_loop {}/{}", base, rel); + mm_alice + .wait_for_log(5., |log| log.contains(&expected_log)) + .await + .unwrap(); + let expected_log = format!("Entering the maker_swap_loop {}/{}", base, rel); + mm_bob + .wait_for_log(5., |log| log.contains(&expected_log)) + .await + .unwrap() + } + + for uuid in uuids.iter() { + // ensure the swaps are indexed to the SQLite database + let expected_log = format!("Inserting new swap {} to the SQLite database", uuid); + mm_alice + .wait_for_log(5., |log| log.contains(&expected_log)) + .await + .unwrap(); + mm_bob + .wait_for_log(5., |log| log.contains(&expected_log)) + .await + .unwrap() } for uuid in uuids.iter() {