diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..128c6ac20 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +.vscode +cmake-build-debug \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3ae3a23ab..1355ce65a 100755 --- a/.gitignore +++ b/.gitignore @@ -263,4 +263,12 @@ Release/* build_win64_release/* DB/* +.env.client +.env.seed +etomic_build/client/DB +etomic_build/client/stats.log +etomic_build/client/unparsed.txt +etomic_build/seed/DB +etomic_build/seed/stats.log +etomic_build/seed/unparsed.txt iguana/exchanges/manychains diff --git a/.travis.yml b/.travis.yml index 5730c4869..b77bb4622 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,6 @@ matrix: include: - os: linux compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-7 env: OS_NAME=Linux MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - os: osx compiler: clang @@ -17,14 +11,34 @@ matrix: osx_image: xcode9.2 before_install: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && sudo apt-get update && sudo apt-get install -y g++-7; fi - git submodule update --init --recursive script: + - export VERSION=`echo "$(git tag -l --points-at HEAD)"` - mkdir build && cd build - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cmake -DCMAKE_C_COMPILER=/usr/bin/gcc-7 -DCMAKE_CXX_COMPILER=/usr/bin/g++-7 ..; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake ..; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cmake -DMM_VERSION="$VERSION" -DCMAKE_C_COMPILER=/usr/bin/gcc-7 -DCMAKE_CXX_COMPILER=/usr/bin/g++-7 ..; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake -DMM_VERSION="$VERSION" ..; fi - cmake --build . --target marketmaker-mainnet + - cmake --build . --target marketmaker-testnet cache: - directories: - - $HOME/.hunter \ No newline at end of file + apt: true + directories: + - $HOME/.hunter + +before_deploy: + - export TAG=`echo "$(git rev-parse --short HEAD)"` + - mkdir deploy + - strip iguana/exchanges/marketmaker-mainnet + - strip iguana/exchanges/marketmaker-testnet + - tar -cvzf deploy/marketmaker-"$TRAVIS_OS_NAME"-"$TAG".tar.gz -C iguana/exchanges marketmaker-mainnet marketmaker-testnet +deploy: + provider: releases + api_key: + secure: "JDwFBGO4WLra9bXr2dsovet8y/ymC0Y+LJNr5/qlUIDt97zVytGbIlUc8BuI2VZFcnAvrtfOGdCs9m/PcLzZd4bMxXSsuaU0AJk/Vj9KzrIIGPJ4uS39KpO1USUpPW+5e0Bisf30JN3N2NypwMbMu42TKjVqaXSbVQfh79Iu6PdnyfiFbbTEfMeiRRrD72c00rwAw7kmndf7Sv9MiMN8WTFe0cQz5eH8GU/BSbnDorSrtClU4r7McR98zXaig/8XVcT543tcqdYW95QO7OqOjAid3XzzA/bPUTjC/nF/AyTJDco26nts0bCrCYeZRXIWdEInFLIeRHhHD7sW7dILRT/I7WlaLWnRtwo8e1L+U1k1yZ84dQMpgBznttdwH3vSj0crwCbFuMaRMMbPeW0H8C1VitLy1mlapw3RDI9yKlcw4V6WjPbz0YKhAoZgT/M/SaGr4ZkoWNCPoV5+Gub78p24Y8Y9BptJgj5t9KAcmDwbJ9wPt006ObWnbXvapo+6N5Dk2zuyQe9seoupzy4CAiNdluzAAVWsV/SjnN2aapjXoxaAaLQC6T8C1l1BpYri9LSKrjerr4QLVl/nw2yovAKNEobLLBVpSwfg4R72fu1BMS65gVsOqtFfs+R47CY+1D1Slev+UmKNMdE51+aXM+1XeC6wDUS5d13mW1NLhOE=" + file_glob: true + file: "deploy/*" + on: + tags: true + skip_cleanup: true diff --git a/Dockerfile.clientnode b/Dockerfile.clientnode new file mode 100644 index 000000000..96d9177df --- /dev/null +++ b/Dockerfile.clientnode @@ -0,0 +1,9 @@ +FROM ubuntu:17.10 +USER root +RUN apt-get update && apt-get install -y rinetd curl libcurl3-gnutls +RUN echo "0.0.0.0 10271 10.100.0.1 10271" >> /etc/rinetd.conf +RUN echo "0.0.0.0 8923 10.100.0.1 8923" >> /etc/rinetd.conf +RUN useradd -u 111 jenkins +USER jenkins +WORKDIR /usr/mm/etomic_build/client +CMD /usr/sbin/rinetd && rm -rf DB && ./client \ No newline at end of file diff --git a/Dockerfile.seednode b/Dockerfile.seednode new file mode 100644 index 000000000..d431296b6 --- /dev/null +++ b/Dockerfile.seednode @@ -0,0 +1,9 @@ +FROM ubuntu:17.10 +USER root +RUN apt-get update && apt-get install -y rinetd curl libcurl3-gnutls +RUN echo "0.0.0.0 10271 10.100.0.1 10271" >> /etc/rinetd.conf +RUN echo "0.0.0.0 8923 10.100.0.1 8923" >> /etc/rinetd.conf +RUN useradd -u 111 jenkins +USER jenkins +WORKDIR /usr/mm/etomic_build/seed +CMD /usr/sbin/rinetd && rm -rf DB && ./run diff --git a/Jenkinsfile b/Jenkinsfile index f7bb536b0..ee317926f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,11 +1,12 @@ pipeline { - agent { - docker { - image 'artempikulin/cmake-ubuntu' - } - - } + agent any stages { + stage('Prepare') { + steps { + sh '''cp -r /root/.env.client .env.client +cp -r /root/.env.seed .env.seed''' + } + } stage('Build') { steps { sh '''git submodule update --init --recursive @@ -13,7 +14,45 @@ rm -rf build mkdir build cd build cmake .. -cmake --build . --target marketmaker-testnet''' +cmake --build . --target marketmaker-testnet +cd ../ +docker-compose build''' + } + } + stage('Trade BEER/ETH') { + steps { + sh '''docker-compose up -d +./start_BEER_OTHER_trade.sh ETH +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f clientnode) +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f seednode) +docker-compose down''' + } + } + stage('Trade ETH/BEER') { + steps { + sh '''docker-compose up -d +./start_BEER_OTHER_trade_inverted.sh ETH +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f clientnode) +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f seednode) +docker-compose down''' + } + } + stage('Trade BEER/ETOMIC') { + steps { + sh '''docker-compose up -d +./start_BEER_OTHER_trade.sh ETOMIC +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f clientnode) +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f seednode) +docker-compose down''' + } + } + stage('Trade ETOMIC/BEER') { + steps { + sh '''docker-compose up -d +./start_BEER_OTHER_trade_inverted.sh ETOMIC +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f clientnode) +timeout 600 grep -q "SWAP completed" <(COMPOSE_HTTP_TIMEOUT=600 docker-compose logs -f seednode) +docker-compose down''' } } } diff --git a/appveyor.yml b/appveyor.yml index de2123bc5..3c82ea80a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,30 @@ version: 1.0.{build} -branches: - only: - - etomic build_script: -- cmd: marketmaker_build_etomic.cmd \ No newline at end of file +- cmd: marketmaker_build_etomic.cmd +cache: + - C:\.hunter + - marketmaker_depends + +after_build: + - '7z a mm-win.zip + .\build_win64_release\iguana\exchanges\Release\marketmaker-mainnet.exe + .\marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl.dll + .\marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.dll + "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\redist\\x64\\Microsoft.VC140.CRT\\msvcp140.dll" + "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\redist\\x64\\Microsoft.VC140.CRT\\vcruntime140.dll"' + +artifacts: + - path: mm-win.zip + name: marketmaker-mainnet + +deploy: + release: v$(appveyor_build_version) + provider: GitHub + auth_token: + secure: iabzoz73JgtOIyE/Nmz4a4XefmK+7pIeup+1Hunj4hGKrdfesFN+176DMApgfu8t + artifact: marketmaker-mainnet + draft: false + prerelease: false + on: + branch: master + appveyor_repo_tag: false \ No newline at end of file diff --git a/cpp-ethereum b/cpp-ethereum index 633c62c08..e804e95d9 160000 --- a/cpp-ethereum +++ b/cpp-ethereum @@ -1 +1 @@ -Subproject commit 633c62c08bc73c7c3935c948a8d6c656a3659976 +Subproject commit e804e95d9a71e87fc5e3e69a2888448f23bc724f diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..52da982c7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,41 @@ +version: '2' +services: + seednode: + build: + context: ./ + dockerfile: Dockerfile.seednode + volumes: + - ~/.zcash-params:/home/jenkins/.zcash-params + - ~/.komodo:/home/jenkins/.komodo + - .:/usr/mm + env_file: + - .env.seed + tty: true + networks: + default: + ipv4_address: 10.100.0.2 + + clientnode: + build: + context: ./ + dockerfile: Dockerfile.clientnode + volumes: + - ~/.zcash-params:/home/jenkins/.zcash-params + - ~/.komodo:/home/jenkins/.komodo + - .:/usr/mm + links: + - seednode + tty: true + env_file: + - .env.client + networks: + default: + ipv4_address: 10.100.0.3 + +networks: + default: + driver: bridge + ipam: + config: + - subnet: 10.100.0.0/16 + gateway: 10.100.0.1 \ No newline at end of file diff --git a/etomic_build/client b/etomic_build/client deleted file mode 100755 index fb4f0c935..000000000 --- a/etomic_build/client +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -source passphrase -source coins -./stop -iguana/exchanges/marketmaker "{\"netid\":9999,\"seednode\":\"5.9.253.204\",\"gui\":\"nogui\",\"client\":1, \"userhome\":\"/${HOME#"/"}\", \"passphrase\":\"$passphrase\", \"coins\":$coins}" & diff --git a/etomic_build/client/buy_BEER_OTHER b/etomic_build/client/buy_BEER_OTHER new file mode 100755 index 000000000..be2acb4da --- /dev/null +++ b/etomic_build/client/buy_BEER_OTHER @@ -0,0 +1,4 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"setprice\",\"base\":\"$1\",\"rel\":\"BEER\",\"price\":1}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"sell\",\"base\":\"$1\",\"rel\":\"BEER\",\"basevolume\":0.1,\"price\":1}" \ No newline at end of file diff --git a/etomic_build/client/client b/etomic_build/client/client new file mode 100755 index 000000000..22f5c462e --- /dev/null +++ b/etomic_build/client/client @@ -0,0 +1,4 @@ +#!/bin/bash +source passphrase +source ../coins +../../build/iguana/exchanges/marketmaker-testnet "{\"netid\":9999,\"seednode\":\"10.100.0.2\",\"gui\":\"nogui\",\"client\":1, \"userhome\":\"/${HOME#"/"}\", \"passphrase\":\"$passphrase\", \"coins\":$coins}" diff --git a/etomic_build/client/enable b/etomic_build/client/enable new file mode 100755 index 000000000..0bda2f3ce --- /dev/null +++ b/etomic_build/client/enable @@ -0,0 +1,7 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"ETOMIC\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"ETH\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"NODEC\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"JST\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"BEER\"}" diff --git a/etomic_build/client/myipaddr b/etomic_build/client/myipaddr new file mode 100644 index 000000000..f1649949c --- /dev/null +++ b/etomic_build/client/myipaddr @@ -0,0 +1 @@ +10.100.0.3 diff --git a/etomic_build/client/passphrase b/etomic_build/client/passphrase new file mode 100644 index 000000000..d54ee899d --- /dev/null +++ b/etomic_build/client/passphrase @@ -0,0 +1 @@ +export passphrase="$PASSPHRASE" diff --git a/etomic_build/client/setpassphrase b/etomic_build/client/setpassphrase new file mode 100755 index 000000000..81cc0b28f --- /dev/null +++ b/etomic_build/client/setpassphrase @@ -0,0 +1,4 @@ +#!/bin/bash +source userpass +source passphrase +curl --url "http://127.0.0.1:7783" --data "{\"netid\":9999,\"seednode\":\"10.100.0.2\",\"userpass\":\"1d8b27b21efabcd96571cd56f91a40fb9aa4cc623d273c63bf9223dc6f8cd81f\",\"method\":\"passphrase\",\"passphrase\":\"$passphrase\",\"gui\":\"nogui\"}" diff --git a/etomic_build/client/userpass b/etomic_build/client/userpass new file mode 100644 index 000000000..19fc21189 --- /dev/null +++ b/etomic_build/client/userpass @@ -0,0 +1,2 @@ +#export userpass="" +export userpass="$USERPASS" diff --git a/etomic_build/coins b/etomic_build/coins index 988b79784..db9100c13 100755 --- a/etomic_build/coins +++ b/etomic_build/coins @@ -1,3 +1,3 @@ -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\":\"ZOI\",\"name\":\"zoin\",\"rpcport\":8255,\"pubtype\":80,\"p2shtype\":7,\"wiftype\":208,\"txfee\":1000}, {\"coin\": \"PIZZA\",\"asset\": \"PIZZA\",\"rpcport\": 11116},{\"coin\": \"BEER\",\"asset\": \"BEER\",\"rpcport\": 8923}, {\"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},{\"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}]" +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\": 11116},{\"coin\": \"BEER\",\"asset\": \"BEER\",\"rpcport\": 8923}, {\"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},{\"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/etomic_build/passphrase b/etomic_build/passphrase deleted file mode 100644 index eb00095d6..000000000 --- a/etomic_build/passphrase +++ /dev/null @@ -1 +0,0 @@ -export passphrase="" diff --git a/etomic_build/run b/etomic_build/run deleted file mode 100755 index b757bb993..000000000 --- a/etomic_build/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -source passphrase -source coins -./stop - $1 iguana/exchanges/marketmaker "{\"netid\":9999,\"gui\":\"nogui\", \"profitmargin\":0.01, \"userhome\":\"/${HOME#"/"}\", \"passphrase\":\"$passphrase\", \"coins\":$coins}" & diff --git a/etomic_build/seed/enable b/etomic_build/seed/enable new file mode 100755 index 000000000..0bda2f3ce --- /dev/null +++ b/etomic_build/seed/enable @@ -0,0 +1,7 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"ETOMIC\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"ETH\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"NODEC\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"JST\"}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"BEER\"}" diff --git a/etomic_build/seed/myipaddr b/etomic_build/seed/myipaddr new file mode 100644 index 000000000..da7788dc2 --- /dev/null +++ b/etomic_build/seed/myipaddr @@ -0,0 +1 @@ +10.100.0.2 diff --git a/etomic_build/seed/passphrase b/etomic_build/seed/passphrase new file mode 100644 index 000000000..d54ee899d --- /dev/null +++ b/etomic_build/seed/passphrase @@ -0,0 +1 @@ +export passphrase="$PASSPHRASE" diff --git a/etomic_build/seed/run b/etomic_build/seed/run new file mode 100755 index 000000000..96ceba6ca --- /dev/null +++ b/etomic_build/seed/run @@ -0,0 +1,4 @@ +#!/bin/bash +source passphrase +source ../coins +../../build/iguana/exchanges/marketmaker-testnet "{\"netid\":9999,\"gui\":\"nogui\", \"profitmargin\":0.01, \"userhome\":\"/${HOME#"/"}\", \"passphrase\":\"$passphrase\", \"coins\":$coins}" diff --git a/etomic_build/seed/sell_BEER_OTHER b/etomic_build/seed/sell_BEER_OTHER new file mode 100755 index 000000000..cd11fc044 --- /dev/null +++ b/etomic_build/seed/sell_BEER_OTHER @@ -0,0 +1,4 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"setprice\",\"base\":\"BEER\",\"rel\":\"$1\",\"price\":0.9}" +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"sell\",\"base\":\"BEER\",\"rel\":\"$1\",\"basevolume\":0.1,\"price\":0.9}" \ No newline at end of file diff --git a/etomic_build/seed/setpassphrase b/etomic_build/seed/setpassphrase new file mode 100755 index 000000000..b3df81427 --- /dev/null +++ b/etomic_build/seed/setpassphrase @@ -0,0 +1,4 @@ +#!/bin/bash +source userpass +source passphrase +curl --url "http://127.0.0.1:7783" --data "{\"netid\":9999,\"seednode\":\"5.9.253.204\",\"userpass\":\"1d8b27b21efabcd96571cd56f91a40fb9aa4cc623d273c63bf9223dc6f8cd81f\",\"method\":\"passphrase\",\"passphrase\":\"$passphrase\",\"gui\":\"nogui\"}" diff --git a/etomic_build/seed/userpass b/etomic_build/seed/userpass new file mode 100644 index 000000000..19fc21189 --- /dev/null +++ b/etomic_build/seed/userpass @@ -0,0 +1,2 @@ +#export userpass="" +export userpass="$USERPASS" diff --git a/iguana/exchanges/CMakeLists.txt b/iguana/exchanges/CMakeLists.txt index 793aeb5a4..011e4cd37 100644 --- a/iguana/exchanges/CMakeLists.txt +++ b/iguana/exchanges/CMakeLists.txt @@ -31,4 +31,9 @@ target_link_libraries(marketmaker-mainnet ${MM_LIBS} etomiclib-mainnet) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") target_link_libraries(marketmaker-mainnet -static-libgcc -static-libstdc++) target_link_libraries(marketmaker-testnet -static-libgcc -static-libstdc++) -endif() \ No newline at end of file +endif() +if(NOT DEFINED MM_VERSION) + SET(MM_VERSION UNKNOWN) +endif() +target_compile_definitions(marketmaker-mainnet PRIVATE -DMM_VERSION="${MM_VERSION}") +target_compile_definitions(marketmaker-testnet PRIVATE -DMM_VERSION="${MM_VERSION}") \ No newline at end of file diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 5176b8f47..e413ffa64 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -251,10 +251,13 @@ cJSON *LP_coinjson(struct iguana_info *coin,int32_t showwif) } #ifndef NOTETOMIC else if (coin->etomic[0] != 0) { - //balance = LP_etomic_get_balance(coin, coin->smartaddr); + if (coin->inactive == 0) { + balance = LP_etomic_get_balance(coin, coin->smartaddr); + } else { + balance = 0; + } jaddnum(item,"height",-1); - //jaddnum(item,"balance",dstr(balance)); - jaddnum(item,"balance",0); + jaddnum(item,"balance",dstr(balance)); } #endif else @@ -374,7 +377,7 @@ struct iguana_info *LP_coinadd(struct iguana_info *cdata) } void *curl_easy_init(); -uint16_t LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t wiftaddr,uint8_t taddr,uint16_t busport,char *confpath) +uint16_t LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t wiftaddr,uint8_t taddr,uint16_t busport,char *confpath,uint8_t decimals) { static void *ctx; char *name2; uint16_t origport = port; @@ -437,6 +440,7 @@ uint16_t LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *asse } coin->curl_handle = curl_easy_init(); portable_mutex_init(&coin->curl_mutex); + coin->decimals = decimals; return(port); } @@ -480,7 +484,7 @@ struct iguana_info *LP_coinfind(char *symbol) else if ( strcmp(symbol,"KMD") == 0 ) name = "komodo"; else return(0); - port = LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0,0,busport,0); + port = LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0,0,busport,0,0); if ( port == 0 ) isinactive = 1; else isinactive = 0; @@ -522,7 +526,9 @@ struct iguana_info *LP_coincreate(cJSON *item) } else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - if ( LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,juint(item,"wiftaddr"),juint(item,"taddr"),LP_busport(port),jstr(item,"confpath")) < 0 ) + + uint8_t decimals = juint(item,"decimals"); + if ( LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,juint(item,"wiftaddr"),juint(item,"taddr"),LP_busport(port),jstr(item,"confpath"),decimals) < 0 ) { coin = LP_coinadd(&cdata); coin->inactive = (uint32_t)time(NULL); diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4d9527b32..4e2e08ba6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -120,6 +120,7 @@ cancel(uuid)\n\ buy(base, rel, price, relvolume, timeout=10, duration=3600, nonce)\n\ sell(base, rel, price, basevolume, timeout=10, duration=3600, nonce)\n\ withdraw(coin, outputs[], broadcast=0)\n\ +eth_withdraw(coin, to, amount, gas, gas_price, broadcast=0)\n\ txblast(coin, utxotxid, utxovout, utxovalue, txfee, passphrase, outputs[], broadcast=0)\n\ sendrawtransaction(coin, signedtx)\n\ swapstatus(pending=0, fast=0)\n\ @@ -176,7 +177,13 @@ getfee(coin)\n\ sleep(seconds=60)\n\ listtransactions(coin, address, count=10, skip=0)\n\ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ +version\n\ \"}")); + if ( strcmp(method,"version") == 0 ) { + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result",MM_VERSION); + return(jprint(retjson,1)); + } if ( (base= jstr(argjson,"base")) == 0 ) base = ""; @@ -232,9 +239,14 @@ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ { if ( (ptr= LP_coinsearch("KMD")) != 0 ) { - if ( jint(argjson,"weeks") <= 0 || jdouble(argjson,"amount") < 10. ) - return(clonestr("{\"error\":\"instantdex_deposit needs to have weeks and amount\"}")); - else return(LP_instantdex_deposit(ptr,juint(argjson,"weeks"),jdouble(argjson,"amount"),jobj(argjson,"broadcast") != 0 ? jint(argjson,"broadcast") : 1)); + if ( jint(argjson,"weeks") <= 0 ) { + return(clonestr("{\"error\":\"instantdex_deposit weeks param must be greater than zero\"}")); + } + if ( jdouble(argjson,"amount") < 10. ) { + return(clonestr("{\"error\":\"instantdex_deposit amount param must be equal or greater than 10\"}")); + } + + return(LP_instantdex_deposit(ptr,juint(argjson,"weeks"),jdouble(argjson,"amount"),jobj(argjson,"broadcast") != 0 ? jint(argjson,"broadcast") : 1)); } return(clonestr("{\"error\":\"cant find KMD\"}")); } @@ -396,11 +408,6 @@ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ jaddbits256(retjson,"privkey",privkey); bitcoin_priv2wif(coin,wiftaddr,wifstr,privkey,wiftype); jaddstr(retjson,"wif",wifstr); -#ifndef NOTETOMIC - char ethaddr[50]; - LP_etomic_pubkeystr_to_addr(pubsecp, ethaddr); - jaddstr(retjson,"ethaddr",ethaddr); -#endif return(jprint(retjson,1)); } else return(clonestr("{\"error\":\"need to have passphrase\"}")); } @@ -456,6 +463,12 @@ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ } else if ( strcmp(method,"inuse") == 0 ) return(jprint(LP_inuse_json(),1)); +#ifndef NOTETOMIC + else if ( strcmp(method,"eth_gas_price") == 0 ) + { + return LP_eth_gas_price(); + } +#endif else if ( (retstr= LP_istradebots_command(ctx,pubsock,method,argjson)) != 0 ) return(retstr); if ( base[0] != 0 && rel[0] != 0 ) @@ -584,6 +597,23 @@ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ jaddstr(retjson,"coin",coin); return(jprint(retjson,1)); } +#ifndef NOT_ETOMIC + if (strcmp(coin, "ETOMIC") == 0) { + char eth_addr[100]; + bits256 privkey = LP_privkey("ETOMIC", ptr->smartaddr, ptr->taddr); + LP_etomic_priv2addr(eth_addr, privkey); + if (get_etomic_from_faucet(eth_addr, ptr->smartaddr) != 1) { + return(clonestr("{\"error\":\"Could not get ETOMIC from faucet!\"}")); + } + } + + if (ptr->etomic[0] != 0) { + struct iguana_info *etomic_coin = LP_coinsearch("ETOMIC"); + if (etomic_coin->inactive != 0) { + return(clonestr("{\"error\":\"Enable ETOMIC first to use ETH/ERC20!\"}")); + } + } +#endif if ( LP_conflicts_find(ptr) == 0 ) { cJSON *array; diff --git a/iguana/exchanges/LP_etomic.c b/iguana/exchanges/LP_etomic.c index 532f8f4d5..9d0a7e468 100644 --- a/iguana/exchanges/LP_etomic.c +++ b/iguana/exchanges/LP_etomic.c @@ -22,6 +22,9 @@ // Created by artem on 24.01.18. // #include "LP_etomic.h" +#define ALICE_PAYMENT_SENT 1 +#define BOB_DEPOSIT_SENT 1 +#define BOB_PAYMENT_SENT 1 int32_t LP_etomic_wait_for_confirmation(char *txId) { @@ -38,13 +41,15 @@ void LP_etomic_pubkeystr_to_addr(char *pubkey, char *output) char *LP_etomicalice_send_fee(struct basilisk_swap *swap) { char amount[100], secretKey[70], dexaddr[50]; - satoshisToWei(amount, swap->myfee.I.amount); + satoshisToWei(amount, LP_DEXFEE(swap->I.alicerealsat)); uint8arrayToHex(secretKey, swap->persistent_privkey.bytes, 32); LP_etomic_pubkeystr_to_addr(INSTANTDEX_PUBKEY, dexaddr); if (strcmp(swap->I.alicestr,"ETH") == 0 ) { - return(sendEth(dexaddr, amount, secretKey, 1)); + return(sendEth(dexaddr, amount, secretKey, 1, 0, 0, 1)); } else { - return(sendErc20(swap->I.alicetomic, dexaddr, amount, secretKey, 1)); + struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr); + + return(sendErc20(swap->I.alicetomic, dexaddr, amount, secretKey, 1, 0, 0, 1, alicecoin->decimals)); } } @@ -68,19 +73,21 @@ uint8_t LP_etomic_verify_alice_fee(struct basilisk_swap *swap) return(0); } uint64_t txValue = weiToSatoshi(data.valueHex); - if (txValue != swap->otherfee.I.amount) { - printf("Alice fee %s amount %" PRIu64 " is not equal to expected %" PRIu64 "\n", swap->otherfee.I.ethTxid, txValue, swap->otherfee.I.amount); + if (txValue != LP_DEXFEE(swap->I.alicerealsat)) { + printf("Alice fee %s amount %" PRIu64 " is not equal to expected %" PRId64 "\n", swap->otherfee.I.ethTxid, txValue, LP_DEXFEE(swap->I.alicerealsat)); return(0); } return(1); } else { + struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr); + if (strcmp(data.to, swap->I.alicetomic) != 0) { printf("Alice ERC20 fee %s token address %s is not equal to expected %s\n", swap->otherfee.I.ethTxid, data.to, swap->I.alicetomic); return(0); } char weiAmount[70]; - satoshisToWei(weiAmount, swap->otherfee.I.amount); - return(verifyAliceErc20FeeData(swap->I.alicetomic, dexaddr, weiAmount, data.input)); + satoshisToWei(weiAmount, LP_DEXFEE(swap->I.alicerealsat)); + return(verifyAliceErc20FeeData(swap->I.alicetomic, dexaddr, weiAmount, data.input, alicecoin->decimals)); } } @@ -100,28 +107,31 @@ char *LP_etomicalice_send_payment(struct basilisk_swap *swap) strcpy(txData.from, swap->I.etomicdest); strcpy(txData.to, ETOMIC_ALICECONTRACT); - satoshisToWei(txData.amount, swap->I.alicesatoshis); + satoshisToWei(txData.amount, swap->I.alicerealsat); uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32); return(aliceSendsEthPayment(input,txData)); } else { + struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr); + memset(&input20,0,sizeof(input20)); strcpy(input20.bobAddress, swap->I.etomicsrc); uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20); uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20); uint8arrayToHex(input20.dealId, swap->alicepayment.I.actualtxid.bytes, 32); strcpy(input20.tokenAddress, swap->I.alicetomic); - satoshisToWei(input20.amount, swap->I.alicesatoshis); + satoshisToWei(input20.amount, swap->I.alicerealsat); + input20.decimals = alicecoin->decimals; strcpy(txData.from, swap->I.etomicdest); strcpy(txData.to, ETOMIC_ALICECONTRACT); strcpy(txData.amount, "0"); uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32); - uint64_t allowance = getErc20Allowance(swap->I.etomicdest, ETOMIC_ALICECONTRACT, swap->I.alicetomic); - if (allowance < swap->I.alicesatoshis) { + uint64_t allowance = getErc20Allowance(swap->I.etomicdest, ETOMIC_ALICECONTRACT, swap->I.alicetomic, alicecoin->decimals); + if (allowance < swap->I.alicerealsat) { printf("Alice token allowance is too low, setting new allowance\n"); ApproveErc20Input approveErc20Input; strcpy(approveErc20Input.tokenAddress, swap->I.alicetomic); @@ -161,8 +171,8 @@ uint8_t LP_etomic_verify_alice_payment(struct basilisk_swap *swap, char *txId) if ( strcmp(swap->I.alicestr,"ETH") == 0 ) { uint64_t paymentAmount = weiToSatoshi(data.valueHex); - if (paymentAmount != swap->I.alicesatoshis) { - printf("Alice payment amount %" PRIu64 " does not match expected %" PRIu64 "\n", paymentAmount, swap->I.alicesatoshis); + if (paymentAmount != swap->I.alicerealsat) { + printf("Alice payment amount %" PRIu64 " does not match expected %" PRIu64 "\n", paymentAmount, swap->I.alicerealsat); return(0); } memset(&input,0,sizeof(input)); @@ -173,13 +183,16 @@ uint8_t LP_etomic_verify_alice_payment(struct basilisk_swap *swap, char *txId) return(verifyAliceEthPaymentData(input, data.input)); } else { + struct iguana_info *alicecoin = LP_coinfind(swap->I.alicestr); + memset(&input20,0,sizeof(input20)); strcpy(input20.bobAddress, swap->I.etomicsrc); uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20); uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20); uint8arrayToHex(input20.dealId, swap->alicepayment.I.actualtxid.bytes, 32); strcpy(input20.tokenAddress, swap->I.alicetomic); - satoshisToWei(input20.amount, swap->I.alicesatoshis); + satoshisToWei(input20.amount, swap->I.alicerealsat); + input20.decimals = alicecoin->decimals; return(verifyAliceErc20PaymentData(input20, data.input)); } @@ -201,13 +214,18 @@ char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap) memset(&txData,0,sizeof(txData)); memset(&input,0,sizeof(input)); - struct iguana_info *ecoin; + struct iguana_info *ecoin, *alice_coin; bits256 privkey; ecoin = LP_coinfind("ETOMIC"); + alice_coin = LP_coinfind(swap->dest); privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); uint8arrayToHex(input.dealId, swap->txids[BASILISK_ALICEPAYMENT].bytes, 32); - satoshisToWei(input.amount, swap->destamount); + if (alicePaymentStatus(input.dealId + 2) != ALICE_PAYMENT_SENT) { + printf("Alice payment smart contract status check failed, can't spend\n"); + return NULL; + } + satoshisToWei(input.amount, swap->alicerealsat); if (swap->alicetomic[0] != 0) { strcpy(input.tokenAddress, swap->alicetomic); @@ -223,6 +241,8 @@ char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap) } uint8arrayToHex(input.bobSecret, invertedSecret.bytes, 32); + input.decimals = alice_coin->decimals; + strcpy(txData.from, swap->etomicdest); strcpy(txData.to, ETOMIC_ALICECONTRACT); strcpy(txData.amount, "0"); @@ -253,7 +273,12 @@ char *LP_etomicbob_spends_alice_payment(struct LP_swap_remember *swap) privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); uint8arrayToHex(input.dealId, swap->txids[BASILISK_ALICEPAYMENT].bytes, 32); - satoshisToWei(input.amount, swap->destamount); + if (alicePaymentStatus(input.dealId + 2) != ALICE_PAYMENT_SENT) { + printf("Alice payment smart contract status check failed, can't spend\n"); + return NULL; + } + + satoshisToWei(input.amount, swap->alicerealsat); if (swap->alicetomic[0] != 0) { strcpy(input.tokenAddress, swap->alicetomic); @@ -268,6 +293,8 @@ char *LP_etomicbob_spends_alice_payment(struct LP_swap_remember *swap) } uint8arrayToHex(input.aliceSecret, invertedSecret.bytes, 32); uint8arrayToHex(input.bobHash, swap->secretBn, 20); + struct iguana_info *alice_coin = LP_coinfind(swap->dest); + input.decimals = alice_coin->decimals; strcpy(txData.from, swap->etomicsrc); strcpy(txData.to, ETOMIC_ALICECONTRACT); @@ -292,24 +319,27 @@ char *LP_etomicbob_sends_deposit(struct basilisk_swap *swap) strcpy(txData.from, swap->I.etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); - satoshisToWei(txData.amount, swap->bobdeposit.I.amount); + satoshisToWei(txData.amount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat)); uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32); return bobSendsEthDeposit(input, txData); } else { + struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr); + uint8arrayToHex(input20.depositId, swap->bobdeposit.I.actualtxid.bytes, 32); strcpy(input20.aliceAddress, swap->I.etomicdest); uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20); - satoshisToWei(input20.amount, swap->bobdeposit.I.amount); + satoshisToWei(input20.amount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat)); strcpy(input20.tokenAddress, swap->I.bobtomic); input20.lockTime = swap->bobdeposit.I.locktime; + input20.decimals = bobcoin->decimals; strcpy(txData.from, swap->I.etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); strcpy(txData.amount, "0"); uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32); - uint64_t allowance = getErc20Allowance(swap->I.etomicsrc, ETOMIC_BOBCONTRACT, swap->I.bobtomic); - if (allowance < swap->bobdeposit.I.amount) { + uint64_t allowance = getErc20Allowance(swap->I.etomicsrc, ETOMIC_BOBCONTRACT, swap->I.bobtomic, bobcoin->decimals); + if (allowance < LP_DEPOSITSATOSHIS(swap->I.bobrealsat)) { printf("Bob token allowance is too low, setting new allowance\n"); ApproveErc20Input approveErc20Input; strcpy(approveErc20Input.tokenAddress, swap->I.bobtomic); @@ -351,8 +381,8 @@ uint8_t LP_etomic_verify_bob_deposit(struct basilisk_swap *swap, char *txId) memset(&input20,0,sizeof(input20)); if ( strcmp(swap->I.bobstr,"ETH") == 0 ) { uint64_t depositAmount = weiToSatoshi(data.valueHex); - if (depositAmount != swap->bobdeposit.I.amount) { - printf("Bob deposit %s amount %" PRIu64 " != expected %" PRIu64 "\n", txId, depositAmount, swap->bobdeposit.I.amount); + if (depositAmount != LP_DEPOSITSATOSHIS(swap->I.bobrealsat)) { + printf("Bob deposit %s amount %" PRIu64 " != expected %" PRIu64 "\n", txId, depositAmount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat)); return(0); } uint8arrayToHex(input.depositId, swap->bobdeposit.I.actualtxid.bytes, 32); @@ -362,12 +392,15 @@ uint8_t LP_etomic_verify_bob_deposit(struct basilisk_swap *swap, char *txId) return verifyBobEthDepositData(input, data.input); } else { + struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr); + uint8arrayToHex(input20.depositId, swap->bobdeposit.I.actualtxid.bytes, 32); strcpy(input20.aliceAddress, swap->I.etomicdest); uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20); - satoshisToWei(input20.amount, swap->bobdeposit.I.amount); + satoshisToWei(input20.amount, LP_DEPOSITSATOSHIS(swap->I.bobrealsat)); strcpy(input20.tokenAddress, swap->I.bobtomic); input20.lockTime = swap->bobdeposit.I.locktime; + input20.decimals = bobcoin->decimals; return verifyBobErc20DepositData(input20, data.input); } @@ -384,9 +417,10 @@ char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap) memset(&txData,0,sizeof(txData)); memset(&input,0,sizeof(input)); - struct iguana_info *ecoin; + struct iguana_info *ecoin, *bobcoin; bits256 privkey; ecoin = LP_coinfind("ETOMIC"); + bobcoin = LP_coinfind(swap->src); privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); EthTxReceipt receipt = getEthTxReceipt(swap->bobDepositEthTx); @@ -395,6 +429,11 @@ char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap) return NULL; } uint8arrayToHex(input.depositId, swap->txids[BASILISK_BOBDEPOSIT].bytes, 32); + if (bobDepositStatus(input.depositId + 2) != BOB_DEPOSIT_SENT) { + printf("Bob deposit smart contract status check failed, can't claim\n"); + return NULL; + } + strcpy(input.aliceAddress, swap->etomicdest); bits256 invertedSecret; @@ -409,7 +448,8 @@ char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap) } else { strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000"); } - satoshisToWei(input.amount, swap->values[BASILISK_BOBDEPOSIT]); + satoshisToWei(input.amount, LP_DEPOSITSATOSHIS(swap->bobrealsat)); + input.decimals = bobcoin->decimals; strcpy(txData.from, swap->etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); @@ -435,24 +475,27 @@ char *LP_etomicbob_sends_payment(struct basilisk_swap *swap) strcpy(txData.from, swap->I.etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); - satoshisToWei(txData.amount, swap->bobpayment.I.amount); + satoshisToWei(txData.amount, swap->I.bobrealsat); uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32); return bobSendsEthPayment(input, txData); } else { + struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr); + uint8arrayToHex(input20.paymentId, swap->bobpayment.I.actualtxid.bytes, 32); strcpy(input20.aliceAddress, swap->I.etomicdest); uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20); - satoshisToWei(input20.amount, swap->bobpayment.I.amount); + satoshisToWei(input20.amount, swap->I.bobrealsat); strcpy(input20.tokenAddress, swap->I.bobtomic); input20.lockTime = swap->bobpayment.I.locktime; + input20.decimals = bobcoin->decimals; strcpy(txData.from, swap->I.etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); strcpy(txData.amount, "0"); uint8arrayToHex(txData.secretKey, swap->persistent_privkey.bytes, 32); - uint64_t allowance = getErc20Allowance(swap->I.etomicsrc, ETOMIC_BOBCONTRACT, swap->I.bobtomic); - if (allowance < swap->bobpayment.I.amount) { + uint64_t allowance = getErc20Allowance(swap->I.etomicsrc, ETOMIC_BOBCONTRACT, swap->I.bobtomic, bobcoin->decimals); + if (allowance < swap->I.bobrealsat) { printf("Bob token allowance is too low, setting new allowance\n"); ApproveErc20Input approveErc20Input; strcpy(approveErc20Input.tokenAddress, swap->I.bobtomic); @@ -493,8 +536,8 @@ uint8_t LP_etomic_verify_bob_payment(struct basilisk_swap *swap, char *txId) if ( strcmp(swap->I.bobstr,"ETH") == 0 ) { uint64_t paymentAmount = weiToSatoshi(data.valueHex); - if (paymentAmount != swap->bobpayment.I.amount) { - printf("Bob payment %s amount %" PRIu64 " != expected %" PRIu64 "\n", txId, paymentAmount, swap->bobpayment.I.amount); + if (paymentAmount != swap->I.bobrealsat) { + printf("Bob payment %s amount %" PRIu64 " != expected %" PRIu64 "\n", txId, paymentAmount, swap->I.bobrealsat); return(0); } uint8arrayToHex(input.paymentId, swap->bobpayment.I.actualtxid.bytes, 32); @@ -504,12 +547,15 @@ uint8_t LP_etomic_verify_bob_payment(struct basilisk_swap *swap, char *txId) return verifyBobEthPaymentData(input, data.input); } else { + struct iguana_info *bobcoin = LP_coinfind(swap->I.bobstr); + uint8arrayToHex(input20.paymentId, swap->bobpayment.I.actualtxid.bytes, 32); strcpy(input20.aliceAddress, swap->I.etomicdest); uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20); - satoshisToWei(input20.amount, swap->bobpayment.I.amount); + satoshisToWei(input20.amount, swap->I.bobrealsat); strcpy(input20.tokenAddress, swap->I.bobtomic); input20.lockTime = swap->bobpayment.I.locktime; + input20.decimals = bobcoin->decimals; return verifyBobErc20PaymentData(input20, data.input); } @@ -526,9 +572,10 @@ char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap) memset(&txData,0,sizeof(txData)); memset(&input,0,sizeof(input)); - struct iguana_info *ecoin; + struct iguana_info *ecoin, *bobcoin; bits256 privkey; ecoin = LP_coinfind("ETOMIC"); + bobcoin = LP_coinfind(swap->src); privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); EthTxReceipt receipt = getEthTxReceipt(swap->bobPaymentEthTx); @@ -537,6 +584,10 @@ char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap) return NULL; } uint8arrayToHex(input.paymentId, swap->txids[BASILISK_BOBPAYMENT].bytes, 32); + if (bobPaymentStatus(input.paymentId + 2) != BOB_PAYMENT_SENT) { + printf("Bob payment smart contract status check failed, can't spend\n"); + return NULL; + } strcpy(input.aliceAddress, swap->etomicdest); uint8arrayToHex(input.aliceHash, swap->secretAm, 20); @@ -545,7 +596,8 @@ char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap) } else { strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000"); } - satoshisToWei(input.amount, swap->values[BASILISK_BOBPAYMENT]); + satoshisToWei(input.amount, swap->bobrealsat); + input.decimals = bobcoin->decimals; strcpy(txData.from, swap->etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); @@ -570,13 +622,18 @@ char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap) printf("Bob payment %s receipt status failed, can't spend\n", swap->bobPaymentEthTx); return NULL; } - struct iguana_info *ecoin; + struct iguana_info *ecoin, *bobcoin; bits256 privkey; ecoin = LP_coinfind("ETOMIC"); + bobcoin = LP_coinfind(swap->src); privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); uint8arrayToHex(input.paymentId, swap->txids[BASILISK_BOBPAYMENT].bytes, 32); - satoshisToWei(input.amount, swap->values[BASILISK_BOBPAYMENT]); + if (bobPaymentStatus(input.paymentId + 2) != BOB_PAYMENT_SENT) { + printf("Bob payment smart contract status check failed, can't spend\n"); + return NULL; + } + satoshisToWei(input.amount, swap->bobrealsat); if (swap->bobtomic[0] != 0) { strcpy(input.tokenAddress, swap->bobtomic); @@ -591,6 +648,7 @@ char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap) invertedSecret.bytes[i] = swap->privAm.bytes[31 - i]; } uint8arrayToHex(input.aliceSecret, invertedSecret.bytes, 32); + input.decimals = bobcoin->decimals; strcpy(txData.from, swap->etomicdest); strcpy(txData.to, ETOMIC_BOBCONTRACT); @@ -616,13 +674,19 @@ char *LP_etomicalice_claims_bob_deposit(struct LP_swap_remember *swap) return NULL; } - struct iguana_info *ecoin; + struct iguana_info *ecoin, *bobcoin; bits256 privkey; ecoin = LP_coinfind("ETOMIC"); + bobcoin = LP_coinfind(swap->src); privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); uint8arrayToHex(input.depositId, swap->txids[BASILISK_BOBDEPOSIT].bytes, 32); - satoshisToWei(input.amount, swap->values[BASILISK_BOBDEPOSIT]); + if (bobDepositStatus(input.depositId + 2) != BOB_DEPOSIT_SENT) { + printf("Bob deposit smart contract status check failed, can't claim\n"); + return NULL; + } + + satoshisToWei(input.amount, LP_DEPOSITSATOSHIS(swap->bobrealsat)); if (swap->bobtomic[0] != 0) { strcpy(input.tokenAddress, swap->bobtomic); @@ -632,6 +696,7 @@ char *LP_etomicalice_claims_bob_deposit(struct LP_swap_remember *swap) strcpy(input.bobAddress, swap->etomicsrc); uint8arrayToHex(input.bobHash, swap->secretBn, 20); + input.decimals = bobcoin->decimals; strcpy(txData.from, swap->etomicdest); strcpy(txData.to, ETOMIC_BOBCONTRACT); @@ -718,6 +783,6 @@ uint64_t LP_etomic_get_balance(struct iguana_info *coin, char *coinaddr) if (strcmp(coin->symbol, "ETH") == 0) { return getEthBalance(coinaddr); } else { - return getErc20BalanceSatoshi(coinaddr, coin->etomic); + return getErc20BalanceSatoshi(coinaddr, coin->etomic, coin->decimals); } } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index db99385d4..8358580e9 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -241,7 +241,7 @@ struct basilisk_swapinfo bits256 myhash,otherhash,orderhash; uint32_t statebits,otherstatebits,started,expiration,finished,dead,reftime,putduration,callduration; int32_t bobconfirms,aliceconfirms,iambob,reclaimed,bobspent,alicespent,pad,aliceistrusted,bobistrusted,otheristrusted,otherstrust,alicemaxconfirms,bobmaxconfirms; - int64_t alicesatoshis,bobsatoshis,bobinsurance,aliceinsurance,Atxfee,Btxfee; + int64_t alicesatoshis,bobsatoshis,bobinsurance,aliceinsurance,Atxfee,Btxfee,alicerealsat,bobrealsat; bits256 myprivs[2],mypubs[2],otherpubs[2],pubA0,pubA1,pubB0,pubB1,privAm,pubAm,privBn,pubBn; uint32_t crcs_mypub[2],crcs_mychoosei[2],crcs_myprivs[2],crcs_mypriv[2]; @@ -273,7 +273,7 @@ static char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment struct LP_swap_remember { bits256 pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; - uint64_t Atxfee,Btxfee,srcamount,destamount,aliceid; + uint64_t Atxfee,Btxfee,srcamount,destamount,aliceid,alicerealsat,bobrealsat; int64_t values[sizeof(txnames)/sizeof(*txnames)]; uint32_t finishtime,tradeid,requestid,quoteid,plocktime,dlocktime,expiration,state,otherstate; int32_t iambob,finishedflag,origfinishedflag,Predeemlen,Dredeemlen,sentflags[sizeof(txnames)/sizeof(*txnames)]; @@ -312,7 +312,7 @@ struct iguana_info double price_kmd,force,perc,goal,goalperc,relvolume,rate; void *electrum; void *ctx; uint64_t maxamount,kmd_equiv,balanceA,balanceB,valuesumA,valuesumB; - uint8_t pubkey33[33],zcash; + uint8_t pubkey33[33],zcash,decimals; int32_t privkeydepth; void *curl_handle; portable_mutex_t curl_mutex; bits256 cachedtxid,notarizationtxid; uint8_t *cachedtxiddata; int32_t cachedtxidlen; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1c58d9e58..a6039311a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,6 +30,9 @@ // there is an issue about waiting for notarization for a swap that never starts (expiration ok) #include +#ifndef MM_VERSION +#define MM_VERSION "UNKNOWN" +#endif long LP_cjson_allocated,LP_cjson_total,LP_cjson_count; @@ -117,7 +120,7 @@ struct LP_globals { //struct LP_utxoinfo *LP_utxoinfos[2],*LP_utxoinfos2[2]; bits256 LP_mypub25519,LP_privkey,LP_mypriv25519,LP_passhash; - uint64_t LP_skipstatus[10000]; + uint64_t LP_skipstatus[10000], LP_required_etomic_balance; uint16_t netid; uint8_t LP_myrmd160[20],LP_pubsecp[33]; uint32_t LP_sessionid,counter; @@ -1393,8 +1396,7 @@ extern int32_t bitcoind_RPC_inittime; void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybusport,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0,version[64]; long filesize,n; int32_t valid,timeout; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128],*coins_str=0; cJSON *coinsjson=0; void *ctx = bitcoin_ctx(); - sprintf(version,"Marketmaker %s.%s %s rsize.%ld",LP_MAJOR_VERSION,LP_MINOR_VERSION,LP_BUILD_NUMBER,sizeof(struct basilisk_request)); + char *myipaddr=0; long filesize,n; int32_t valid,timeout; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128],*coins_str=0; cJSON *coinsjson=0; void *ctx = bitcoin_ctx(); bitcoind_RPC_inittime = 1; if ( LP_MAXPRICEINFOS > 256 ) { @@ -1402,7 +1404,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu exit(-1); } LP_showwif = juint(argjson,"wif"); - printf("showwif.%d %s %u\n",LP_showwif,version,calc_crc32(0,version,(int32_t)strlen(version))); + printf("showwif.%d version: %s %u\n",LP_showwif,MM_VERSION,calc_crc32(0,MM_VERSION,(int32_t)strlen(MM_VERSION))); if ( passphrase == 0 || passphrase[0] == 0 ) { printf("jeezy says we cant use the nullstring as passphrase and I agree\n"); @@ -1476,10 +1478,10 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu myipaddr = clonestr("127.0.0.1"); #ifndef _WIN32 #ifndef FROM_JS - if ( system("curl -s4 checkip.amazonaws.com > myipaddr") == 0 ) + char ipfname[64]; + strcpy(ipfname,"myipaddr"); + if ( access( ipfname, F_OK ) != -1 || system("curl -s4 checkip.amazonaws.com > myipaddr") == 0 ) { - char ipfname[64]; - strcpy(ipfname,"myipaddr"); if ( (myipaddr= OS_filestr(&filesize,ipfname)) != 0 && myipaddr[0] != 0 ) { n = strlen(myipaddr); diff --git a/iguana/exchanges/LP_portfolio.c b/iguana/exchanges/LP_portfolio.c index 29d54d1ee..b38a08c89 100644 --- a/iguana/exchanges/LP_portfolio.c +++ b/iguana/exchanges/LP_portfolio.c @@ -95,14 +95,12 @@ uint64_t LP_balance(uint64_t *valuep,int32_t iambob,char *symbol,char *coinaddr) cJSON *array,*item; bits256 zero; int32_t i,n; uint64_t valuesum,satoshisum,value; valuesum = satoshisum = 0; memset(zero.bytes,0,sizeof(zero)); -/* #ifndef NOTETOMIC struct iguana_info *coin = LP_coinfind(symbol); - if (coin->etomic[0] != 0) { + if (coin->etomic[0] != 0 && coin->inactive == 0) { valuesum = LP_etomic_get_balance(coin, coinaddr); } else #endif -*/ if ( (array= LP_listunspent(symbol,coinaddr,zero,zero)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index deaacf1c9..630910f3d 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -80,6 +80,9 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx fprintf(fp,",\"alicePaymentEthTx\":\"%s\"", swap->alicepayment.I.ethTxid); } + fprintf(fp,",\"aliceRealSat\":\"%" PRId64 "\"", swap->I.alicerealsat); + fprintf(fp,",\"bobRealSat\":\"%" PRId64 "\"", swap->I.bobrealsat); + fprintf(fp,",\"alicecoin\":\"%s\"",swap->I.alicestr); if ( swap->I.alicetomic[0] != 0 ) fprintf(fp,",\"alicetomic\":\"%s\"",swap->I.alicetomic); @@ -921,6 +924,9 @@ int32_t LP_swap_load(struct LP_swap_remember *rswap,int32_t forceflag) strcpy(rswap->alicetomic, jstr(txobj,"alicetomic")); } + rswap->bobrealsat = jint(txobj, "bobRealSat"); + rswap->alicerealsat = jint(txobj, "aliceRealSat"); + rswap->txids[i] = txid; if ( jstr(txobj,"Apayment") != 0 ) safecopy(rswap->alicepaymentaddr,jstr(txobj,"Apayment"),sizeof(rswap->alicepaymentaddr)); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 0e59fc626..9c1bca6c2 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -137,6 +137,11 @@ int32_t LP_getheight(int32_t *notarizedp,struct iguana_info *coin) uint64_t LP_RTsmartbalance(struct iguana_info *coin) { +#ifndef NOTETOMIC + if (coin->etomic[0] != 0) { + return LP_etomic_get_balance(coin, coin->smartaddr); + } +#endif cJSON *array,*item; char buf[512],*retstr; int32_t i,n; uint64_t valuesum,value; bits256 zero; valuesum = 0; memset(zero.bytes,0,sizeof(zero)); diff --git a/iguana/exchanges/LP_signatures.c b/iguana/exchanges/LP_signatures.c index 91667fa2e..2d8e45750 100644 --- a/iguana/exchanges/LP_signatures.c +++ b/iguana/exchanges/LP_signatures.c @@ -442,6 +442,16 @@ char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *re jaddstr(reqjson,"pubsecp",pubsecpstr); if ( (kmd= LP_coinfind("KMD")) != 0 && (ap= LP_address(kmd,kmd->smartaddr)) != 0 && ap->instantdex_credits != 0 ) jaddnum(reqjson,"credits",dstr(ap->instantdex_credits)); +#ifndef NOTETOMIC + if (basecoin->etomic[0] != 0) { + uint64_t etomic_coin_balance = LP_etomic_get_balance(basecoin, basecoin->smartaddr); + jaddstr(reqjson,"utxocoin","ETH_OR_ERC20"); + jaddnum(reqjson,"bal",dstr(etomic_coin_balance)); + jaddnum(reqjson,"min",dstr(etomic_coin_balance)); + jaddnum(reqjson,"max",dstr(etomic_coin_balance)); + jaddnum(reqjson,"n",1); + } else +#endif if ( (numutxos= LP_address_minmax(1,&median,&minsize,&maxsize,basecoin,basecoin->smartaddr)) != 0 ) { //printf("send %s numutxos.%d median %.8f min %.8f max %.8f\n",base,numutxos,dstr(median),dstr(minsize),dstr(maxsize)); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 6831ae4ec..5c7af583e 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -854,7 +854,16 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; bobwaittimeout = LP_calc_waittimeout(bobstr); alicewaittimeout = LP_calc_waittimeout(alicestr); - if ( swap != 0 ) +#ifndef NOTETOMIC + if (swap->I.bobtomic[0] != 0 || swap->I.alicetomic[0] != 0) { + uint64_t eth_balance = getEthBalance(swap->I.etomicsrc); + if (eth_balance < 500000) { + err = -5000, printf("Bob ETH balance too low, aborting swap!\n"); + } + } +#endif + + if ( swap != 0 && err == 0) { if ( LP_waitsend("pubkeys",120,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) err = -2000, printf("error waitsend pubkeys\n"); @@ -948,7 +957,17 @@ void LP_aliceloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; bobwaittimeout = LP_calc_waittimeout(bobstr); alicewaittimeout = LP_calc_waittimeout(alicestr); - if ( swap != 0 ) + +#ifndef NOTETOMIC + if (swap->I.bobtomic[0] != 0 || swap->I.alicetomic[0] != 0) { + uint64_t eth_balance = getEthBalance(swap->I.etomicdest); + if (eth_balance < 500000) { + err = -5001, printf("Alice ETH balance too low, aborting swap!\n"); + } + } +#endif + + if ( swap != 0 && err == 0) { printf("start swap iamalice pair.%d\n",swap->N.pair); if ( LP_sendwait("pubkeys",120,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) @@ -1179,6 +1198,16 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 free(swap); return(0); } +#ifndef NOTETOMIC + if (strcmp(alicestr, "ETOMIC") == 0) { + swap->I.alicerealsat = swap->I.alicesatoshis; + swap->I.alicesatoshis = 100000000; + } + if (strcmp(bobstr, "ETOMIC") == 0) { + swap->I.bobrealsat = swap->I.bobsatoshis; + swap->I.bobsatoshis = 100000000; + } +#endif if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE ) swap->I.bobinsurance = LP_MIN_TXFEE; if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d2deaf3d4..ef27a86a0 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -2046,31 +2046,107 @@ char *LP_movecoinbases(char *symbol) #ifndef NOTETOMIC +char *LP_eth_tx_fee(struct iguana_info *coin, char *dest_addr, char *amount, int64_t gas, int64_t gas_price) +{ + bits256 privkey; + cJSON *retjson = cJSON_CreateObject(); + int64_t actual_gas_price = 0, actual_gas = 0; + char privkey_str[70]; + + if (gas_price > 0) { + actual_gas_price = gas_price; + } else { + actual_gas_price = getGasPriceFromStation(0); + if (actual_gas_price == 0) { + return (clonestr("{\"error\":\"Couldn't get gas price from station!\"}")); + } + } + cJSON_AddNumberToObject(retjson, "gas_price", actual_gas_price); + + if (gas > 0) { + actual_gas = gas; + } else if (strcmp(coin->symbol, "ETH") == 0) { + actual_gas = 21000; + } else { + privkey = LP_privkey(coin->symbol, coin->smartaddr, coin->taddr); + uint8arrayToHex(privkey_str, privkey.bytes, 32); + actual_gas = estimate_erc20_gas(coin->etomic, dest_addr, amount, privkey_str, coin->decimals); + if (actual_gas == 0) { + return (clonestr("{\"error\":\"Couldn't estimate erc20 transfer gas usage!\"}")); + } + } + cJSON_AddNumberToObject(retjson, "gas", actual_gas); + + double_t eth_fee = (actual_gas_price * actual_gas) / 1000000000.0; + cJSON_AddNumberToObject(retjson, "eth_fee", eth_fee); + return(jprint(retjson,1)); +} + char *LP_eth_withdraw(struct iguana_info *coin,cJSON *argjson) { cJSON *retjson = cJSON_CreateObject(); + cJSON *gas_json = cJSON_GetObjectItem(argjson, "gas"); + cJSON *gas_price_json = cJSON_GetObjectItem(argjson, "gas_price"); char *dest_addr, *tx_id, privkey_str[70], amount_str[100]; - int64_t amount; + int64_t amount = 0, gas = 0, gas_price = 0, broadcast = 0; bits256 privkey; dest_addr = jstr(argjson, "to"); + if (dest_addr == NULL) { + return(clonestr("{\"error\":\"param 'to' is required!\"}")); + } amount = jdouble(argjson, "amount") * 100000000; - privkey = LP_privkey(coin->symbol, coin->smartaddr, coin->taddr); - uint8arrayToHex(privkey_str, privkey.bytes, 32); + if (amount == 0) { + return(clonestr("{\"error\":\"'amount' is not set or equal to zero!\"}")); + } + if (gas_json != NULL && is_cJSON_Number(gas_json)) { + gas = gas_json->valueint; + if (gas < 21000) { + return (clonestr("{\"error\":\"'gas' can't be lower than 21000!\"}")); + } + } + if (gas_price_json != NULL && is_cJSON_Number(gas_price_json)) { + gas_price = gas_price_json->valueint; + if (gas_price < 1) { + return (clonestr("{\"error\":\"'gas_price' can't be lower than 1!\"}")); + } + } + + broadcast = jint(argjson, "broadcast"); satoshisToWei(amount_str, amount); - if (strcmp(coin->symbol, "ETH") == 0) { - tx_id = sendEth(dest_addr, amount_str, privkey_str, 0); + if (broadcast == 1) { + privkey = LP_privkey(coin->symbol, coin->smartaddr, coin->taddr); + uint8arrayToHex(privkey_str, privkey.bytes, 32); + if (strcmp(coin->symbol, "ETH") == 0) { + tx_id = sendEth(dest_addr, amount_str, privkey_str, 0, gas, gas_price, 0); + } else { + tx_id = sendErc20(coin->etomic, dest_addr, amount_str, privkey_str, 0, gas, gas_price, 0, coin->decimals); + } + if (tx_id != NULL) { + jaddstr(retjson, "tx_id", tx_id); + free(tx_id); + } else { + jaddstr(retjson, "error", "Error sending transaction"); + } + return (jprint(retjson, 1)); } else { - tx_id = sendErc20(coin->etomic, dest_addr, amount_str, privkey_str, 0); + return LP_eth_tx_fee(coin, dest_addr, amount_str, gas, gas_price); } - jaddstr(retjson, "tx_id", tx_id); - return(jprint(retjson,1)); } +char *LP_eth_gas_price() +{ + cJSON *retjson = cJSON_CreateObject(); + uint64_t gas_price = getGasPriceFromStation(0); + if (gas_price > 0) { + cJSON_AddNumberToObject(retjson, "gas_price", gas_price); + } else { + cJSON_AddStringToObject(retjson, "error", "Could not get gas price from station!"); + } + return(jprint(retjson,1)); +} #endif - - int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) { struct iguana_info *coin; int32_t len,retval=-1; char *retstr,*hexstr; cJSON *argjson,*outputs,*item,*retjson,*obj; diff --git a/iguana/exchanges/etomicswap/etomiccurl.c b/iguana/exchanges/etomicswap/etomiccurl.c index e7f1296ee..c6a493f33 100644 --- a/iguana/exchanges/etomicswap/etomiccurl.c +++ b/iguana/exchanges/etomicswap/etomiccurl.c @@ -1,7 +1,6 @@ #include "etomiccurl.h" #include -static char *ethRpcUrl = ETOMIC_URL; pthread_mutex_t sendTxMutex = PTHREAD_MUTEX_INITIALIZER; struct string { @@ -36,10 +35,9 @@ size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s) cJSON *parseEthRpcResponse(char *requestResult) { - printf("Trying to parse ETH RPC response: %s\n", requestResult); cJSON *json = cJSON_Parse(requestResult); if (json == NULL) { - printf("ETH RPC response parse failed!\n"); + printf("ETH RPC response parse failed: %s!\n", requestResult); return NULL; } cJSON *tmp = cJSON_GetObjectItem(json, "result"); @@ -56,7 +54,7 @@ cJSON *parseEthRpcResponse(char *requestResult) return result; } -char* sendRequest(char* request) +char* sendRequest(char *request, char *url) { CURL *curl; CURLcode res; @@ -72,13 +70,15 @@ char* sendRequest(char* request) curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); - curl_easy_setopt(curl, CURLOPT_URL, ethRpcUrl); + curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + curl_easy_cleanup(curl); + return NULL; } /* always cleanup */ @@ -98,7 +98,7 @@ cJSON *sendRpcRequest(char *method, cJSON *params) cJSON_AddItemToObject(request, "params", cJSON_Duplicate(params, 1)); cJSON_AddNumberToObject(request, "id", 1); string = cJSON_PrintUnformatted(request); - char* requestResult = sendRequest(string); + char* requestResult = sendRequest(string, ETOMIC_URL); free(string); cJSON_Delete(request); cJSON *result = parseEthRpcResponse(requestResult); @@ -151,8 +151,8 @@ char* sendRawTx(char* rawTx) int64_t getNonce(char* address) { - // we should lock this mutex and unlock it only when transaction was already sent. - // make sure that sendRawTx is called after getting a nonce! + // we should lock this mutex and unlock it only when transaction was already sent or failed. + // make sure that sendRawTx or unlock_send_tx_mutex is called after getting a nonce! if (pthread_mutex_lock(&sendTxMutex) != 0) { printf("Nonce mutex lock failed\n"); }; @@ -186,7 +186,7 @@ char* getEthBalanceRequest(char* address) return balance; } -char* ethCall(char* to, const char* data) +char *ethCall(char *to, const char *data) { cJSON *params = cJSON_CreateArray(); cJSON *txObject = cJSON_CreateObject(); @@ -196,7 +196,7 @@ char* ethCall(char* to, const char* data) cJSON_AddItemToArray(params, cJSON_CreateString("latest")); cJSON *resultJson = sendRpcRequest("eth_call", params); cJSON_Delete(params); - char* result = NULL; + char *result = NULL; if (resultJson != NULL && is_cJSON_String(resultJson) && resultJson->valuestring != NULL) { result = (char *) malloc(strlen(resultJson->valuestring) + 1); strcpy(result, resultJson->valuestring); @@ -205,6 +205,26 @@ char* ethCall(char* to, const char* data) return result; } +uint64_t estimateGas(char *from, char *to, const char *data) +{ + cJSON *params = cJSON_CreateArray(); + cJSON *txObject = cJSON_CreateObject(); + cJSON_AddStringToObject(txObject, "from", from); + cJSON_AddStringToObject(txObject, "to", to); + cJSON_AddStringToObject(txObject, "data", data); + cJSON_AddItemToArray(params, txObject); + cJSON_AddItemToArray(params, cJSON_CreateString("latest")); + cJSON *resultJson = sendRpcRequest("eth_estimateGas", params); + cJSON_Delete(params); + uint64_t result = 0; + if (resultJson != NULL && is_cJSON_String(resultJson) && resultJson->valuestring != NULL) { + result = (uint64_t)strtoul(resultJson->valuestring, NULL, 0); + result = (result / 100) * 120; // add 20% because real gas usage might differ from estimate + } + cJSON_Delete(resultJson); + return result; +} + EthTxReceipt getEthTxReceipt(char *txId) { EthTxReceipt result; @@ -265,7 +285,7 @@ EthTxData getEthTxData(char *txId) return result; } -uint64_t getGasPriceFromStation() +uint64_t getGasPriceFromStation(uint8_t defaultOnErr) { CURL *curl; CURLcode res; @@ -283,6 +303,12 @@ uint64_t getGasPriceFromStation() curl_easy_setopt(curl, CURLOPT_URL, "https://ethgasstation.info/json/ethgasAPI.json"); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); + uint64_t result; + if (defaultOnErr == 1) { + result = DEFAULT_GAS_PRICE; + } else { + result = 0; + } /* Check for errors */ if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); @@ -292,9 +318,9 @@ uint64_t getGasPriceFromStation() /* always cleanup */ curl_easy_cleanup(curl); cJSON *resultJson = cJSON_Parse(s.ptr); - uint64_t result = DEFAULT_GAS_PRICE; free(s.ptr); if (resultJson == NULL) { + printf("Could not parse gas station response!\n"); return result; } @@ -342,3 +368,41 @@ int32_t waitForConfirmation(char *txId) return((int32_t)receipt.confirmations); } + +void unlock_send_tx_mutex() +{ + pthread_mutex_unlock(&sendTxMutex); +} + +uint8_t get_etomic_from_faucet(char *eth_addr, char *etomic_addr) +{ + char* string; + cJSON *request = cJSON_CreateObject(); + cJSON_AddStringToObject(request, "ethAddress", eth_addr); + cJSON_AddStringToObject(request, "etomicAddress", etomic_addr); + string = cJSON_PrintUnformatted(request); + char* requestResult = sendRequest(string, FAUCET_URL); + free(string); + cJSON_Delete(request); + + if (requestResult == NULL) { + return 0; + } + + cJSON *json = cJSON_Parse(requestResult); + if (json == NULL) { + printf("ETOMIC faucet response parse failed!\n"); + return 0; + } + cJSON *error = cJSON_GetObjectItem(json, "error"); + uint8_t result = 0; + if (error != NULL && !is_cJSON_Null(error)) { + char *errorString = cJSON_PrintUnformatted(error); + printf("Got ETOMIC faucet error: %s\n", errorString); + free(errorString); + } else { + result = 1; + } + cJSON_Delete(json); + return result; +} diff --git a/iguana/exchanges/etomicswap/etomiccurl.h b/iguana/exchanges/etomicswap/etomiccurl.h index c0433bc75..6e5036739 100644 --- a/iguana/exchanges/etomicswap/etomiccurl.h +++ b/iguana/exchanges/etomicswap/etomiccurl.h @@ -16,9 +16,11 @@ extern "C"{ #define DEFAULT_GAS_PRICE 100 #else #define ETOMIC_URL "http://195.201.0.6:8555" -#define DEFAULT_GAS_PRICE 4 +#define DEFAULT_GAS_PRICE 10 #endif +#define FAUCET_URL "http://195.201.116.176:8000/getEtomic" + typedef struct { uint64_t blockNumber; @@ -39,13 +41,16 @@ typedef struct char* sendRawTx(char* rawTx); char* sendRawTxWaitConfirm(char* rawTx); char* ethCall(char* to, const char* data); +uint64_t estimateGas(char *from, char *to, const char *data); int64_t getNonce(char* address); char* getEthBalanceRequest(char* address); EthTxReceipt getEthTxReceipt(char *txId); EthTxData getEthTxData(char *txId); uint64_t getEthBlockNumber(); -uint64_t getGasPriceFromStation(); +uint64_t getGasPriceFromStation(uint8_t defaultOnErr); int32_t waitForConfirmation(char *txId); +void unlock_send_tx_mutex(); +uint8_t get_etomic_from_faucet(char *eth_addr, char *etomic_addr); #ifdef __cplusplus } diff --git a/iguana/exchanges/etomicswap/etomiclib.cpp b/iguana/exchanges/etomicswap/etomiclib.cpp index 204848477..b1bcbe7c1 100644 --- a/iguana/exchanges/etomicswap/etomiclib.cpp +++ b/iguana/exchanges/etomicswap/etomiclib.cpp @@ -27,18 +27,18 @@ TransactionSkeleton txDataToSkeleton(BasicTxData txData) tx.to = jsToAddress(txData.to); tx.value = jsToU256(txData.amount); tx.gas = 200000; - tx.gasPrice = getGasPriceFromStation() * boost::multiprecision::pow(u256(10), 9); + tx.gasPrice = getGasPriceFromStation(1) * boost::multiprecision::pow(u256(10), 9); tx.nonce = getNonce(txData.from); return tx; } char *signTx(TransactionSkeleton& tx, char* secret) { - Secret& secretKey = *(new Secret(secret)); - auto baseTx = new TransactionBase(tx, secretKey); - RLPStream& rlpStream = *(new RLPStream()); - baseTx->streamRLP(rlpStream); - std::stringstream& ss = *(new std::stringstream); + Secret secretKey(secret); + TransactionBase baseTx(tx, secretKey); + RLPStream rlpStream; + baseTx.streamRLP(rlpStream); + std::stringstream ss; ss << rlpStream.out(); return stringStreamToChar(ss); } @@ -50,7 +50,7 @@ char *approveErc20(ApproveErc20Input input) tx.to = jsToAddress(input.tokenAddress); tx.value = 0; tx.gas = 300000; - tx.gasPrice = getGasPriceFromStation() * boost::multiprecision::pow(u256(10), 9); + tx.gasPrice = getGasPriceFromStation(1) * boost::multiprecision::pow(u256(10), 9); tx.nonce = getNonce(input.owner); std::stringstream ss; ss << "0x095ea7b3" @@ -101,7 +101,12 @@ uint8_t verifyAliceEthPaymentData(AliceSendsEthPaymentInput input, char *data) std::stringstream aliceSendsErc20PaymentData(AliceSendsErc20PaymentInput input) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } u256 amount = jsToU256(input.amount); if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); @@ -148,12 +153,20 @@ char* aliceReclaimsAlicePayment(AliceReclaimsAlicePaymentInput input, BasicTxDat std::stringstream ss; u256 amount = jsToU256(input.amount); dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } } + ss << "0x8b9a167a" << toHex(jsToBytes(input.dealId)) << toHex(toBigEndian(amount)) @@ -179,12 +192,20 @@ char* bobSpendsAlicePayment(BobSpendsAlicePaymentInput input, BasicTxData txData std::stringstream ss; u256 amount = jsToU256(input.amount); dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } } + ss << "0x392ec66b" << toHex(jsToBytes(input.dealId)) << toHex(toBigEndian(amount)) @@ -241,7 +262,13 @@ uint8_t verifyBobEthDepositData(BobSendsEthDepositInput input, char *data) std::stringstream bobSendsErc20DepositData(BobSendsErc20DepositInput input) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + u256 amount = jsToU256(input.amount); u256 lockTime = input.lockTime; if (decimals < 18) { @@ -289,7 +316,13 @@ char* bobRefundsDeposit(BobRefundsDepositInput input, BasicTxData txData) u256 amount = jsToU256(input.amount); dev::Address tokenAddress = jsToAddress(input.tokenAddress); if (tokenAddress != ZeroAddress) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } @@ -316,7 +349,13 @@ char* aliceClaimsBobDeposit(AliceClaimsBobDepositInput input, BasicTxData txData u256 amount = jsToU256(input.amount); dev::Address tokenAddress = jsToAddress(input.tokenAddress); if (tokenAddress != ZeroAddress) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } @@ -374,9 +413,15 @@ uint8_t verifyBobEthPaymentData(BobSendsEthPaymentInput input, char *data) std::stringstream bobSendsErc20PaymentData(BobSendsErc20PaymentInput input) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); u256 amount = jsToU256(input.amount); u256 lockTime = input.lockTime; + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } @@ -422,7 +467,13 @@ char* bobReclaimsBobPayment(BobReclaimsBobPaymentInput input, BasicTxData txData u256 amount = jsToU256(input.amount); dev::Address tokenAddress = jsToAddress(input.tokenAddress); if (tokenAddress != ZeroAddress) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } @@ -450,7 +501,13 @@ char* aliceSpendsBobPayment(AliceSpendsBobPaymentInput input, BasicTxData txData u256 amount = jsToU256(input.amount); dev::Address tokenAddress = jsToAddress(input.tokenAddress); if (tokenAddress != ZeroAddress) { - uint8_t decimals = getErc20Decimals(input.tokenAddress); + uint8_t decimals; + if (input.decimals > 0) { + decimals = input.decimals; + } else { + decimals = getErc20Decimals(input.tokenAddress); + } + if (decimals < 18) { amount /= boost::multiprecision::pow(u256(10), 18 - decimals); } @@ -472,24 +529,24 @@ char* aliceSpendsBobPayment(AliceSpendsBobPaymentInput input, BasicTxData txData char* privKey2Addr(char* privKey) { - Secret& secretKey = *(new Secret(privKey)); - std::stringstream& ss = *(new std::stringstream); + Secret secretKey(privKey); + std::stringstream ss; ss << "0x" << toAddress(secretKey); return stringStreamToChar(ss); }; char* pubKey2Addr(char* pubKey) { - Public& publicKey = *(new Public(pubKey)); - std::stringstream& ss = *(new std::stringstream); + Public publicKey(pubKey); + std::stringstream ss; ss << "0x" << toAddress(publicKey); return stringStreamToChar(ss); }; char* getPubKeyFromPriv(char* privKey) { - Public publicKey = toPublic(*(new Secret(privKey))); - std::stringstream& ss = *(new std::stringstream); + Public publicKey = toPublic(Secret(privKey)); + std::stringstream ss; ss << "0x" << publicKey; return stringStreamToChar(ss); } @@ -497,29 +554,42 @@ char* getPubKeyFromPriv(char* privKey) uint64_t getEthBalance(char* address) { char* hexBalance = getEthBalanceRequest(address); - // convert wei to satoshi - u256 balance = jsToU256(hexBalance) / boost::multiprecision::pow(u256(10), 10); - free(hexBalance); - return static_cast(balance); + if (hexBalance != NULL) { + // convert wei to satoshi + u256 balance = jsToU256(hexBalance) / boost::multiprecision::pow(u256(10), 10); + free(hexBalance); + return static_cast(balance); + } else { + return 0; + } } -uint64_t getErc20BalanceSatoshi(char *address, char *tokenAddress) +uint64_t getErc20BalanceSatoshi(char *address, char *tokenAddress, uint8_t setDecimals) { std::stringstream ss; ss << "0x70a08231" << "000000000000000000000000" << toHex(jsToAddress(address)); - std::stringstream& resultStream = *(new std::stringstream); char* hexBalance = ethCall(tokenAddress, ss.str().c_str()); // convert wei to satoshi - uint8_t decimals = getErc20Decimals(tokenAddress); - u256 balance = jsToU256(hexBalance); - if (decimals < 18) { - balance *= boost::multiprecision::pow(u256(10), 18 - decimals); + uint8_t decimals; + if (hexBalance != NULL) { + if (setDecimals > 0) { + decimals = setDecimals; + } else { + decimals = getErc20Decimals(tokenAddress); + } + + u256 balance = jsToU256(hexBalance); + if (decimals < 18) { + balance *= boost::multiprecision::pow(u256(10), 18 - decimals); + } + balance /= boost::multiprecision::pow(u256(10), 10); + free(hexBalance); + return static_cast(balance); + } else { + return 0; } - balance /= boost::multiprecision::pow(u256(10), 10); - free(hexBalance); - return static_cast(balance); } char *getErc20BalanceHexWei(char *address, char *tokenAddress) @@ -532,7 +602,7 @@ char *getErc20BalanceHexWei(char *address, char *tokenAddress) return hexBalance; } -uint64_t getErc20Allowance(char *owner, char *spender, char *tokenAddress) +uint64_t getErc20Allowance(char *owner, char *spender, char *tokenAddress, uint8_t set_decimals) { std::stringstream ss; ss << "0xdd62ed3e" @@ -541,7 +611,12 @@ uint64_t getErc20Allowance(char *owner, char *spender, char *tokenAddress) << "000000000000000000000000" << toHex(jsToAddress(spender)); char* hexAllowance = ethCall(tokenAddress, ss.str().c_str()); - uint8_t decimals = getErc20Decimals(tokenAddress); + uint8_t decimals; + if (set_decimals > 0) { + decimals = set_decimals; + } else { + decimals = getErc20Decimals(tokenAddress); + } u256 allowance = jsToU256(hexAllowance); if (decimals < 18) { allowance *= boost::multiprecision::pow(u256(10), 18 - decimals); @@ -582,17 +657,30 @@ uint64_t weiToSatoshi(char *wei) return static_cast(satoshi); } -char *sendEth(char *to, char *amount, char *privKey, uint8_t waitConfirm) +char *sendEth(char *to, char *amount, char *privKey, uint8_t waitConfirm, int64_t gas, int64_t gasPrice, uint8_t defaultGasOnErr) { TransactionSkeleton tx; char *from = privKey2Addr(privKey), *result; tx.from = jsToAddress(from); tx.to = jsToAddress(to); tx.value = jsToU256(amount); - tx.gas = 21000; - tx.gasPrice = getGasPriceFromStation() * boost::multiprecision::pow(u256(10), 9); tx.nonce = getNonce(from); free(from); + if (gas > 0) { + tx.gas = gas; + } else { + tx.gas = 21000; + } + if (gasPrice > 0) { + tx.gasPrice = gasPrice * boost::multiprecision::pow(u256(10), 9); + } else { + tx.gasPrice = getGasPriceFromStation(defaultGasOnErr) * boost::multiprecision::pow(u256(10), 9); + if (tx.gasPrice == 0 && !defaultGasOnErr) { + printf("Could not get gas price from station!\n"); + unlock_send_tx_mutex(); + return NULL; + } + } char *rawTx = signTx(tx, privKey); if (waitConfirm == 0) { @@ -604,10 +692,15 @@ char *sendEth(char *to, char *amount, char *privKey, uint8_t waitConfirm) return result; } -std::stringstream getErc20TransferData(char *tokenAddress, char *to, char *amount) +std::stringstream getErc20TransferData(char *tokenAddress, char *to, char *amount, uint8_t setDecimals) { u256 amountWei = jsToU256(amount); - uint8_t decimals = getErc20Decimals(tokenAddress); + uint8_t decimals; + if (setDecimals > 0) { + decimals = setDecimals; + } else { + decimals = getErc20Decimals(tokenAddress); + } if (decimals < 18) { amountWei /= boost::multiprecision::pow(u256(10), 18 - decimals); } @@ -620,19 +713,64 @@ std::stringstream getErc20TransferData(char *tokenAddress, char *to, char *amoun return ss; } -char *sendErc20(char *tokenAddress, char *to, char *amount, char *privKey, uint8_t waitConfirm) +uint64_t estimate_erc20_gas( + char *tokenAddress, + char *to, + char *amount, + char *privKey, + uint8_t decimals +) +{ + std::stringstream ss = getErc20TransferData(tokenAddress, to, amount, decimals); + char *from = privKey2Addr(privKey); + uint64_t result = estimateGas(from, tokenAddress, ss.str().c_str()); + free(from); + return result; +} + +char *sendErc20( + char *tokenAddress, + char *to, + char *amount, + char *privKey, + uint8_t waitConfirm, + int64_t gas, + int64_t gasPrice, + uint8_t defaultGasOnErr, + uint8_t decimals +) { TransactionSkeleton tx; char *from = privKey2Addr(privKey), *result; + std::stringstream ss = getErc20TransferData(tokenAddress, to, amount, decimals); + tx.from = jsToAddress(from); tx.to = jsToAddress(tokenAddress); tx.value = 0; - tx.gas = 60000; - tx.gasPrice = getGasPriceFromStation() * boost::multiprecision::pow(u256(10), 9); tx.nonce = getNonce(from); + + if (gas > 0) { + tx.gas = gas; + } else { + uint64_t gasEstimation = estimateGas(from, tokenAddress, ss.str().c_str()); + if (gasEstimation > 0) { + tx.gas = gasEstimation; + } else { + tx.gas = 150000; + } + } free(from); + if (gasPrice > 0) { + tx.gasPrice = gasPrice * boost::multiprecision::pow(u256(10), 9); + } else { + tx.gasPrice = getGasPriceFromStation(defaultGasOnErr) * boost::multiprecision::pow(u256(10), 9); + if (tx.gasPrice == 0 && !defaultGasOnErr) { + printf("Could not get gas price from station!\n"); + unlock_send_tx_mutex(); + return NULL; + } + } - std::stringstream ss = getErc20TransferData(tokenAddress, to, amount); tx.data = jsToBytes(ss.str()); char *rawTx = signTx(tx, privKey); @@ -645,12 +783,48 @@ char *sendErc20(char *tokenAddress, char *to, char *amount, char *privKey, uint8 return result; } -uint8_t verifyAliceErc20FeeData(char* tokenAddress, char *to, char *amount, char *data) +uint8_t verifyAliceErc20FeeData(char *tokenAddress, char *to, char *amount, char *data, uint8_t decimals) { - std::stringstream ss = getErc20TransferData(tokenAddress, to, amount); + std::stringstream ss = getErc20TransferData(tokenAddress, to, amount, decimals); if (strcmp(ss.str().c_str(), data) != 0) { printf("Alice ERC20 fee data %s is not equal to expected %s\n", data, ss.str().c_str()); return 0; } return 1; } + +uint8_t alicePaymentStatus(char *paymentId) +{ + char buffer[100]; + memset(buffer, 0, sizeof(buffer)); + strcpy(buffer, "0x81cd872a"); + strcat(buffer, paymentId); + char *hexStatus = ethCall(ETOMIC_ALICECONTRACT, buffer); + auto status = (uint8_t) strtol(hexStatus + 66, NULL, 0); + free(hexStatus); + return status; +} + +uint8_t bobDepositStatus(char *depositId) +{ + char buffer[100]; + memset(buffer, 0, sizeof(buffer)); + strcpy(buffer, "0x3d4dff7b"); + strcat(buffer, depositId); + char *hexStatus = ethCall(ETOMIC_BOBCONTRACT, buffer); + auto status = (uint8_t) strtol(hexStatus + 130, NULL, 0); + free(hexStatus); + return status; +} + +uint8_t bobPaymentStatus(char *paymentId) +{ + char buffer[100]; + memset(buffer, 0, sizeof(buffer)); + strcpy(buffer, "0x0716326d"); + strcat(buffer, paymentId); + char *hexStatus = ethCall(ETOMIC_BOBCONTRACT, buffer); + auto status = (uint8_t) strtol(hexStatus + 130, NULL, 0); + free(hexStatus); + return status; +} diff --git a/iguana/exchanges/etomicswap/etomiclib.h b/iguana/exchanges/etomicswap/etomiclib.h index c7b846ddb..db1547f4e 100644 --- a/iguana/exchanges/etomicswap/etomiclib.h +++ b/iguana/exchanges/etomicswap/etomiclib.h @@ -38,6 +38,7 @@ typedef struct { char bobAddress[65]; char aliceHash[65]; char bobHash[65]; + uint8_t decimals; } AliceSendsErc20PaymentInput; typedef struct { @@ -47,6 +48,7 @@ typedef struct { char bobAddress[65]; char aliceHash[65]; char bobSecret[70]; + uint8_t decimals; } AliceReclaimsAlicePaymentInput; typedef struct { @@ -56,6 +58,7 @@ typedef struct { char aliceAddress[65]; char aliceSecret[70]; char bobHash[65]; + uint8_t decimals; } BobSpendsAlicePaymentInput; typedef struct { @@ -72,6 +75,7 @@ typedef struct { char aliceAddress[65]; char bobHash[65]; uint64_t lockTime; + uint8_t decimals; } BobSendsErc20DepositInput; typedef struct { @@ -80,6 +84,7 @@ typedef struct { char tokenAddress[65]; char aliceAddress[65]; char bobSecret[70]; + uint8_t decimals; } BobRefundsDepositInput; typedef struct { @@ -88,6 +93,7 @@ typedef struct { char tokenAddress[65]; char bobAddress[65]; char bobHash[65]; + uint8_t decimals; } AliceClaimsBobDepositInput; typedef struct { @@ -104,6 +110,7 @@ typedef struct { char aliceAddress[65]; char aliceHash[65]; uint64_t lockTime; + uint8_t decimals; } BobSendsErc20PaymentInput; typedef struct { @@ -112,6 +119,7 @@ typedef struct { char tokenAddress[65]; char aliceAddress[65]; char aliceHash[65]; + uint8_t decimals; } BobReclaimsBobPaymentInput; typedef struct { @@ -120,6 +128,7 @@ typedef struct { char tokenAddress[65]; char aliceSecret[70]; char bobAddress[65]; + uint8_t decimals; } AliceSpendsBobPaymentInput; typedef struct { @@ -165,23 +174,45 @@ char* getPubKeyFromPriv(char* privKey); // returns satoshis, not wei! uint64_t getEthBalance(char* address); -uint64_t getErc20BalanceSatoshi(char* address, char tokenAddress[65]); +uint64_t getErc20BalanceSatoshi(char *address, char *tokenAddress, uint8_t setDecimals); char *getErc20BalanceHexWei(char* address, char tokenAddress[65]); uint8_t getErc20Decimals(char *tokenAddress); // returns satoshis, not wei! -uint64_t getErc20Allowance(char *owner, char *spender, char *tokenAddress); +uint64_t getErc20Allowance(char *owner, char *spender, char *tokenAddress, uint8_t set_decimals); void uint8arrayToHex(char *dest, uint8_t *input, int len); void satoshisToWei(char *dest, uint64_t input); uint64_t weiToSatoshi(char *wei); -char *sendEth(char *to, char *amount, char *privKey, uint8_t waitConfirm); -char *sendErc20(char *tokenAddress, char *to, char *amount, char *privKey, uint8_t waitConfirm); +char *sendEth(char *to, char *amount, char *privKey, uint8_t waitConfirm, int64_t gas, int64_t gasPrice, uint8_t defaultGasOnErr); +char *sendErc20( + char *tokenAddress, + char *to, + char *amount, + char *privKey, + uint8_t waitConfirm, + int64_t gas, + int64_t gasPrice, + uint8_t defaultGasOnErr, + uint8_t decimals +); + +uint8_t verifyAliceErc20FeeData(char* tokenAddress, char *to, char *amount, char *data, uint8_t decimals); + +uint8_t alicePaymentStatus(char *paymentId); +uint8_t bobDepositStatus(char *depositId); +uint8_t bobPaymentStatus(char *paymentId); + +uint64_t estimate_erc20_gas( + char *tokenAddress, + char *to, + char *amount, + char *privKey, + uint8_t decimals +); -uint8_t verifyAliceErc20FeeData(char* tokenAddress, char *to, char *amount, char *data); -// Your prototype or Definition #ifdef __cplusplus } #endif diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index aa0866b07..8e86139cf 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -164,6 +164,7 @@ int main(int argc, const char * argv[]) { char dirname[512]; double incr; cJSON *retjson; OS_init(); + printf("BarterDEX Marketmaker %s \n",MM_VERSION); if ( strstr(argv[0],"btc2kmd") != 0 && argv[1] != 0 ) { bits256 privkey,checkkey; uint8_t tmptype; char kmdwif[64],str[65],str2[65],*retstr; diff --git a/marketmaker_build_depends.cmd b/marketmaker_build_depends.cmd index a09e0ea04..6a294d20c 100644 --- a/marketmaker_build_depends.cmd +++ b/marketmaker_build_depends.cmd @@ -36,54 +36,66 @@ exit rem MSBuild /help echo. echo Decker will automatically download and build all needed *.dll and *.lib for you ;) -timeout /t 5 /nobreak mkdir marketmaker_depends mkdir x64\Release rem --- pthreads --- :compile_pthreads +if not exist marketmaker_depends\pthread-win32\bin\x64_MSVC2015.Release\pthread_lib.lib ( cd marketmaker_depends git clone https://github.com/DeckerSU/pthread-win32 cd pthread-win32 MSBuild pthread.2015.sln /t:Rebuild /p:Configuration=Release /p:Platform=Win32 MSBuild pthread.2015.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64 cd ../.. +) copy marketmaker_depends\pthread-win32\bin\x64_MSVC2015.Release\pthread_lib.lib OSlibs\win\x64\pthread_lib.lib rem --- nanomsg --- :compile_nanomsg - -cd marketmaker_depends -git clone https://github.com/nanomsg/nanomsg -cd nanomsg -mkdir build_msvc_2015_win32 -mkdir build_msvc_2015_win64 -cd build_msvc_2015_win64 -cmake -G "Visual Studio 14 2015 Win64" .. -cmake --build . --config Release --target nanomsg -cd ../../.. +if not exist marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.lib ( + if not exist marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.exp ( + if not exist marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.dll ( + cd marketmaker_depends + git clone https://github.com/nanomsg/nanomsg + cd nanomsg + mkdir build_msvc_2015_win32 + mkdir build_msvc_2015_win64 + cd build_msvc_2015_win64 + cmake -G "Visual Studio 14 2015 Win64" .. + cmake --build . --config Release --target nanomsg + cd ../../.. + ) + ) +) copy marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.lib OSlibs\win\x64\release\nanomsg.lib copy marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.exp OSlibs\win\x64\release\nanomsg.exp copy marketmaker_depends\nanomsg\build_msvc_2015_win64\Release\nanomsg.dll x64\Release\nanomsg.dll rem --- curl --- :compile_curl -cd marketmaker_depends -git clone https://github.com/curl/curl -cd curl -mkdir build_msvc_2015_win32 -mkdir build_msvc_2015_win64 -cd build_msvc_2015_win64 -cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_USE_WINSSL:BOOL=ON .. -cmake --build . --config Release --target libcurl +if not exist marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl_imp.lib ( + if not exist marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl_imp.exp ( + if not exist marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl.dll ( + cd marketmaker_depends + git clone https://github.com/curl/curl + cd curl + mkdir build_msvc_2015_win32 + mkdir build_msvc_2015_win64 + cd build_msvc_2015_win64 + cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_USE_WINSSL:BOOL=ON .. + cmake --build . --config Release --target libcurl -rem cmake .. -G"Visual Studio 14 2015 Win64" -DCURL_STATICLIB=ON -DCURL_DISABLE_LDAP=ON -DCURL_STATIC_CRT=ON -rem cmake .. -G"Visual Studio 14 2015 Win64" -DCURL_STATICLIB:BOOL=ON -DCURL_STATIC_CRT:BOOL=ON -DHTTP_ONLY:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=RELEASE .. -rem cmake --build . --config Release -rem cmake --build . --config Release --target libcurl + rem cmake .. -G"Visual Studio 14 2015 Win64" -DCURL_STATICLIB=ON -DCURL_DISABLE_LDAP=ON -DCURL_STATIC_CRT=ON + rem cmake .. -G"Visual Studio 14 2015 Win64" -DCURL_STATICLIB:BOOL=ON -DCURL_STATIC_CRT:BOOL=ON -DHTTP_ONLY:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=RELEASE .. + rem cmake --build . --config Release + rem cmake --build . --config Release --target libcurl -cd ../../.. + cd ../../.. + ) + ) +) copy marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl_imp.lib OSlibs\win\x64\release\libcurl.lib copy marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl_imp.exp OSlibs\win\x64\release\libcurl.exp copy marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl.dll x64\Release\libcurl.dll \ No newline at end of file diff --git a/marketmaker_build_etomic.cmd b/marketmaker_build_etomic.cmd index ed76db72c..2b8f9a02d 100644 --- a/marketmaker_build_etomic.cmd +++ b/marketmaker_build_etomic.cmd @@ -7,16 +7,13 @@ copy marketmaker_depends\curl\build_msvc_2015_win64\lib\Release\libcurl_imp.lib copy marketmaker_depends\pthread-win32\bin\x64_MSVC2015.Release\pthread_lib.lib marketmaker_depends\pthread-win32\bin\x64_MSVC2015.Release\pthread.lib echo [#2] Prepare build etomic needed things ... -git submodule init git submodule update --init --recursive cd cpp-ethereum -rem git submodule init -rem git submodule update --init -call scripts\install_deps.bat +call scripts\install_deps.bat cd .. mkdir build_win64_release cd build_win64_release -cmake .. -G "Visual Studio 14 2015 Win64" +cmake .. -G "Visual Studio 14 2015 Win64" -DMM_VERSION="%APPVEYOR_BUILD_VERSION%" rem Steps before build: rem diff --git a/start_BEER_OTHER_trade.sh b/start_BEER_OTHER_trade.sh new file mode 100755 index 000000000..23a5acee1 --- /dev/null +++ b/start_BEER_OTHER_trade.sh @@ -0,0 +1,12 @@ +#!/bin/bash +docker-compose exec -T clientnode ./setpassphrase +sleep 5 +docker-compose exec -T clientnode ./enable +sleep 5 +docker-compose exec -T seednode ./setpassphrase +sleep 5 +docker-compose exec -T seednode ./enable +sleep 5 +docker-compose exec -T seednode ./sell_BEER_OTHER $1 +sleep 5 +docker-compose exec -T clientnode ./buy_BEER_OTHER $1 \ No newline at end of file diff --git a/start_BEER_OTHER_trade_inverted.sh b/start_BEER_OTHER_trade_inverted.sh new file mode 100755 index 000000000..68ef9ab3f --- /dev/null +++ b/start_BEER_OTHER_trade_inverted.sh @@ -0,0 +1,12 @@ +#!/bin/bash +docker-compose exec -T clientnode ./setpassphrase +sleep 5 +docker-compose exec -T clientnode ./enable +sleep 5 +docker-compose exec -T seednode ./setpassphrase +sleep 5 +docker-compose exec -T seednode ./enable +sleep 5 +docker-compose exec -T clientnode ./buy_BEER_OTHER $1 +sleep 5 +docker-compose exec -T seednode ./sell_BEER_OTHER $1 \ No newline at end of file