diff --git a/CMakeLists.txt b/CMakeLists.txt index e833ab65f..f37d6a291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5.1) +cmake_minimum_required(VERSION 3.9.6) include("cmake/HunterGate.cmake") HunterGate( URL "https://github.com/ruslo/hunter/archive/v0.19.173.tar.gz" @@ -6,6 +6,24 @@ HunterGate( LOCAL ) project(SuperNET) +set(DEPS_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_EXTENSIONS Off) + +include(cmake/DownloadProject.cmake) + +# Download and install nanomsg at CMake configure time +download_project(PROJ nanomsg + GIT_REPOSITORY https://github.com/nanomsg/nanomsg.git + GIT_TAG 1.1.2 + GIT_SHALLOW 1 + GIT_PROGRESS 1 + CMAKE_ARGS "-DNN_STATIC_LIB=ON -DNN_ENABLE_DOC=OFF -DNN_TESTS=OFF -DNN_TOOLS=OFF -DNN_ENABLE_NANOCAT=OFF -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_PREFIX}" + UPDATE_DISCONNECTED 1 + ) + +find_library(NANOMSG_LIBRARY NAMES nanomsg PATHS ${DEPS_INSTALL_PREFIX}/lib) include_directories("${CMAKE_SOURCE_DIR}") add_subdirectory(cpp-ethereum) add_subdirectory(iguana/exchanges) diff --git a/README.md b/README.md index b0577f2a1..b0c77724c 100755 --- a/README.md +++ b/README.md @@ -257,13 +257,14 @@ Execute the OSX deploy script: The iguana binary and its linked libraries are in ```$HOME/tmp/iguana```. # Cmake build of marketmaker with linked etomic lib for ETH/ERC20 atomic swaps: -0. `make sure g++-7 ln to /usr/bin/g++` +1. `make sure g++-7 ln to /usr/bin/g++` 1. `cd ~/SuperNET` -2. `git checkout dev` -3. `git submodule update --init --recursive` -4. `mkdir build` -5. `cd build` -6. `cmake ..` -7. `cmake --build . --target marketmaker` -8. `cd build/iguana/exchanges` -9. `./marketmaker` +1. `git checkout dev` +1. `git submodule update --init --recursive` +1. `mkdir build` +1. `cd build` +1. `cmake ..` +1. `cmake --build . --target marketmaker-testnet` for Ropsten Ethereum testnet. +1. `cmake --build . --target marketmaker-mainnet` for Ethereum mainnet. +1. `cd build/iguana/exchanges` +1. `./marketmaker-testnet` or `./marketmaker-mainnet` diff --git a/cmake/DownloadProject.CMakeLists.cmake.in b/cmake/DownloadProject.CMakeLists.cmake.in new file mode 100644 index 000000000..aabbbcb46 --- /dev/null +++ b/cmake/DownloadProject.CMakeLists.cmake.in @@ -0,0 +1,15 @@ +# Distributed under the OSI-approved MIT License. See accompanying +# file LICENSE or https://github.com/Crascit/DownloadProject for details. + +cmake_minimum_required(VERSION 2.8.2) + +project(${DL_ARGS_PROJ}-download NONE) + +include(ExternalProject) +ExternalProject_Add(${DL_ARGS_PROJ}-download + ${DL_ARGS_UNPARSED_ARGUMENTS} + SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" + BINARY_DIR "${DL_ARGS_BINARY_DIR}" + BUILD_COMMAND "" + TEST_COMMAND "" +) diff --git a/cmake/DownloadProject.cmake b/cmake/DownloadProject.cmake new file mode 100644 index 000000000..e300f4265 --- /dev/null +++ b/cmake/DownloadProject.cmake @@ -0,0 +1,182 @@ +# Distributed under the OSI-approved MIT License. See accompanying +# file LICENSE or https://github.com/Crascit/DownloadProject for details. +# +# MODULE: DownloadProject +# +# PROVIDES: +# download_project( PROJ projectName +# [PREFIX prefixDir] +# [DOWNLOAD_DIR downloadDir] +# [SOURCE_DIR srcDir] +# [BINARY_DIR binDir] +# [QUIET] +# ... +# ) +# +# Provides the ability to download and unpack a tarball, zip file, git repository, +# etc. at configure time (i.e. when the cmake command is run). How the downloaded +# and unpacked contents are used is up to the caller, but the motivating case is +# to download source code which can then be included directly in the build with +# add_subdirectory() after the call to download_project(). Source and build +# directories are set up with this in mind. +# +# The PROJ argument is required. The projectName value will be used to construct +# the following variables upon exit (obviously replace projectName with its actual +# value): +# +# projectName_SOURCE_DIR +# projectName_BINARY_DIR +# +# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically +# need to be provided. They can be specified if you want the downloaded source +# and build directories to be located in a specific place. The contents of +# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the +# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. +# +# The DOWNLOAD_DIR argument does not normally need to be set. It controls the +# location of the temporary CMake build used to perform the download. +# +# The PREFIX argument can be provided to change the base location of the default +# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments +# are provided, then PREFIX will have no effect. The default value for PREFIX is +# CMAKE_BINARY_DIR. +# +# The QUIET option can be given if you do not want to show the output associated +# with downloading the specified project. +# +# In addition to the above, any other options are passed through unmodified to +# ExternalProject_Add() to perform the actual download, patch and update steps. +# The following ExternalProject_Add() options are explicitly prohibited (they +# are reserved for use by the download_project() command): +# +# CONFIGURE_COMMAND +# BUILD_COMMAND +# INSTALL_COMMAND +# TEST_COMMAND +# +# Only those ExternalProject_Add() arguments which relate to downloading, patching +# and updating of the project sources are intended to be used. Also note that at +# least one set of download-related arguments are required. +# +# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to +# prevent a check at the remote end for changes every time CMake is run +# after the first successful download. See the documentation of the ExternalProject +# module for more information. It is likely you will want to use this option if it +# is available to you. Note, however, that the ExternalProject implementation contains +# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when +# using the URL download method or when specifying a SOURCE_DIR with no download +# method. Fixes for these have been created, the last of which is scheduled for +# inclusion in CMake 3.8.0. Details can be found here: +# +# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c +# https://gitlab.kitware.com/cmake/cmake/issues/16428 +# +# If you experience build errors related to the update step, consider avoiding +# the use of UPDATE_DISCONNECTED. +# +# EXAMPLE USAGE: +# +# include(DownloadProject) +# download_project(PROJ googletest +# GIT_REPOSITORY https://github.com/google/googletest.git +# GIT_TAG master +# UPDATE_DISCONNECTED 1 +# QUIET +# ) +# +# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) +# +#======================================================================================== + + +set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") + +include(CMakeParseArguments) + +function(download_project) + + set(options QUIET) + set(oneValueArgs + PROJ + PREFIX + DOWNLOAD_DIR + SOURCE_DIR + BINARY_DIR + # Prevent the following from being passed through + CONFIGURE_COMMAND + BUILD_COMMAND + INSTALL_COMMAND + TEST_COMMAND + ) + set(multiValueArgs "") + + cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Hide output if requested + if (DL_ARGS_QUIET) + set(OUTPUT_QUIET "OUTPUT_QUIET") + else() + unset(OUTPUT_QUIET) + message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") + endif() + + # Set up where we will put our temporary CMakeLists.txt file and also + # the base point below which the default source and binary dirs will be. + # The prefix must always be an absolute path. + if (NOT DL_ARGS_PREFIX) + set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") + else() + get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if (NOT DL_ARGS_DOWNLOAD_DIR) + set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") + endif() + + # Ensure the caller can know where to find the source and build directories + if (NOT DL_ARGS_SOURCE_DIR) + set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") + endif() + if (NOT DL_ARGS_BINARY_DIR) + set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") + endif() + set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) + set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) + + # The way that CLion manages multiple configurations, it causes a copy of + # the CMakeCache.txt to be copied across due to it not expecting there to + # be a project within a project. This causes the hard-coded paths in the + # cache to be copied and builds to fail. To mitigate this, we simply + # remove the cache if it exists before we configure the new project. It + # is safe to do so because it will be re-generated. Since this is only + # executed at the configure step, it should not cause additional builds or + # downloads. + file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt") + + # Create and build a separate CMake project to carry out the download. + # If we've already previously done these steps, they will not cause + # anything to be updated, so extra rebuilds of the project won't occur. + # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project + # has this set to something not findable on the PATH. + configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" + "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" + -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}" + . + RESULT_VARIABLE result + ${OUTPUT_QUIET} + WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" + ) + if(result) + message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + ${OUTPUT_QUIET} + WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" + ) + if(result) + message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") + endif() + +endfunction() diff --git a/iguana/exchanges/CMakeLists.txt b/iguana/exchanges/CMakeLists.txt index 696d2557c..2aa749888 100644 --- a/iguana/exchanges/CMakeLists.txt +++ b/iguana/exchanges/CMakeLists.txt @@ -1,7 +1,14 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -add_executable(marketmaker mm.c) +set(MM_SOURCES mm.c ../mini-gmp.c ../groestl.c ../segwit_addr.c ../keccak.c LP_etomic.c) +set(MM_LIBS ${NANOMSG_LIBRARY} curl pthread libcrypto777 libjpeg libsecp256k1) +add_executable(marketmaker-testnet ${MM_SOURCES}) +add_executable(marketmaker-mainnet ${MM_SOURCES}) include_directories(../../crypto777) -target_sources(marketmaker PRIVATE ../mini-gmp.c) -target_sources(marketmaker PRIVATE ../groestl.c) -target_sources(marketmaker PRIVATE ../segwit_addr.c) -target_link_libraries(marketmaker PRIVATE nanomsg curl pthread m libcrypto777 libjpeg libsecp256k1 "-Wl,--allow-multiple-definition" etomiclib) \ No newline at end of file +target_compile_definitions(marketmaker-testnet PRIVATE ETOMIC_TESTNET USE_STATIC_NANOMSG) +target_compile_definitions(marketmaker-mainnet PRIVATE USE_STATIC_NANOMSG) +if(UNIX) + target_link_libraries(marketmaker-testnet m) + target_link_libraries(marketmaker-mainnet m) +endif() +target_link_libraries(marketmaker-testnet ${MM_LIBS} etomiclib-testnet) +target_link_libraries(marketmaker-mainnet ${MM_LIBS} etomiclib-mainnet) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index d37152137..a493654e6 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -236,6 +236,13 @@ cJSON *LP_coinjson(struct iguana_info *coin,int32_t showwif) jaddnum(item,"balance",dstr(balance)); jaddnum(item,"KMDvalue",dstr(LP_KMDvalue(coin,balance))); } +#ifndef NOTETOMIC + else if (coin->etomic[0] != 0) { + balance = LP_etomic_get_balance(coin, coin->smartaddr); + jaddnum(item,"height",-1); + jaddnum(item,"balance",dstr(balance)); + } +#endif else { jaddnum(item,"height",-1); diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 3f5817b80..fec82e846 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -611,6 +611,14 @@ jpg(srcfile, destfile, power2=7, password, data="", required, ind=0)\n\ } return(clonestr("{\"error\":\"cant find coind\"}")); } +#ifndef NOTETOMIC + else if ( strcmp(method,"eth_withdraw") == 0 ) + { + if ( (ptr= LP_coinsearch(coin)) != 0 ) { + return LP_eth_withdraw(ptr, argjson); + } + } +#endif else if ( strcmp(method,"setconfirms") == 0 ) { int32_t n; diff --git a/iguana/exchanges/LP_etomic.c b/iguana/exchanges/LP_etomic.c index c263738de..0086b47d3 100644 --- a/iguana/exchanges/LP_etomic.c +++ b/iguana/exchanges/LP_etomic.c @@ -21,9 +21,58 @@ // // Created by artem on 24.01.18. // -#include "etomicswap/etomiclib.h" -#include "etomicswap/etomiccurl.h" -#include +#include "LP_etomic.h" + +int32_t LP_etomic_wait_for_confirmation(char *txId) +{ + return(waitForConfirmation(txId)); +} + +char *LP_etomicalice_send_fee(struct basilisk_swap *swap) +{ + char amount[100], secretKey[70]; + satoshisToWei(amount, swap->myfee.I.amount); + uint8arrayToHex(secretKey, swap->persistent_privkey.bytes, 32); + if (strcmp(swap->I.alicestr,"ETH") == 0 ) { + return(sendEth(ETH_FEE_ACCEPTOR, amount, secretKey, 1)); + } else { + return(sendErc20(swap->I.alicetomic, ETH_FEE_ACCEPTOR, amount, secretKey, 1)); + } +} + +uint8_t LP_etomic_verify_alice_fee(struct basilisk_swap *swap) +{ + if (waitForConfirmation(swap->otherfee.I.ethTxid) < 0) { + printf("Alice fee tx %s does not exist", swap->otherfee.I.ethTxid); + return(0); + } + EthTxData data = getEthTxData(swap->otherfee.I.ethTxid); + if (strcmp(data.from, swap->I.etomicdest) != 0) { + printf("Alice fee tx %s was sent from wrong address %s\n", swap->otherfee.I.ethTxid, data.from); + return(0); + } + + if ( strcmp(swap->I.alicestr,"ETH") == 0 ) { + if (strcmp(data.to, ETH_FEE_ACCEPTOR) != 0) { + printf("Alice fee %s was sent to wrong address %s\n", swap->otherfee.I.ethTxid, data.to); + 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); + return(0); + } + return(1); + } else { + 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, ETH_FEE_ACCEPTOR, weiAmount, data.input)); + } +} char *LP_etomicalice_send_payment(struct basilisk_swap *swap) { @@ -49,23 +98,94 @@ char *LP_etomicalice_send_payment(struct basilisk_swap *swap) else { memset(&input20,0,sizeof(input20)); - strcpy(input20.bobAddress, swap->I.etomicdest); + 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.utxotxid.bytes, 32); + uint8arrayToHex(input20.dealId, swap->alicepayment.I.actualtxid.bytes, 32); strcpy(input20.tokenAddress, swap->I.alicetomic); satoshisToWei(input20.amount, swap->I.alicesatoshis); - strcpy(txData.from, swap->I.etomicsrc); + 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) { + printf("Alice token allowance is too low, setting new allowance\n"); + ApproveErc20Input approveErc20Input; + strcpy(approveErc20Input.tokenAddress, swap->I.alicetomic); + strcpy(approveErc20Input.owner, swap->I.etomicdest); + strcpy(approveErc20Input.spender, ETOMIC_ALICECONTRACT); + + char *tokenBalance = getErc20BalanceHexWei(swap->I.etomicdest, swap->I.alicetomic); + strcpy(approveErc20Input.amount, tokenBalance); + free(tokenBalance); + strcpy(approveErc20Input.secret, txData.secretKey); + + char *allowTxId = approveErc20(approveErc20Input); + LP_etomic_wait_for_confirmation(allowTxId); + free(allowTxId); + } + return(aliceSendsErc20Payment(input20,txData)); } } +uint8_t LP_etomic_verify_alice_payment(struct basilisk_swap *swap, char *txId) +{ + if (waitForConfirmation(txId) < 0) { + printf("Alice payment %s does not exist\n", txId); + return(0); + } + EthTxData data = getEthTxData(txId); + if (strcmp(data.to, ETOMIC_ALICECONTRACT) != 0) { + printf("Alice payment %s was sent to wrong address %s\n", txId, data.to); + return(0); + } + if (strcmp(data.from, swap->I.etomicdest) != 0) { + printf("Alice payment %s was done from wrong address %s\n", txId, data.from); + return(0); + } + AliceSendsEthPaymentInput input; AliceSendsErc20PaymentInput input20; + + 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); + return(0); + } + memset(&input,0,sizeof(input)); + strcpy(input.bobAddress, swap->I.etomicsrc); + uint8arrayToHex(input.bobHash, swap->I.secretBn, 20); + uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20); + uint8arrayToHex(input.dealId, swap->alicepayment.I.actualtxid.bytes, 32); + + return(verifyAliceEthPaymentData(input, data.input)); + } else { + 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); + + return(verifyAliceErc20PaymentData(input20, data.input)); + } +} + char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap) { + if (waitForConfirmation(swap->alicePaymentEthTx) < 0) { + printf("Alice ETH payment %s is not found, can't reclaim\n", swap->alicePaymentEthTx); + return NULL; + } + EthTxReceipt receipt = getEthTxReceipt(swap->alicePaymentEthTx); + if (strcmp(receipt.status, "0x1") != 0) { + printf("Alice payment receipt status failed, can't reclaim\n"); + return NULL; + } AliceReclaimsAlicePaymentInput input; BasicTxData txData; memset(&txData,0,sizeof(txData)); @@ -77,14 +197,14 @@ char *LP_etomicalice_reclaims_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->values[BASILISK_ALICEPAYMENT]); + satoshisToWei(input.amount, swap->destamount); if (swap->alicetomic[0] != 0) { strcpy(input.tokenAddress, swap->alicetomic); } else { strcpy(input.tokenAddress, "0x0000000000000000000000000000000000000000"); } - strcpy(input.bobAddress, swap->etomicdest); + strcpy(input.bobAddress, swap->etomicsrc); uint8arrayToHex(input.aliceHash, swap->secretAm, 20); bits256 invertedSecret; int32_t i; @@ -93,7 +213,7 @@ char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap) } uint8arrayToHex(input.bobSecret, invertedSecret.bytes, 32); - strcpy(txData.from, swap->etomicsrc); + strcpy(txData.from, swap->etomicdest); strcpy(txData.to, ETOMIC_ALICECONTRACT); strcpy(txData.amount, "0"); uint8arrayToHex(txData.secretKey, privkey.bytes, 32); @@ -102,6 +222,15 @@ char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap) char *LP_etomicbob_spends_alice_payment(struct LP_swap_remember *swap) { + if (waitForConfirmation(swap->alicePaymentEthTx) < 0) { + printf("Alice ETH payment %s is not found, can't spend\n", swap->alicePaymentEthTx); + return NULL; + } + EthTxReceipt receipt = getEthTxReceipt(swap->alicePaymentEthTx); + if (strcmp(receipt.status, "0x1") != 0) { + printf("Alice payment receipt status failed, can't spend\n"); + return NULL; + } BobSpendsAlicePaymentInput input; BasicTxData txData; @@ -149,6 +278,7 @@ char *LP_etomicbob_sends_deposit(struct basilisk_swap *swap) uint8arrayToHex(input.depositId, swap->bobdeposit.I.actualtxid.bytes, 32); strcpy(input.aliceAddress, swap->I.etomicdest); uint8arrayToHex(input.bobHash, swap->I.secretBn, 20); + input.lockTime = swap->bobdeposit.I.locktime; strcpy(txData.from, swap->I.etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); @@ -161,17 +291,84 @@ char *LP_etomicbob_sends_deposit(struct basilisk_swap *swap) uint8arrayToHex(input20.bobHash, swap->I.secretBn, 20); satoshisToWei(input20.amount, swap->bobdeposit.I.amount); strcpy(input20.tokenAddress, swap->I.bobtomic); + input20.lockTime = swap->bobdeposit.I.locktime; 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) { + printf("Bob token allowance is too low, setting new allowance\n"); + ApproveErc20Input approveErc20Input; + strcpy(approveErc20Input.tokenAddress, swap->I.bobtomic); + strcpy(approveErc20Input.owner, swap->I.etomicsrc); + strcpy(approveErc20Input.spender, ETOMIC_BOBCONTRACT); + + char *tokenBalance = getErc20BalanceHexWei(swap->I.etomicsrc, swap->I.bobtomic); + strcpy(approveErc20Input.amount, tokenBalance); + free(tokenBalance); + strcpy(approveErc20Input.secret, txData.secretKey); + + char *allowTxId = approveErc20(approveErc20Input); + LP_etomic_wait_for_confirmation(allowTxId); + free(allowTxId); + } + return bobSendsErc20Deposit(input20, txData); } } +uint8_t LP_etomic_verify_bob_deposit(struct basilisk_swap *swap, char *txId) +{ + if (waitForConfirmation(txId) < 0) { + printf("Bob deposit txid %s does not exist\n", txId); + return(0); + } + EthTxData data = getEthTxData(txId); + if (strcmp(data.to, ETOMIC_BOBCONTRACT) != 0) { + printf("Bob deposit txid %s was sent to wrong address %s\n", txId, data.to); + return(0); + } + if (strcmp(data.from, swap->I.etomicsrc) != 0) { + printf("Bob deposit txid %s was sent from wrong address %s\n", txId, data.from); + return(0); + } + BobSendsEthDepositInput input; + BobSendsErc20DepositInput input20; + memset(&input,0,sizeof(input)); + 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); + return(0); + } + uint8arrayToHex(input.depositId, swap->bobdeposit.I.actualtxid.bytes, 32); + strcpy(input.aliceAddress, swap->I.etomicdest); + uint8arrayToHex(input.bobHash, swap->I.secretBn, 20); + input.lockTime = swap->bobdeposit.I.locktime; + + return verifyBobEthDepositData(input, data.input); + } else { + 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); + strcpy(input20.tokenAddress, swap->I.bobtomic); + input20.lockTime = swap->bobdeposit.I.locktime; + + return verifyBobErc20DepositData(input20, data.input); + } +} + char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap) { + if (waitForConfirmation(swap->bobDepositEthTx) < 0) { + printf("Bob deposit %s is not found, can't refund\n", swap->bobDepositEthTx); + return NULL; + } BobRefundsDepositInput input; BasicTxData txData; memset(&txData,0,sizeof(txData)); @@ -183,9 +380,12 @@ char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap) privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); EthTxReceipt receipt = getEthTxReceipt(swap->bobDepositEthTx); + if (strcmp(receipt.status, "0x1") != 0) { + printf("Bob deposit %s receipt status failed, can't refund\n", swap->bobDepositEthTx); + return NULL; + } uint8arrayToHex(input.depositId, swap->txids[BASILISK_BOBDEPOSIT].bytes, 32); strcpy(input.aliceAddress, swap->etomicdest); - sprintf(input.aliceCanClaimAfter, "%" PRIu64, receipt.blockNumber + 960); bits256 invertedSecret; int32_t i; @@ -221,6 +421,7 @@ char *LP_etomicbob_sends_payment(struct basilisk_swap *swap) uint8arrayToHex(input.paymentId, swap->bobpayment.I.actualtxid.bytes, 32); strcpy(input.aliceAddress, swap->I.etomicdest); uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20); + input.lockTime = swap->bobpayment.I.locktime; strcpy(txData.from, swap->I.etomicsrc); strcpy(txData.to, ETOMIC_BOBCONTRACT); @@ -233,17 +434,83 @@ char *LP_etomicbob_sends_payment(struct basilisk_swap *swap) uint8arrayToHex(input20.aliceHash, swap->I.secretAm, 20); satoshisToWei(input20.amount, swap->bobpayment.I.amount); strcpy(input20.tokenAddress, swap->I.bobtomic); + input20.lockTime = swap->bobpayment.I.locktime; 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) { + printf("Bob token allowance is too low, setting new allowance\n"); + ApproveErc20Input approveErc20Input; + strcpy(approveErc20Input.tokenAddress, swap->I.bobtomic); + strcpy(approveErc20Input.owner, swap->I.etomicsrc); + strcpy(approveErc20Input.spender, ETOMIC_BOBCONTRACT); + + char *tokenBalance = getErc20BalanceHexWei(swap->I.etomicsrc, swap->I.bobtomic); + strcpy(approveErc20Input.amount, tokenBalance); + free(tokenBalance); + strcpy(approveErc20Input.secret, txData.secretKey); + + char *allowTxId = approveErc20(approveErc20Input); + LP_etomic_wait_for_confirmation(allowTxId); + free(allowTxId); + } + return bobSendsErc20Payment(input20, txData); } } +uint8_t LP_etomic_verify_bob_payment(struct basilisk_swap *swap, char *txId) +{ + if (waitForConfirmation(txId) < 0) { + printf("Bob payment %s is not found\n", txId); + return 0; + } + EthTxData data = getEthTxData(txId); + if (strcmp(data.to, ETOMIC_BOBCONTRACT) != 0) { + printf("Bob payment %s was sent to wrong address %s\n", txId, data.to); + } + if (strcmp(data.from, swap->I.etomicsrc) != 0) { + printf("Bob payment %s was sent from wrong address %s\n", txId, data.from); + } + BobSendsEthPaymentInput input; + BobSendsErc20PaymentInput input20; + memset(&input,0,sizeof(input)); + memset(&input20,0,sizeof(input20)); + + 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); + return(0); + } + uint8arrayToHex(input.paymentId, swap->bobpayment.I.actualtxid.bytes, 32); + strcpy(input.aliceAddress, swap->I.etomicdest); + uint8arrayToHex(input.aliceHash, swap->I.secretAm, 20); + input.lockTime = swap->bobpayment.I.locktime; + + return verifyBobEthPaymentData(input, data.input); + } else { + 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); + strcpy(input20.tokenAddress, swap->I.bobtomic); + input20.lockTime = swap->bobpayment.I.locktime; + + return verifyBobErc20PaymentData(input20, data.input); + } +} + char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap) { + if (waitForConfirmation(swap->bobPaymentEthTx) < 0) { + printf("Bob payment %s is not found, can't reclaim\n", swap->bobPaymentEthTx); + return NULL; + } BobReclaimsBobPaymentInput input; BasicTxData txData; memset(&txData,0,sizeof(txData)); @@ -255,9 +522,12 @@ char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap) privkey = LP_privkey(ecoin->symbol, ecoin->smartaddr, ecoin->taddr); EthTxReceipt receipt = getEthTxReceipt(swap->bobPaymentEthTx); + if (strcmp(receipt.status, "0x1") != 0) { + printf("Bob payment receipt status failed, can't reclaim\n"); + return NULL; + } uint8arrayToHex(input.paymentId, swap->txids[BASILISK_BOBPAYMENT].bytes, 32); strcpy(input.aliceAddress, swap->etomicdest); - sprintf(input.bobCanClaimAfter, "%" PRIu64, receipt.blockNumber + 480); uint8arrayToHex(input.aliceHash, swap->secretAm, 20); if (swap->bobtomic[0] != 0) { @@ -276,13 +546,20 @@ char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap) char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap) { + if (waitForConfirmation(swap->bobPaymentEthTx) < 0) { + printf("Bob payment %s is not found, can't spend\n", swap->bobPaymentEthTx); + return NULL; + } AliceSpendsBobPaymentInput input; BasicTxData txData; memset(&txData,0,sizeof(txData)); memset(&input,0,sizeof(input)); EthTxReceipt receipt = getEthTxReceipt(swap->bobPaymentEthTx); - + if (strcmp(receipt.status, "0x1") != 0) { + printf("Bob payment %s receipt status failed, can't spend\n", swap->bobPaymentEthTx); + return NULL; + } struct iguana_info *ecoin; bits256 privkey; ecoin = LP_coinfind("ETOMIC"); @@ -290,7 +567,6 @@ char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap) uint8arrayToHex(input.paymentId, swap->txids[BASILISK_BOBPAYMENT].bytes, 32); satoshisToWei(input.amount, swap->values[BASILISK_BOBPAYMENT]); - sprintf(input.bobCanClaimAfter, "%" PRIu64, receipt.blockNumber + 480); if (swap->bobtomic[0] != 0) { strcpy(input.tokenAddress, swap->bobtomic); @@ -315,12 +591,20 @@ char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap) char *LP_etomicalice_claims_bob_deposit(struct LP_swap_remember *swap) { + if (waitForConfirmation(swap->bobDepositEthTx) < 0) { + printf("Bob deposit %s is not found, can't claim\n", swap->bobDepositEthTx); + return NULL; + } AliceClaimsBobDepositInput input; BasicTxData txData; memset(&txData,0,sizeof(txData)); memset(&input,0,sizeof(input)); EthTxReceipt receipt = getEthTxReceipt(swap->bobDepositEthTx); + if (strcmp(receipt.status, "0x1") != 0) { + printf("Bob deposit receipt status failed, can't claim\n"); + return NULL; + } struct iguana_info *ecoin; bits256 privkey; @@ -329,7 +613,6 @@ char *LP_etomicalice_claims_bob_deposit(struct LP_swap_remember *swap) uint8arrayToHex(input.depositId, swap->txids[BASILISK_BOBDEPOSIT].bytes, 32); satoshisToWei(input.amount, swap->values[BASILISK_BOBDEPOSIT]); - sprintf(input.aliceCanClaimAfter, "%" PRIu64, receipt.blockNumber + 960); if (swap->bobtomic[0] != 0) { strcpy(input.tokenAddress, swap->bobtomic); @@ -355,9 +638,11 @@ char *sendEthTx(struct basilisk_swap *swap, struct basilisk_rawtx *rawtx) return LP_etomicbob_sends_deposit(swap); } else if (rawtx == &swap->bobpayment && swap->I.bobtomic[0] != 0) { return LP_etomicbob_sends_payment(swap); + } else if (swap->I.iambob == 0 && rawtx == &swap->myfee && swap->I.alicetomic[0] != 0) { + return LP_etomicalice_send_fee(swap); } else { char *result = malloc(67); - strcpy(result, "0x0000000000000000000000000000000000000000000000000000000000000000"); + strcpy(result, EMPTY_ETH_TX_ID); return result; } } @@ -404,3 +689,25 @@ int32_t LP_etomic_pub2addr(char *coinaddr,uint8_t pub64[64]) } return(-1); } + +uint8_t LP_etomic_is_empty_tx_id(char *txId) +{ + if (strcmp(txId, EMPTY_ETH_TX_ID) == 0) { + return 1; + } + return 0; +} + +uint64_t LP_etomic_get_balance(struct iguana_info *coin, char *coinaddr) +{ + if (coin->etomic[0] == 0) { + printf("Trying to get etomic balance for non-etomic coin %s!", coin->symbol); + return 0; + } + + if (strcmp(coin->symbol, "ETH") == 0) { + return getEthBalance(coinaddr); + } else { + return getErc20BalanceSatoshi(coinaddr, coin->etomic); + } +} diff --git a/iguana/exchanges/LP_etomic.h b/iguana/exchanges/LP_etomic.h new file mode 100644 index 000000000..31da07237 --- /dev/null +++ b/iguana/exchanges/LP_etomic.h @@ -0,0 +1,54 @@ +// +// Created by artem on 13.03.18. +// + +#ifndef SUPERNET_LP_ETOMIC_H +#define SUPERNET_LP_ETOMIC_H +#include "etomicswap/etomiclib.h" +#include "etomicswap/etomiccurl.h" +#include +#include "LP_include.h" + +int32_t LP_etomic_wait_for_confirmation(char *txId); + +char *LP_etomicalice_send_fee(struct basilisk_swap *swap); + +uint8_t LP_etomic_verify_alice_fee(struct basilisk_swap *swap); + +char *LP_etomicalice_send_payment(struct basilisk_swap *swap); + +uint8_t LP_etomic_verify_alice_payment(struct basilisk_swap *swap, char *txId); + +char *LP_etomicalice_reclaims_payment(struct LP_swap_remember *swap); + +char *LP_etomicbob_spends_alice_payment(struct LP_swap_remember *swap); + +char *LP_etomicbob_sends_deposit(struct basilisk_swap *swap); + +uint8_t LP_etomic_verify_bob_deposit(struct basilisk_swap *swap, char *txId); + +char *LP_etomicbob_refunds_deposit(struct LP_swap_remember *swap); + +char *LP_etomicbob_sends_payment(struct basilisk_swap *swap); + +uint8_t LP_etomic_verify_bob_payment(struct basilisk_swap *swap, char *txId); + +char *LP_etomicbob_reclaims_payment(struct LP_swap_remember *swap); + +char *LP_etomicalice_spends_bob_payment(struct LP_swap_remember *swap); + +char *LP_etomicalice_claims_bob_deposit(struct LP_swap_remember *swap); + +char *sendEthTx(struct basilisk_swap *swap, struct basilisk_rawtx *rawtx); + +int32_t LP_etomic_priv2addr(char *coinaddr,bits256 privkey); + +int32_t LP_etomic_priv2pub(uint8_t *pub64,bits256 privkey); + +int32_t LP_etomic_pub2addr(char *coinaddr,uint8_t pub64[64]); + +uint8_t LP_etomic_is_empty_tx_id(char *txId); + +uint64_t LP_etomic_get_balance(struct iguana_info *coin, char *coinaddr); + +#endif //SUPERNET_LP_ETOMIC_H diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 38b1a688a..f1bdb2fb1 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -266,7 +266,7 @@ struct basilisk_swapinfo #define BASILISK_ALICERECLAIM 9 #define BASILISK_ALICECLAIM 10 //0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0 -char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; +static char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; struct LP_swap_remember { @@ -276,7 +276,7 @@ struct LP_swap_remember uint32_t finishtime,tradeid,requestid,quoteid,plocktime,dlocktime,expiration,state,otherstate; int32_t iambob,finishedflag,origfinishedflag,Predeemlen,Dredeemlen,sentflags[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],Predeemscript[1024],Dredeemscript[1024],pubkey33[33],other33[33]; - char Agui[65],Bgui[65],gui[65],src[65],dest[65],bobtomic[128],alicetomic[128],etomicsrc[65],etomicdest[65],destaddr[64],Adestaddr[64],Sdestaddr[64],alicepaymentaddr[64],bobpaymentaddr[64],bobdepositaddr[64],alicecoin[65],bobcoin[65],*txbytes[sizeof(txnames)/sizeof(*txnames)],bobDepositEthTx[75],bobPaymentEthTx[75]; + char Agui[65],Bgui[65],gui[65],src[65],dest[65],bobtomic[128],alicetomic[128],etomicsrc[65],etomicdest[65],destaddr[64],Adestaddr[64],Sdestaddr[64],alicepaymentaddr[64],bobpaymentaddr[64],bobdepositaddr[64],alicecoin[65],bobcoin[65],*txbytes[sizeof(txnames)/sizeof(*txnames)],bobDepositEthTx[75],bobPaymentEthTx[75],alicePaymentEthTx[75]; }; struct LP_outpoint @@ -579,5 +579,6 @@ int bech32_convert_bits(uint8_t *out,int32_t *outlen,int outbits,const uint8_t * int bech32_decode(char *hrp,uint8_t *data,int32_t *data_len,const char *input); int bech32_encode(char *output,const char *hrp,const uint8_t *data,int32_t data_len); void HashGroestl(void * buf, const void * pbegin, int len); +bits256 LP_privkey(char *symbol,char *coinaddr,uint8_t taddr); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7e6303c80..a5e473324 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -85,6 +85,11 @@ void LP_millistats_update(struct LP_millistats *mp) } #include "LP_include.h" + +#ifndef NOTETOMIC +#include "LP_etomic.h" +#endif + portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex,LP_networkmutex,LP_psockmutex,LP_coinmutex,LP_messagemutex,LP_portfoliomutex,LP_electrummutex,LP_butxomutex,LP_reservedmutex,LP_nanorecvsmutex,LP_tradebotsmutex,LP_gcmutex,LP_inusemutex,LP_cJSONmutex,LP_logmutex,LP_statslogmutex,LP_tradesmutex,LP_commandQmutex,LP_blockinit_mutex,LP_pendswap_mutex,LP_listmutex; int32_t LP_canbind; char *Broadcaststr,*Reserved_msgs[2][1000]; @@ -178,9 +183,6 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_prices.c" #include "LP_scan.c" #include "LP_transaction.c" -#ifndef NOTETOMIC -#include "LP_etomic.c" -#endif #include "LP_stats.c" #include "LP_remember.c" #include "LP_instantdex.c" diff --git a/iguana/exchanges/LP_portfolio.c b/iguana/exchanges/LP_portfolio.c index 23a1d1102..27cac5e8e 100644 --- a/iguana/exchanges/LP_portfolio.c +++ b/iguana/exchanges/LP_portfolio.c @@ -95,6 +95,14 @@ 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) { + 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 09ddbfa21..4140f90e9 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -75,6 +75,9 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx if (swap->bobpayment.I.ethTxid[0] != 0) { fprintf(fp,",\"bobPaymentEthTx\":\"%s\"", swap->bobpayment.I.ethTxid); } + if (swap->alicepayment.I.ethTxid[0] != 0) { + fprintf(fp,",\"alicePaymentEthTx\":\"%s\"", swap->alicepayment.I.ethTxid); + } fprintf(fp,",\"alicecoin\":\"%s\"",swap->I.alicestr); if ( swap->I.alicetomic[0] != 0 ) @@ -901,6 +904,10 @@ int32_t LP_swap_load(struct LP_swap_remember *rswap,int32_t forceflag) strcpy(rswap->bobPaymentEthTx, jstr(txobj,"bobPaymentEthTx")); } + if (jstr(txobj,"alicePaymentEthTx") != 0) { + strcpy(rswap->alicePaymentEthTx, jstr(txobj,"alicePaymentEthTx")); + } + if (jstr(txobj,"bobtomic") != 0) { strcpy(rswap->bobtomic, jstr(txobj,"bobtomic")); } @@ -1256,7 +1263,11 @@ cJSON *basilisk_remember(int32_t fastflag,int64_t *KMDtotals,int64_t *BTCtotals, if ( rswap.bobtomic[0] != 0 ) { char *aliceSpendEthTxId = LP_etomicalice_spends_bob_payment(&rswap); - free(aliceSpendEthTxId); + if (aliceSpendEthTxId != NULL) { + free(aliceSpendEthTxId); + } else { + printf("Alice spend ETH tx send failed!\n"); + } } #endif } @@ -1301,7 +1312,11 @@ cJSON *basilisk_remember(int32_t fastflag,int64_t *KMDtotals,int64_t *BTCtotals, if ( rswap.bobtomic[0] != 0 ) { char *aliceClaimsEthTxId = LP_etomicalice_claims_bob_deposit(&rswap); - free(aliceClaimsEthTxId); + if (aliceClaimsEthTxId != NULL) { + free(aliceClaimsEthTxId); + } else { + printf("Alice Bob deposit claim ETH tx failed!\n"); + } } #endif } @@ -1373,7 +1388,11 @@ cJSON *basilisk_remember(int32_t fastflag,int64_t *KMDtotals,int64_t *BTCtotals, if ( rswap.alicetomic[0] != 0 ) { char *bobSpendEthTx = LP_etomicbob_spends_alice_payment(&rswap); - free(bobSpendEthTx); + if (bobSpendEthTx != NULL) { + free(bobSpendEthTx); + } else { + printf("Bob spends Alice payment ETH tx send failed!\n"); + } } #endif //printf("bobspend.(%s)\n",rswap.txbytes[BASILISK_BOBSPEND]); @@ -1406,7 +1425,11 @@ cJSON *basilisk_remember(int32_t fastflag,int64_t *KMDtotals,int64_t *BTCtotals, if ( rswap.bobtomic[0] != 0 ) { char *bobReclaimEthTx = LP_etomicbob_reclaims_payment(&rswap); - free(bobReclaimEthTx); + if (bobReclaimEthTx != NULL) { + free(bobReclaimEthTx); + } else { + printf("Bob reclaims payment ETH tx send failed!\n"); + } } #endif //int32_t z; @@ -1448,7 +1471,11 @@ cJSON *basilisk_remember(int32_t fastflag,int64_t *KMDtotals,int64_t *BTCtotals, if ( rswap.bobtomic[0] != 0 ) { char *bobRefundsEthTx = LP_etomicbob_refunds_deposit(&rswap); - free(bobRefundsEthTx); + if (bobRefundsEthTx != NULL) { + free(bobRefundsEthTx); + } else { + printf("Bob refunds deposit ETH tx send failed!\n"); + } } #endif //printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,rswap.pubB1),rswap.txbytes[BASILISK_BOBREFUND]); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 92e3c9b44..fd6bffc64 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -107,7 +107,7 @@ depositspent.(f34e04ad74e290f63f3d0bccb7d0d50abfa54eea58de38816fdc596a19767add) alice.1 bob.0 */ - +#define TX_WAIT_TIMEOUT 1800 uint32_t LP_atomic_locktime(char *base,char *rel) { @@ -721,15 +721,20 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 if ( swap->I.bobtomic[0] != 0 || swap->I.alicetomic[0] != 0 ) { char *ethTxId = sendEthTx(swap, rawtx); - strcpy(rawtx->I.ethTxid, ethTxId); - free(ethTxId); + if (ethTxId != NULL) { + strcpy(rawtx->I.ethTxid, ethTxId); + free(ethTxId); + } else { + printf("Error sending ETH tx\n"); + return(-1); + } } #endif sendlen = 0; sendbuf[sendlen++] = rawtx->I.datalen & 0xff; sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; sendbuf[sendlen++] = rawtx->I.redeemlen; - if ( rawtx->I.ethTxid[0] != 0 && strlen(rawtx->I.ethTxid) == 66 ) + if ( rawtx->I.ethTxid[0] != 0 && strlen(rawtx->I.ethTxid) == 66 ) { uint8_t ethTxidBytes[32]; // ETH txid always starts with 0x @@ -857,7 +862,7 @@ void LP_bobloop(void *_swap) //LP_swapsfp_update(&swap->I.req); LP_swap_critical = (uint32_t)time(NULL); LP_unavailableset(swap->bobdeposit.utxotxid,swap->bobdeposit.utxovout,(uint32_t)time(NULL)+60,swap->I.otherhash); - if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT*10,LP_verify_otherfee) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,TX_WAIT_TIMEOUT,LP_verify_otherfee) < 0 ) { error = 1; err = -2004, printf("error waiting for alicefee\n"); @@ -871,7 +876,7 @@ void LP_bobloop(void *_swap) } } LP_unavailableset(swap->bobpayment.utxotxid,swap->bobpayment.utxovout,(uint32_t)time(NULL)+60,swap->I.otherhash); - if ( error == 0 && LP_waitfor(swap->N.pair,swap,1800,LP_verify_alicepayment) < 0 ) + if ( error == 0 && LP_waitfor(swap->N.pair,swap,TX_WAIT_TIMEOUT,LP_verify_alicepayment) < 0 ) { error = 1; err = -2006, printf("error waiting for alicepayment\n"); @@ -945,7 +950,7 @@ void LP_aliceloop(void *_swap) LP_swap_critical = (uint32_t)time(NULL); if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x80,data,maxlen,&swap->myfee,0x40,0) == 0 ) err = -1004, printf("error sending alicefee\n"); - else if ( LP_waitfor(swap->N.pair,swap,1800,LP_verify_bobdeposit) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,TX_WAIT_TIMEOUT,LP_verify_bobdeposit) < 0 ) err = -1005, printf("error waiting for bobdeposit\n"); else { @@ -970,7 +975,7 @@ void LP_aliceloop(void *_swap) } //swap->sentflag = 1; LP_swap_critical = (uint32_t)time(NULL); - if ( LP_waitfor(swap->N.pair,swap,1800,LP_verify_bobpayment) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,TX_WAIT_TIMEOUT,LP_verify_bobpayment) < 0 ) err = -1007, printf("error waiting for bobpayment\n"); else { @@ -1222,10 +1227,20 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 swap->I.bobconfirms = swap->I.bobmaxconfirms; if ( swap->I.aliceconfirms > swap->I.alicemaxconfirms ) swap->I.aliceconfirms = swap->I.alicemaxconfirms; - if ( bobcoin->isassetchain != 0 ) - swap->I.bobconfirms = BASILISK_DEFAULT_MAXCONFIRMS/2; - if ( alicecoin->isassetchain != 0 ) - swap->I.aliceconfirms = BASILISK_DEFAULT_MAXCONFIRMS/2; + if ( bobcoin->isassetchain != 0 ) { + if (strcmp(bobstr, "ETOMIC") != 0) { + swap->I.bobconfirms = BASILISK_DEFAULT_MAXCONFIRMS / 2; + } else { + swap->I.bobconfirms = 1; + } + } + if ( alicecoin->isassetchain != 0 ) { + if (strcmp(alicestr, "ETOMIC") != 0) { + swap->I.aliceconfirms = BASILISK_DEFAULT_MAXCONFIRMS / 2; + } else { + swap->I.aliceconfirms = 1; + } + } if ( strcmp("BAY",swap->I.req.src) != 0 && strcmp("BAY",swap->I.req.dest) != 0 ) { swap->I.bobconfirms *= !swap->I.bobistrusted; diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 89aecde0a..c43b4c92a 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -13,7 +13,6 @@ * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ - // // LP_transaction.c // marketmaker @@ -1647,6 +1646,31 @@ char *LP_withdraw(struct iguana_info *coin,cJSON *argjson) return(jprint(retjson,1)); } +#ifndef NOTETOMIC + +char *LP_eth_withdraw(struct iguana_info *coin,cJSON *argjson) +{ + cJSON *retjson = cJSON_CreateObject(); + char *dest_addr, *tx_id, privkey_str[70], amount_str[100]; + int64_t amount; + bits256 privkey; + + dest_addr = jstr(argjson, "to"); + amount = jdouble(argjson, "amount") * 100000000; + privkey = LP_privkey(coin->symbol, coin->smartaddr, coin->taddr); + uint8arrayToHex(privkey_str, privkey.bytes, 32); + satoshisToWei(amount_str, amount); + if (strcmp(coin->symbol, "ETH") == 0) { + tx_id = sendEth(dest_addr, amount_str, privkey_str, 0); + } else { + tx_id = sendErc20(coin->etomic, dest_addr, amount_str, privkey_str, 0); + } + jaddstr(retjson, "tx_id", tx_id); + 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; @@ -2259,6 +2283,13 @@ int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t data //printf("dexfee verified\n"); } else printf("locktime mismatch in otherfee, reject %u vs %u\n",swap->otherfee.I.locktime,swap->I.started+1); +#ifndef NOTETOMIC + if (swap->otherfee.I.ethTxid[0] != 0 && LP_etomic_is_empty_tx_id(swap->otherfee.I.ethTxid) == 0) { + if (LP_etomic_wait_for_confirmation(swap->otherfee.I.ethTxid) < 0 || LP_etomic_verify_alice_fee(swap) == 0) { + return(-1); + } + } +#endif return(0); } else printf("destaddress mismatch in other fee, reject (%s) vs (%s)\n",swap->otherfee.I.destaddr,swap->otherfee.p2shaddr); } @@ -2336,6 +2367,13 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da printf("%02x",swap->aliceclaim.txbytes[i]); printf(" <- aliceclaim\n");*/ //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); +#ifndef NOTETOMIC + if (swap->bobdeposit.I.ethTxid[0] != 0 && LP_etomic_is_empty_tx_id(swap->bobdeposit.I.ethTxid) == 0) { + if (LP_etomic_wait_for_confirmation(swap->bobdeposit.I.ethTxid) < 0 || LP_etomic_verify_bob_deposit(swap, swap->bobdeposit.I.ethTxid) == 0) { + return(-1); + } + } +#endif return(LP_waitmempool(coin->symbol,swap->bobdeposit.I.destaddr,swap->bobdeposit.I.signedtxid,0,60)); } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->aliceclaim.I.suppress_pubkeys,swap->bobdeposit.I.destaddr); } @@ -2359,6 +2397,13 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; basilisk_dontforget_update(swap,&swap->alicepayment); +#ifndef NOTETOMIC + if (swap->alicepayment.I.ethTxid[0] != 0 && LP_etomic_is_empty_tx_id(swap->alicepayment.I.ethTxid) == 0) { + if (LP_etomic_verify_alice_payment(swap, swap->alicepayment.I.ethTxid) == 0) { + return(-1); + } + } +#endif return(LP_waitmempool(coin->symbol,swap->alicepayment.I.destaddr,swap->alicepayment.I.signedtxid,0,60)); //printf("import alicepayment address.(%s)\n",swap->alicepayment.p2shaddr); //LP_importaddress(coin->symbol,swap->alicepayment.p2shaddr); @@ -2411,6 +2456,13 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da memcpy(swap->alicespend.I.pubkey33,swap->persistent_pubkey33,33); bitcoin_address(coin->symbol,swap->alicespend.I.destaddr,coin->taddr,coin->pubtype,swap->persistent_pubkey33,33); //char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); +#ifndef NOTETOMIC + if (swap->bobpayment.I.ethTxid[0] != 0 && LP_etomic_is_empty_tx_id(swap->bobpayment.I.ethTxid) == 0) { + if (LP_etomic_wait_for_confirmation(swap->bobpayment.I.ethTxid) < 0 || LP_etomic_verify_bob_payment(swap, swap->bobpayment.I.ethTxid) == 0) { + return(-1); + } + } +#endif if ( (retval= basilisk_rawtx_sign(coin->symbol,coin->wiftaddr,coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobpayment.I.destaddr,coin->zcash)) == 0 ) { /*for (i=0; ibobpayment.I.datalen; i++) diff --git a/iguana/exchanges/LP_utxo.c b/iguana/exchanges/LP_utxo.c index a4aa40098..68c9ea2de 100644 --- a/iguana/exchanges/LP_utxo.c +++ b/iguana/exchanges/LP_utxo.c @@ -626,6 +626,11 @@ cJSON *LP_address_balance(struct iguana_info *coin,char *coinaddr,int32_t electr { cJSON *array,*retjson,*item; bits256 zero; int32_t i,n; uint64_t balance = 0; memset(zero.bytes,0,sizeof(zero)); +#ifndef NOTETOMIC + if (coin->etomic[0] != 0) { + balance = LP_etomic_get_balance(coin, coinaddr); + } else +#endif if ( coin->electrum == 0 ) { if ( (array= LP_listunspent(coin->symbol,coinaddr,zero,zero)) != 0 ) diff --git a/iguana/exchanges/etomicswap/CMakeLists.txt b/iguana/exchanges/etomicswap/CMakeLists.txt index 0df98500a..46c2d2adf 100644 --- a/iguana/exchanges/etomicswap/CMakeLists.txt +++ b/iguana/exchanges/etomicswap/CMakeLists.txt @@ -1,10 +1,11 @@ -cmake_minimum_required(VERSION 2.8.9) -add_library(etomiclib etomiclib.cpp) -add_library(etomiccurl etomiccurl.c) +cmake_minimum_required(VERSION 3.5.1) +add_library(etomiclib-testnet etomiclib.cpp etomiccurl.c) +add_library(etomiclib-mainnet etomiclib.cpp etomiccurl.c) +target_compile_definitions(etomiclib-testnet PRIVATE ETOMIC_TESTNET) add_executable(alice alice.c) add_executable(bob bob.c) include_directories("${CMAKE_SOURCE_DIR}/cpp-ethereum") -target_link_libraries(etomiccurl PUBLIC curl libcrypto777) -target_link_libraries(etomiclib PUBLIC ethcore devcrypto devcore etomiccurl) -target_link_libraries(alice PUBLIC etomiclib) -target_link_libraries(bob PUBLIC etomiclib etomiccurl) \ No newline at end of file +target_link_libraries(etomiclib-testnet PUBLIC curl libcrypto777 ethcore devcrypto devcore pthread) +target_link_libraries(etomiclib-mainnet PUBLIC curl libcrypto777 ethcore devcrypto devcore pthread) +target_link_libraries(alice PUBLIC etomiclib-testnet) +target_link_libraries(bob PUBLIC etomiclib-testnet) diff --git a/iguana/exchanges/etomicswap/bob.c b/iguana/exchanges/etomicswap/bob.c index 2ee3f5cc2..794b0b533 100644 --- a/iguana/exchanges/etomicswap/bob.c +++ b/iguana/exchanges/etomicswap/bob.c @@ -11,9 +11,14 @@ char* bobContractAddress = "0x9387Fd3a016bB0205e4e131Dde886B9d2BC000A2"; char* aliceAddress = "0x485d2cc2d13a9e12E4b53D606DB1c8adc884fB8a"; -char* bobAddress = "0xA7EF3f65714AE266414C9E58bB4bAa4E6FB82B41"; +char* bobAddress = "0xbAB36286672fbdc7B250804bf6D14Be0dF69fa29"; char* tokenAddress = "0xc0eb7AeD740E1796992A08962c15661bDEB58003"; +void *erc20ApproveThread(ApproveErc20Input *input) { + char *result = approveErc20(*input); + free(result); +} + int main(int argc, char** argv) { enum { @@ -28,7 +33,8 @@ int main(int argc, char** argv) BOB_APPROVES_ERC20, BOB_ETH_BALANCE, BOB_ERC20_BALANCE, - TX_RECEIPT + TX_RECEIPT, + TX_DATA }; if (argc < 2) { return 1; @@ -51,8 +57,12 @@ int main(int argc, char** argv) strcpy(input.bobHash, argv[3]); result = bobSendsEthDeposit(input, txData); - printf("%s\n", result); - free(result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } break; case BOB_ERC20_DEPOSIT: strcpy(txData.amount, "0"); @@ -70,7 +80,12 @@ int main(int argc, char** argv) strcpy(input1.tokenAddress, tokenAddress); result = bobSendsErc20Deposit(input1, txData); - printf("%s\n", result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } free(result); break; case BOB_CLAIMS_DEPOSIT: @@ -84,11 +99,15 @@ int main(int argc, char** argv) strcpy(input2.amount, "1000000000000000000"); strcpy(input2.aliceAddress, aliceAddress); strcpy(input2.tokenAddress, argv[3]); - strcpy(input2.aliceCanClaimAfter, argv[4]); strcpy(input2.bobSecret, argv[5]); result = bobRefundsDeposit(input2, txData); - printf("%s\n", result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } free(result); break; case ALICE_CLAIMS_DEPOSIT: @@ -102,11 +121,15 @@ int main(int argc, char** argv) strcpy(input3.amount, "1000000000000000000"); strcpy(input3.bobAddress, bobAddress); strcpy(input3.tokenAddress, argv[3]); - strcpy(input3.aliceCanClaimAfter, argv[4]); strcpy(input3.bobHash, argv[5]); result = aliceClaimsBobDeposit(input3, txData); - printf("%s\n", result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } free(result); break; case BOB_ETH_PAYMENT: @@ -121,7 +144,12 @@ int main(int argc, char** argv) strcpy(input4.aliceAddress, aliceAddress); result = bobSendsEthPayment(input4, txData); - printf("%s\n", result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } free(result); break; case BOB_ERC20_PAYMENT: @@ -139,7 +167,12 @@ int main(int argc, char** argv) strcpy(input5.aliceHash, argv[3]); result = bobSendsErc20Payment(input5, txData); - printf("%s\n", result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } free(result); break; case BOB_CLAIMS_PAYMENT: @@ -154,11 +187,15 @@ int main(int argc, char** argv) strcpy(input6.aliceAddress, aliceAddress); strcpy(input6.amount, "1000000000000000000"); strcpy(input6.tokenAddress, argv[3]); - strcpy(input6.bobCanClaimAfter, argv[4]); strcpy(input6.aliceHash, argv[5]); result = bobReclaimsBobPayment(input6, txData); - printf("%s\n", result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } free(result); break; case ALICE_CLAIMS_PAYMENT: @@ -173,39 +210,127 @@ int main(int argc, char** argv) strcpy(input7.bobAddress, bobAddress); strcpy(input7.amount, "1000000000000000000"); strcpy(input7.tokenAddress, argv[3]); - strcpy(input7.bobCanClaimAfter, argv[4]); strcpy(input7.aliceSecret, argv[5]); result = aliceSpendsBobPayment(input7, txData); - printf("%s\n", result); - free(result); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } break; case BOB_APPROVES_ERC20: - result = approveErc20( - "10000000000000000000", - "0xA7EF3f65714AE266414C9E58bB4bAa4E6FB82B41", - getenv("BOB_PK") - - ); - printf("%s\n", result); - free(result); + printf("approving erc20\n"); + ApproveErc20Input input8; + strcpy(input8.amount, "0"); + strcpy(input8.spender, bobContractAddress); + strcpy(input8.owner, bobAddress); + strcpy(input8.tokenAddress, tokenAddress); + strcpy(input8.secret, getenv("BOB_PK")); + ApproveErc20Input input123; + strcpy(input123.amount, "100"); + strcpy(input123.spender, bobContractAddress); + strcpy(input123.owner, bobAddress); + strcpy(input123.tokenAddress, tokenAddress); + strcpy(input123.secret, getenv("BOB_PK")); + pthread_t t1, t2; + pthread_create(&t1, NULL, erc20ApproveThread, &input8); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_create(&t2, NULL, erc20ApproveThread, &input123); + pthread_join(t1, NULL); + pthread_join(t2, NULL); + /*result = approveErc20(input8); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } + result = approveErc20(&input8); + if (result != NULL) { + printf("%s\n", result); + free(result); + } else { + printf("Tx send result was NULL\n"); + } + */ break; case BOB_ETH_BALANCE: printf("%" PRIu64 "\n", getEthBalance(bobAddress)); break; case BOB_ERC20_BALANCE: - printf("%" PRIu64 "\n", getErc20Balance(bobAddress, tokenAddress)); + printf("%" PRIu64 "\n", getErc20BalanceSatoshi(bobAddress, tokenAddress)); break; case TX_RECEIPT: printf("getTxReceipt\n"); EthTxReceipt txReceipt; - txReceipt = getEthTxReceipt("0x82afa1b00f8a63e1a91430162e5cb2d4ebe915831ffd56e6e3227814913e23e6"); - printf("%" PRIu64 "\n", txReceipt.blockNumber); - printf("%s\n", txReceipt.blockHash); + txReceipt = getEthTxReceipt("0xc337b9cfe76aaa9022d9399a9e4ecdc1b7044d65ef74e8911a4b47874bee60c6"); + printf("blockNumber: %" PRIu64 "\n", txReceipt.blockNumber); + printf("blockHash: %s\n", txReceipt.blockHash); + printf("status: %s\n", txReceipt.status); + printf("confirmations: %" PRIu64 "\n", txReceipt.confirmations); + break; + case TX_DATA: + printf("getTxData\n"); + EthTxData ethTxData; + ethTxData = getEthTxData("0xc337b9cfe76aaa9022d9399a9e4ecdc1b7044d65ef74e8911a4b47874bee60c6"); + printf("from : %s\n", ethTxData.from); + printf("to: %s\n", ethTxData.to); + printf("value: %s\n", ethTxData.valueHex); + printf("input: %s\n", ethTxData.input); + printf("exists: %d\n", ethTxData.exists); break; default: return 1; } + /* char *pubkey = getPubKeyFromPriv(getenv("BOB_PK")); printf("pubkey: %s\n", pubkey); free(pubkey); @@ -214,5 +339,23 @@ int main(int argc, char** argv) char weiBuffer[100]; satoshisToWei(weiBuffer, satoshis); printf("wei: %s\n", weiBuffer); + + uint8_t decimals = getErc20Decimals(tokenAddress); + printf("decimals: %d\n", decimals); + + uint64_t tokenAllowance = getErc20Allowance(bobAddress, bobContractAddress, tokenAddress); + printf("allowance: %" PRIu64 "\n", tokenAllowance); + + char *sendEthTx = sendEth(bobAddress, "100000000000000", getenv("BOB_PK")); + printf("sent ETH: %s\n", sendEthTx); + free(sendEthTx); + + char *sendErc20Tx = sendErc20(tokenAddress, bobAddress, "100000000000000", getenv("BOB_PK")); + printf("sent Erc20: %s\n", sendErc20Tx); + free(sendErc20Tx); + + uint64_t gasPrice = getGasPriceFromStation(); + printf("gasPrice: %" PRIu64 "\n", gasPrice); + */ return 0; } diff --git a/iguana/exchanges/etomicswap/etomiccurl.c b/iguana/exchanges/etomicswap/etomiccurl.c index f80e87d3e..e7f1296ee 100644 --- a/iguana/exchanges/etomicswap/etomiccurl.c +++ b/iguana/exchanges/etomicswap/etomiccurl.c @@ -1,10 +1,8 @@ #include "etomiccurl.h" #include -#include -#include -#include "../../../includes/cJSON.h" static char *ethRpcUrl = ETOMIC_URL; +pthread_mutex_t sendTxMutex = PTHREAD_MUTEX_INITIALIZER; struct string { char *ptr; @@ -36,6 +34,28 @@ size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s) return size*nmemb; } +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"); + return NULL; + } + cJSON *tmp = cJSON_GetObjectItem(json, "result"); + cJSON *error = cJSON_GetObjectItem(json, "error"); + cJSON *result = NULL; + if (!is_cJSON_Null(tmp)) { + result = cJSON_Duplicate(tmp, 1); + } else if (error != NULL && !is_cJSON_Null(error)) { + char *errorString = cJSON_PrintUnformatted(error); + printf("Got ETH rpc error: %s\n", errorString); + free(errorString); + } + cJSON_Delete(json); + return result; +} + char* sendRequest(char* request) { CURL *curl; @@ -69,128 +89,256 @@ char* sendRequest(char* request) } } -char* sendRawTx(char* rawTx) +cJSON *sendRpcRequest(char *method, cJSON *params) { char* string; cJSON *request = cJSON_CreateObject(); - cJSON *params = cJSON_CreateArray(); - cJSON_AddItemToObject(request, "jsonrpc", cJSON_CreateString("2.0")); - cJSON_AddItemToObject(request, "method", cJSON_CreateString("eth_sendRawTransaction")); - cJSON_AddItemToArray(params, cJSON_CreateString(rawTx)); - cJSON_AddItemToObject(request, "params", params); - cJSON_AddItemToObject(request, "id", cJSON_CreateNumber(2)); + cJSON_AddStringToObject(request, "jsonrpc", "2.0"); + cJSON_AddStringToObject(request, "method", method); + cJSON_AddItemToObject(request, "params", cJSON_Duplicate(params, 1)); + cJSON_AddNumberToObject(request, "id", 1); string = cJSON_PrintUnformatted(request); char* requestResult = sendRequest(string); - cJSON *json = cJSON_Parse(requestResult); + free(string); cJSON_Delete(request); - char* tmp = cJSON_GetObjectItem(json, "result")->valuestring; - char* txId = (char*)malloc(strlen(tmp) + 1); - strcpy(txId, tmp); - cJSON_Delete(json); + cJSON *result = parseEthRpcResponse(requestResult); free(requestResult); - free(string); + return result; +} + +char* sendRawTxWaitConfirm(char* rawTx) +{ + cJSON *params = cJSON_CreateArray(); + cJSON_AddItemToArray(params, cJSON_CreateString(rawTx)); + cJSON *resultJson = sendRpcRequest("eth_sendRawTransaction", params); + cJSON_Delete(params); + char *txId = NULL; + if (resultJson != NULL && is_cJSON_String(resultJson) && resultJson->valuestring != NULL) { + char* tmp = resultJson->valuestring; + txId = (char *) malloc(strlen(tmp) + 1); + strcpy(txId, tmp); + } + /* + if (resultJson != NULL && is_cJSON_String(resultJson) && resultJson->valuestring != NULL) { + char* tmp = resultJson->valuestring; + if (waitForConfirmation(tmp) > 0) { + txId = (char *) malloc(strlen(tmp) + 1); + strcpy(txId, tmp); + } + } + */ + cJSON_Delete(resultJson); + pthread_mutex_unlock(&sendTxMutex); return txId; } -int getNonce(char* address) +char* sendRawTx(char* rawTx) { - char* string; - cJSON *request = cJSON_CreateObject(); cJSON *params = cJSON_CreateArray(); - cJSON_AddItemToObject(request, "jsonrpc", cJSON_CreateString("2.0")); - cJSON_AddItemToObject(request, "method", cJSON_CreateString("eth_getTransactionCount")); + cJSON_AddItemToArray(params, cJSON_CreateString(rawTx)); + cJSON *resultJson = sendRpcRequest("eth_sendRawTransaction", params); + cJSON_Delete(params); + char *txId = NULL; + if (resultJson != NULL && is_cJSON_String(resultJson) && resultJson->valuestring != NULL) { + char* tmp = resultJson->valuestring; + txId = (char *) malloc(strlen(tmp) + 1); + strcpy(txId, tmp); + } + cJSON_Delete(resultJson); + pthread_mutex_unlock(&sendTxMutex); + return txId; +} + +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! + if (pthread_mutex_lock(&sendTxMutex) != 0) { + printf("Nonce mutex lock failed\n"); + }; + cJSON *params = cJSON_CreateArray(); cJSON_AddItemToArray(params, cJSON_CreateString(address)); - cJSON_AddItemToArray(params, cJSON_CreateString("pending")); - cJSON_AddItemToObject(request, "params", params); - cJSON_AddItemToObject(request, "id", cJSON_CreateNumber(2)); - string = cJSON_PrintUnformatted(request); - char* requestResult = sendRequest(string); - cJSON_Delete(request); - cJSON *json = cJSON_Parse(requestResult); - int nonce = (int)strtol(cJSON_GetObjectItem(json, "result")->valuestring, NULL, 0); - cJSON_Delete(json); - free(requestResult); - free(string); + // cJSON_AddItemToArray(params, cJSON_CreateString("pending")); + int64_t nonce = -1; + cJSON *nonceJson = sendRpcRequest("parity_nextNonce", params); + cJSON_Delete(params); + if (nonceJson != NULL && is_cJSON_String(nonceJson) && nonceJson != NULL) { + nonce = (int64_t) strtol(nonceJson->valuestring, NULL, 0); + } + cJSON_Delete(nonceJson); + printf("Got ETH nonce %d\n", (int)nonce); return nonce; } char* getEthBalanceRequest(char* address) { - char* string; - cJSON *request = cJSON_CreateObject(); cJSON *params = cJSON_CreateArray(); - cJSON_AddItemToObject(request, "jsonrpc", cJSON_CreateString("2.0")); - cJSON_AddItemToObject(request, "method", cJSON_CreateString("eth_getBalance")); cJSON_AddItemToArray(params, cJSON_CreateString(address)); cJSON_AddItemToArray(params, cJSON_CreateString("latest")); - cJSON_AddItemToObject(request, "params", params); - cJSON_AddItemToObject(request, "id", cJSON_CreateNumber(2)); - string = cJSON_PrintUnformatted(request); - char* requestResult = sendRequest(string); - cJSON_Delete(request); - cJSON *json = cJSON_Parse(requestResult); - char* tmp = cJSON_GetObjectItem(json, "result")->valuestring; - char* balance = (char*)malloc(strlen(tmp) + 1); - strcpy(balance, tmp); - cJSON_Delete(json); - free(requestResult); - free(string); + cJSON *balanceJson = sendRpcRequest("eth_getBalance", params); + cJSON_Delete(params); + char *balance = NULL; + if (balanceJson != NULL && is_cJSON_String(balanceJson) && balanceJson->valuestring != NULL) { + balance = (char *) malloc(strlen(balanceJson->valuestring) + 1); + strcpy(balance, balanceJson->valuestring); + } + cJSON_Delete(balanceJson); return balance; } char* ethCall(char* to, const char* data) { - char* string; - cJSON *request = cJSON_CreateObject(); cJSON *params = cJSON_CreateArray(); cJSON *txObject = cJSON_CreateObject(); - cJSON_AddItemToObject(request, "jsonrpc", cJSON_CreateString("2.0")); - cJSON_AddItemToObject(request, "method", cJSON_CreateString("eth_call")); cJSON_AddStringToObject(txObject, "to", to); cJSON_AddStringToObject(txObject, "data", data); cJSON_AddItemToArray(params, txObject); cJSON_AddItemToArray(params, cJSON_CreateString("latest")); - cJSON_AddItemToObject(request, "params", params); - cJSON_AddItemToObject(request, "id", cJSON_CreateNumber(2)); - string = cJSON_PrintUnformatted(request); - char* requestResult = sendRequest(string); - cJSON_Delete(request); - cJSON *json = cJSON_Parse(requestResult); - char* tmp = cJSON_GetObjectItem(json, "result")->valuestring; - char* result = (char*)malloc(strlen(tmp) + 1); - strcpy(result, tmp); - cJSON_Delete(json); - free(requestResult); - free(string); + cJSON *resultJson = sendRpcRequest("eth_call", params); + cJSON_Delete(params); + char* result = NULL; + if (resultJson != NULL && is_cJSON_String(resultJson) && resultJson->valuestring != NULL) { + result = (char *) malloc(strlen(resultJson->valuestring) + 1); + strcpy(result, resultJson->valuestring); + } + cJSON_Delete(resultJson); return result; } EthTxReceipt getEthTxReceipt(char *txId) { EthTxReceipt result; - - char* string; - cJSON *request = cJSON_CreateObject(); + memset(&result, 0, sizeof(result)); cJSON *params = cJSON_CreateArray(); - cJSON_AddItemToObject(request, "jsonrpc", cJSON_CreateString("2.0")); - cJSON_AddItemToObject(request, "method", cJSON_CreateString("eth_getTransactionReceipt")); cJSON_AddItemToArray(params, cJSON_CreateString(txId)); - cJSON_AddItemToObject(request, "params", params); - cJSON_AddItemToObject(request, "id", cJSON_CreateNumber(2)); - string = cJSON_PrintUnformatted(request); - char *requestResult = sendRequest(string); - cJSON_Delete(request); - cJSON *json = cJSON_Parse(requestResult); - cJSON *tmp = cJSON_GetObjectItem(json, "result"); - if (is_cJSON_Null(tmp)) { + cJSON *receiptJson = sendRpcRequest("eth_getTransactionReceipt", params); + cJSON_Delete(params); + if (receiptJson == NULL || is_cJSON_Null(cJSON_GetObjectItem(receiptJson, "blockHash")) || is_cJSON_Null(cJSON_GetObjectItem(receiptJson, "blockNumber"))) { + printf("ETH tx %s is not confirmed yet or does not exist at all\n", txId); strcpy(result.blockHash, "0x0000000000000000000000000000000000000000000000000000000000000000"); result.blockNumber = 0; } else { - strcpy(result.blockHash, cJSON_GetObjectItem(tmp, "blockHash")->valuestring); - result.blockNumber = (uint64_t) strtol(cJSON_GetObjectItem(tmp, "blockNumber")->valuestring, NULL, 0); + uint64_t currentBlockNumber = getEthBlockNumber(); + strcpy(result.blockHash, cJSON_GetObjectItem(receiptJson, "blockHash")->valuestring); + strcpy(result.status, cJSON_GetObjectItem(receiptJson, "status")->valuestring); + result.blockNumber = (uint64_t) strtol(cJSON_GetObjectItem(receiptJson, "blockNumber")->valuestring, NULL, 0); + if (currentBlockNumber >= result.blockNumber) { + result.confirmations = currentBlockNumber - result.blockNumber + 1; + } } - cJSON_Delete(json); - free(requestResult); - free(string); + cJSON_Delete(receiptJson); return result; } + +uint64_t getEthBlockNumber() +{ + uint64_t result = 0; + cJSON *params = cJSON_CreateArray(); + cJSON *blockNumberJson = sendRpcRequest("eth_blockNumber", params); + cJSON_Delete(params); + if (blockNumberJson != NULL && is_cJSON_String(blockNumberJson) && blockNumberJson->valuestring != NULL) { + result = (uint64_t) strtol(blockNumberJson->valuestring, NULL, 0); + } + cJSON_Delete(blockNumberJson); + return result; +} + +EthTxData getEthTxData(char *txId) +{ + EthTxData result; + memset(&result, 0, sizeof(result)); + cJSON *params = cJSON_CreateArray(); + cJSON_AddItemToArray(params, cJSON_CreateString(txId)); + cJSON *dataJson = sendRpcRequest("eth_getTransactionByHash", params); + cJSON_Delete(params); + if (dataJson == NULL) { + result.exists = 0; + printf("ETH tx %s get data error or txId does not exist\n", txId); + } else { + result.exists = 1; + strcpy(result.from, cJSON_GetObjectItem(dataJson, "from")->valuestring); + strcpy(result.to, cJSON_GetObjectItem(dataJson, "to")->valuestring); + strcpy(result.input, cJSON_GetObjectItem(dataJson, "input")->valuestring); + strcpy(result.valueHex, cJSON_GetObjectItem(dataJson, "value")->valuestring); + } + free(dataJson); + return result; +} + +uint64_t getGasPriceFromStation() +{ + CURL *curl; + CURLcode res; + struct curl_slist *headers = NULL; + curl = curl_easy_init(); + if (curl) { + struct string s; + init_eth_string(&s); + + headers = curl_slist_append(headers, "Accept: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); + 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); + /* Check for errors */ + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + return DEFAULT_GAS_PRICE; + } + + /* always cleanup */ + curl_easy_cleanup(curl); + cJSON *resultJson = cJSON_Parse(s.ptr); + uint64_t result = DEFAULT_GAS_PRICE; + free(s.ptr); + if (resultJson == NULL) { + return result; + } + + if (is_cJSON_Number(cJSON_GetObjectItem(resultJson, "average"))) { +#ifdef ETOMIC_TESTNET + result = (uint64_t)(cJSON_GetObjectItem(resultJson, "average")->valuedouble / 10) + 10; +#else + result = (uint64_t)(cJSON_GetObjectItem(resultJson, "average")->valuedouble / 10) + 1; +#endif + } + cJSON_Delete(resultJson); + return result; + } else { + return DEFAULT_GAS_PRICE; + } +} + +int32_t waitForConfirmation(char *txId) +{ + EthTxReceipt receipt; + EthTxData txData; + uint8_t retries = 0; + do { + receipt = getEthTxReceipt(txId); + if (receipt.confirmations < 1) { + txData = getEthTxData(txId); + if (txData.exists == 0) { + retries++; + if (retries >= 30) { + printf("Have not found ETH tx %s after 10 checks, aborting\n", txId); + return (-1); + } + } + } else { + break; + } + printf("waiting for ETH txId to be confirmed: %s\n", txId); + sleep(15); + } while (1); + + if (strcmp(receipt.status, "0x1") != 0) { + printf("ETH txid %s receipt status failed\n", txId); + return(-1); + } + + return((int32_t)receipt.confirmations); +} diff --git a/iguana/exchanges/etomicswap/etomiccurl.h b/iguana/exchanges/etomicswap/etomiccurl.h index 3a0a9be1e..c0433bc75 100644 --- a/iguana/exchanges/etomicswap/etomiccurl.h +++ b/iguana/exchanges/etomicswap/etomiccurl.h @@ -1,28 +1,54 @@ +#ifndef ETOMIC_CURL_HEADER +#define ETOMIC_CURL_HEADER + #include +#include +#ifdef _WIN32 +#include "../../../OSlibs/win/pthread.h" +#endif #ifdef __cplusplus extern "C"{ #endif - -#define ETOMIC_TESTNET + #ifdef ETOMIC_TESTNET -#define ETOMIC_URL "https://ropsten.infura.io/y07GHxUyTgeN2mdfOonu" +#define ETOMIC_URL "http://195.201.0.6:8545" +#define DEFAULT_GAS_PRICE 100 #else -#define ETOMIC_URL "https://mainnet.infura.io/y07GHxUyTgeN2mdfOonu" +#define ETOMIC_URL "http://195.201.0.6:8555" +#define DEFAULT_GAS_PRICE 4 #endif - + typedef struct { uint64_t blockNumber; + uint64_t confirmations; char blockHash[75]; + char status[10]; } EthTxReceipt; +typedef struct +{ + char from[50]; + char to[50]; + char input[1000]; + char valueHex[70]; + uint8_t exists; +} EthTxData; + char* sendRawTx(char* rawTx); +char* sendRawTxWaitConfirm(char* rawTx); char* ethCall(char* to, const char* data); -int getNonce(char* address); +int64_t getNonce(char* address); char* getEthBalanceRequest(char* address); EthTxReceipt getEthTxReceipt(char *txId); +EthTxData getEthTxData(char *txId); +uint64_t getEthBlockNumber(); +uint64_t getGasPriceFromStation(); +int32_t waitForConfirmation(char *txId); #ifdef __cplusplus } #endif + +#endif \ No newline at end of file diff --git a/iguana/exchanges/etomicswap/etomiclib.cpp b/iguana/exchanges/etomicswap/etomiclib.cpp index dfe0695ec..1fdc5933e 100644 --- a/iguana/exchanges/etomicswap/etomiclib.cpp +++ b/iguana/exchanges/etomicswap/etomiclib.cpp @@ -12,7 +12,7 @@ using namespace dev; using namespace dev::eth; -char* stringStreamToChar(std::stringstream& ss) +char *stringStreamToChar(std::stringstream& ss) { const std::string tmp = ss.str(); auto result = (char*)malloc(strlen(tmp.c_str()) + 1); @@ -26,13 +26,13 @@ TransactionSkeleton txDataToSkeleton(BasicTxData txData) tx.from = jsToAddress(txData.from); tx.to = jsToAddress(txData.to); tx.value = jsToU256(txData.amount); - tx.gas = 300000; - tx.gasPrice = ETOMIC_GASMULT * exp10<9>(); + tx.gas = 100000; + tx.gasPrice = getGasPriceFromStation() * boost::multiprecision::pow(u256(10), 9); tx.nonce = getNonce(txData.from); return tx; } -char* signTx(TransactionSkeleton& tx, char* secret) +char *signTx(TransactionSkeleton& tx, char* secret) { Secret& secretKey = *(new Secret(secret)); auto baseTx = new TransactionBase(tx, secretKey); @@ -43,30 +43,29 @@ char* signTx(TransactionSkeleton& tx, char* secret) return stringStreamToChar(ss); } -char* approveErc20(char* amount, char* from, char* secret) +char *approveErc20(ApproveErc20Input input) { TransactionSkeleton tx; - tx.from = jsToAddress(from); - tx.to = jsToAddress("0xc0eb7AeD740E1796992A08962c15661bDEB58003"); - tx.value = 0; // exp10<18>(); + tx.from = jsToAddress(input.owner); + tx.to = jsToAddress(input.tokenAddress); + tx.value = 0; tx.gas = 300000; - tx.gasPrice = ETOMIC_GASMULT * exp10<9>(); - tx.nonce = getNonce(from); + tx.gasPrice = getGasPriceFromStation() * boost::multiprecision::pow(u256(10), 9); + tx.nonce = getNonce(input.owner); std::stringstream ss; ss << "0x095ea7b3" << "000000000000000000000000" - << toHex(jsToAddress("0xe1D4236C5774D35Dc47dcc2E5E0CcFc463A3289c")) - << toHex(toBigEndian(jsToU256(amount))); + << toHex(jsToAddress(input.spender)) + << toHex(toBigEndian(jsToU256(input.amount))); tx.data = jsToBytes(ss.str()); - char* rawTx = signTx(tx, secret); - char* result = sendRawTx(rawTx); + char* rawTx = signTx(tx, input.secret); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } -char* aliceSendsEthPayment(AliceSendsEthPaymentInput input, BasicTxData txData) +std::stringstream aliceSendsEthPaymentData(AliceSendsEthPaymentInput input) { - TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; ss << "0x47c7b6e2" << toHex(jsToBytes(input.dealId)) @@ -76,20 +75,41 @@ char* aliceSendsEthPayment(AliceSendsEthPaymentInput input, BasicTxData txData) << "000000000000000000000000" << toHex(jsToBytes(input.bobHash)) << "000000000000000000000000"; + return ss; +} + +char* aliceSendsEthPayment(AliceSendsEthPaymentInput input, BasicTxData txData) +{ + TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = aliceSendsEthPaymentData(input); tx.data = jsToBytes(ss.str()); - char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char *rawTx = signTx(tx, txData.secretKey); + char *result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } -char* aliceSendsErc20Payment(AliceSendsErc20PaymentInput input, BasicTxData txData) +uint8_t verifyAliceEthPaymentData(AliceSendsEthPaymentInput input, char *data) { - TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = aliceSendsEthPaymentData(input); + if (strcmp(ss.str().c_str(), data) != 0) { + printf("Alice ETH payment data %s does not match expected %s\n", data, ss.str().c_str()); + return 0; + } + return 1; +} + +std::stringstream aliceSendsErc20PaymentData(AliceSendsErc20PaymentInput input) +{ + uint8_t decimals = getErc20Decimals(input.tokenAddress); + u256 amount = jsToU256(input.amount); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } std::stringstream ss; ss << "0x184db3bf" << toHex(jsToBytes(input.dealId)) - << toHex(toBigEndian(jsToU256(input.amount))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" << toHex(jsToAddress(input.bobAddress)) << toHex(jsToBytes(input.aliceHash)) @@ -98,22 +118,47 @@ char* aliceSendsErc20Payment(AliceSendsErc20PaymentInput input, BasicTxData txDa << "000000000000000000000000" << "000000000000000000000000" << toHex(jsToAddress(input.tokenAddress)); + return ss; +} + +char* aliceSendsErc20Payment(AliceSendsErc20PaymentInput input, BasicTxData txData) +{ + TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = aliceSendsErc20PaymentData(input); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } +uint8_t verifyAliceErc20PaymentData(AliceSendsErc20PaymentInput input, char *data) +{ + std::stringstream ss = aliceSendsErc20PaymentData(input); + if (strcmp(ss.str().c_str(), data) != 0) { + printf("Alice ERC20 payment data %s is not equal to expected %s\n", data, ss.str().c_str()); + return 0; + } + return 1; +} + char* aliceReclaimsAlicePayment(AliceReclaimsAlicePaymentInput input, BasicTxData txData) { TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; + u256 amount = jsToU256(input.amount); + dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { + uint8_t decimals = getErc20Decimals(input.tokenAddress); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + } ss << "0x8b9a167a" << toHex(jsToBytes(input.dealId)) - << toHex(toBigEndian(jsToU256(input.amount))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)) + << toHex(tokenAddress) << "000000000000000000000000" << toHex(jsToAddress(input.bobAddress)) << toHex(jsToBytes(input.aliceHash)) @@ -123,7 +168,7 @@ char* aliceReclaimsAlicePayment(AliceReclaimsAlicePaymentInput input, BasicTxDat << toHex(jsToBytes(input.bobSecret)); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } @@ -132,11 +177,19 @@ char* bobSpendsAlicePayment(BobSpendsAlicePaymentInput input, BasicTxData txData { TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; + u256 amount = jsToU256(input.amount); + dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { + uint8_t decimals = getErc20Decimals(input.tokenAddress); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + } ss << "0x392ec66b" << toHex(jsToBytes(input.dealId)) - << toHex(toBigEndian(jsToU256(input.amount))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)) + << toHex(tokenAddress) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << toHex(jsToBytes(input.bobHash)) @@ -146,21 +199,29 @@ char* bobSpendsAlicePayment(BobSpendsAlicePaymentInput input, BasicTxData txData << toHex(jsToBytes(input.aliceSecret)); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } -char* bobSendsEthDeposit(BobSendsEthDepositInput input, BasicTxData txData) +std::stringstream bobSendsEthDepositData(BobSendsEthDepositInput input) { - TransactionSkeleton tx = txDataToSkeleton(txData); + u256 lockTime = input.lockTime; std::stringstream ss; - ss << "0xc2c5143f" + ss << "0xdd23795f" << toHex(jsToBytes(input.depositId)) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << toHex(jsToBytes(input.bobHash)) - << "000000000000000000000000"; + << "000000000000000000000000" + << toHex(toBigEndian(lockTime)); + return ss; +} + +char* bobSendsEthDeposit(BobSendsEthDepositInput input, BasicTxData txData) +{ + TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = bobSendsEthDepositData(input); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); char* result = sendRawTx(rawTx); @@ -168,44 +229,82 @@ char* bobSendsEthDeposit(BobSendsEthDepositInput input, BasicTxData txData) return result; } -char* bobSendsErc20Deposit(BobSendsErc20DepositInput input, BasicTxData txData) +uint8_t verifyBobEthDepositData(BobSendsEthDepositInput input, char *data) { - TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = bobSendsEthDepositData(input); + if (strcmp(ss.str().c_str(), data) != 0) { + printf("Bob deposit data %s != expected %s\n", data, ss.str().c_str()); + return 0; + } + return 1; +} + +std::stringstream bobSendsErc20DepositData(BobSendsErc20DepositInput input) +{ + uint8_t decimals = getErc20Decimals(input.tokenAddress); + u256 amount = jsToU256(input.amount); + u256 lockTime = input.lockTime; + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } std::stringstream ss; - ss << "0xce8bbe4b" + ss << "0x5d567259" << toHex(jsToBytes(input.depositId)) - << toHex(toBigEndian(jsToU256(input.amount))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << toHex(jsToBytes(input.bobHash)) << "000000000000000000000000" << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)); + << toHex(jsToAddress(input.tokenAddress)) + << toHex(toBigEndian(lockTime)); + return ss; +} + +char* bobSendsErc20Deposit(BobSendsErc20DepositInput input, BasicTxData txData) +{ + TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = bobSendsErc20DepositData(input); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } +uint8_t verifyBobErc20DepositData(BobSendsErc20DepositInput input, char *data) +{ + std::stringstream ss = bobSendsErc20DepositData(input); + if (strcmp(ss.str().c_str(), data) != 0) { + printf("Bob deposit data %s != expected %s\n", data, ss.str().c_str()); + return 0; + } + return 1; +} + char* bobRefundsDeposit(BobRefundsDepositInput input, BasicTxData txData) { TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; - ss << "0x1dbe6508" + u256 amount = jsToU256(input.amount); + dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { + uint8_t decimals = getErc20Decimals(input.tokenAddress); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + } + ss << "0x1f7a72f7" << toHex(jsToBytes(input.depositId)) - << toHex(toBigEndian(jsToU256(input.amount))) - << toHex(toBigEndian(jsToU256(input.aliceCanClaimAfter))) + << toHex(toBigEndian(amount)) + << toHex(jsToBytes(input.bobSecret)) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)) - << "00000000000000000000000000000000000000000000000000000000000000c0" - << "0000000000000000000000000000000000000000000000000000000000000020" - << toHex(jsToBytes(input.bobSecret)); + << toHex(tokenAddress); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } @@ -214,77 +313,132 @@ char* aliceClaimsBobDeposit(AliceClaimsBobDepositInput input, BasicTxData txData { TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; - ss << "0x960173b5" + u256 amount = jsToU256(input.amount); + dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { + uint8_t decimals = getErc20Decimals(input.tokenAddress); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + } + ss << "0x4b915a68" << toHex(jsToBytes(input.depositId)) - << toHex(toBigEndian(jsToU256(input.amount))) - << toHex(toBigEndian(jsToU256(input.aliceCanClaimAfter))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" << toHex(jsToAddress(input.bobAddress)) << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)) + << toHex(tokenAddress) << toHex(jsToBytes(input.bobHash)) << "000000000000000000000000"; tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } -char* bobSendsEthPayment(BobSendsEthPaymentInput input, BasicTxData txData) +std::stringstream bobSendsEthPaymentData(BobSendsEthPaymentInput input) { - TransactionSkeleton tx = txDataToSkeleton(txData); + u256 lockTime = input.lockTime; std::stringstream ss; - ss << "0xcf36fe8e" + ss << "0x5ab30d95" << toHex(jsToBytes(input.paymentId)) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << toHex(jsToBytes(input.aliceHash)) - << "000000000000000000000000"; + << "000000000000000000000000" + << toHex(toBigEndian(lockTime)); + return ss; +} + +char* bobSendsEthPayment(BobSendsEthPaymentInput input, BasicTxData txData) +{ + TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = bobSendsEthPaymentData(input); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } -char* bobSendsErc20Payment(BobSendsErc20PaymentInput input, BasicTxData txData) +uint8_t verifyBobEthPaymentData(BobSendsEthPaymentInput input, char *data) { - TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = bobSendsEthPaymentData(input); + if (strcmp(ss.str().c_str(), data) != 0) { + printf("Bob payment data %s != expected %s\n", data, ss.str().c_str()); + return 0; + } + return 1; +} + +std::stringstream bobSendsErc20PaymentData(BobSendsErc20PaymentInput input) +{ + uint8_t decimals = getErc20Decimals(input.tokenAddress); + u256 amount = jsToU256(input.amount); + u256 lockTime = input.lockTime; + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } std::stringstream ss; - ss << "0x34f64dfd" + ss << "0xb8a15b1d" << toHex(jsToBytes(input.paymentId)) - << toHex(toBigEndian(jsToU256(input.amount))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << toHex(jsToBytes(input.aliceHash)) << "000000000000000000000000" << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)); + << toHex(jsToAddress(input.tokenAddress)) + << toHex(toBigEndian(lockTime)); + return ss; +} + +char* bobSendsErc20Payment(BobSendsErc20PaymentInput input, BasicTxData txData) +{ + TransactionSkeleton tx = txDataToSkeleton(txData); + std::stringstream ss = bobSendsErc20PaymentData(input); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } +uint8_t verifyBobErc20PaymentData(BobSendsErc20PaymentInput input, char *data) +{ + std::stringstream ss = bobSendsErc20PaymentData(input); + if (strcmp(ss.str().c_str(), data) != 0) { + printf("Bob payment data %s != expected %s\n", data, ss.str().c_str()); + return 0; + } + return 1; +} + char* bobReclaimsBobPayment(BobReclaimsBobPaymentInput input, BasicTxData txData) { TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; - ss << "0xb7cc2312" + u256 amount = jsToU256(input.amount); + dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { + uint8_t decimals = getErc20Decimals(input.tokenAddress); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + } + ss << "0xe45ef4ad" << toHex(jsToBytes(input.paymentId)) - << toHex(toBigEndian(jsToU256(input.amount))) - << toHex(toBigEndian(jsToU256(input.bobCanClaimAfter))) + << toHex(toBigEndian(amount)) << "000000000000000000000000" << toHex(jsToAddress(input.aliceAddress)) << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)) + << toHex(tokenAddress) << toHex(jsToBytes(input.aliceHash)) << "000000000000000000000000"; tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } @@ -293,20 +447,25 @@ char* aliceSpendsBobPayment(AliceSpendsBobPaymentInput input, BasicTxData txData { TransactionSkeleton tx = txDataToSkeleton(txData); std::stringstream ss; - ss << "0x97004255" + u256 amount = jsToU256(input.amount); + dev::Address tokenAddress = jsToAddress(input.tokenAddress); + if (tokenAddress != ZeroAddress) { + uint8_t decimals = getErc20Decimals(input.tokenAddress); + if (decimals < 18) { + amount /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + } + ss << "0x113ee583" << toHex(jsToBytes(input.paymentId)) - << toHex(toBigEndian(jsToU256(input.amount))) - << toHex(toBigEndian(jsToU256(input.bobCanClaimAfter))) + << toHex(toBigEndian(amount)) + << toHex(jsToBytes(input.aliceSecret)) << "000000000000000000000000" << toHex(jsToAddress(input.bobAddress)) << "000000000000000000000000" - << toHex(jsToAddress(input.tokenAddress)) - << "00000000000000000000000000000000000000000000000000000000000000c0" - << "0000000000000000000000000000000000000000000000000000000000000020" - << toHex(jsToBytes(input.aliceSecret)); + << toHex(tokenAddress); tx.data = jsToBytes(ss.str()); char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char* result = sendRawTxWaitConfirm(rawTx); free(rawTx); return result; } @@ -339,12 +498,12 @@ uint64_t getEthBalance(char* address) { char* hexBalance = getEthBalanceRequest(address); // convert wei to satoshi - u256 balance = jsToU256(hexBalance) / exp10<10>(); + u256 balance = jsToU256(hexBalance) / boost::multiprecision::pow(u256(10), 10); free(hexBalance); return static_cast(balance); } -uint64_t getErc20Balance(char* address, char* tokenAddress) +uint64_t getErc20BalanceSatoshi(char *address, char *tokenAddress) { std::stringstream ss; ss << "0x70a08231" @@ -353,11 +512,54 @@ uint64_t getErc20Balance(char* address, char* tokenAddress) std::stringstream& resultStream = *(new std::stringstream); char* hexBalance = ethCall(tokenAddress, ss.str().c_str()); // convert wei to satoshi - u256 balance = jsToU256(hexBalance) / exp10<10>(); + uint8_t 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); } +char *getErc20BalanceHexWei(char *address, char *tokenAddress) +{ + std::stringstream ss; + ss << "0x70a08231" + << "000000000000000000000000" + << toHex(jsToAddress(address)); + char *hexBalance = ethCall(tokenAddress, ss.str().c_str()); + return hexBalance; +} + +uint64_t getErc20Allowance(char *owner, char *spender, char *tokenAddress) +{ + std::stringstream ss; + ss << "0xdd62ed3e" + << "000000000000000000000000" + << toHex(jsToAddress(owner)) + << "000000000000000000000000" + << toHex(jsToAddress(spender)); + char* hexAllowance = ethCall(tokenAddress, ss.str().c_str()); + uint8_t decimals = getErc20Decimals(tokenAddress); + u256 allowance = jsToU256(hexAllowance); + if (decimals < 18) { + allowance *= boost::multiprecision::pow(u256(10), 18 - decimals); + } + // convert wei to satoshi + allowance /= boost::multiprecision::pow(u256(10), 10); + free(hexAllowance); + return static_cast(allowance); +} + +uint8_t getErc20Decimals(char *tokenAddress) +{ + char* hexDecimals = ethCall(tokenAddress, "0x313ce567"); + auto decimals = (uint8_t) strtol(hexDecimals, NULL, 0); + free(hexDecimals); + return decimals; +} + void uint8arrayToHex(char *dest, uint8_t *input, int len) { strcpy(dest, "0x"); @@ -373,3 +575,82 @@ void satoshisToWei(char *dest, uint64_t input) sprintf(dest, "%" PRIu64, input); strcat(dest, "0000000000"); } + +uint64_t weiToSatoshi(char *wei) +{ + u256 satoshi = jsToU256(wei) / boost::multiprecision::pow(u256(10), 10); + return static_cast(satoshi); +} + +char *sendEth(char *to, char *amount, char *privKey, uint8_t waitConfirm) +{ + 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); + + char *rawTx = signTx(tx, privKey); + if (waitConfirm == 0) { + result = sendRawTx(rawTx); + } else { + result = sendRawTxWaitConfirm(rawTx); + } + free(rawTx); + return result; +} + +std::stringstream getErc20TransferData(char *tokenAddress, char *to, char *amount) +{ + u256 amountWei = jsToU256(amount); + uint8_t decimals = getErc20Decimals(tokenAddress); + if (decimals < 18) { + amountWei /= boost::multiprecision::pow(u256(10), 18 - decimals); + } + // convert wei to satoshi + std::stringstream ss; + ss << "0xa9059cbb" + << "000000000000000000000000" + << toHex(jsToAddress(to)) + << toHex(toBigEndian(amountWei)); + return ss; +} + +char *sendErc20(char *tokenAddress, char *to, char *amount, char *privKey, uint8_t waitConfirm) +{ + TransactionSkeleton tx; + char *from = privKey2Addr(privKey), *result; + 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); + free(from); + + std::stringstream ss = getErc20TransferData(tokenAddress, to, amount); + tx.data = jsToBytes(ss.str()); + + char *rawTx = signTx(tx, privKey); + if (waitConfirm == 0) { + result = sendRawTx(rawTx); + } else { + result = sendRawTxWaitConfirm(rawTx); + } + free(rawTx); + return result; +} + +uint8_t verifyAliceErc20FeeData(char* tokenAddress, char *to, char *amount, char *data) +{ + std::stringstream ss = getErc20TransferData(tokenAddress, to, amount); + 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; +} diff --git a/iguana/exchanges/etomicswap/etomiclib.h b/iguana/exchanges/etomicswap/etomiclib.h index fba03e4e1..cc5ccebfc 100644 --- a/iguana/exchanges/etomicswap/etomiclib.h +++ b/iguana/exchanges/etomicswap/etomiclib.h @@ -6,19 +6,17 @@ #ifdef __cplusplus extern "C" { #endif - -#define ETOMIC_TESTNET + #ifdef ETOMIC_TESTNET -#define ETOMIC_ALICECONTRACT "0xe1D4236C5774D35Dc47dcc2E5E0CcFc463A3289c" -#define ETOMIC_BOBCONTRACT "0x9387Fd3a016bB0205e4e131Dde886B9d2BC000A2" -#define ETOMIC_GASMULT 100 +#define ETOMIC_ALICECONTRACT "0xe1d4236c5774d35dc47dcc2e5e0ccfc463a3289c" +#define ETOMIC_BOBCONTRACT "0x2a8e4f9ae69c86e277602c6802085febc4bd5986" #else -#define ETOMIC_ALICECONTRACT "0x9bC5418CEdED51dB08467fc4b62F32C5D9EBdA55" -#define ETOMIC_BOBCONTRACT "0xB1Ad803ea4F57401639c123000C75F5B66E4D123" -#define ETOMIC_GASMULT 4 +#define ETOMIC_ALICECONTRACT "0x9bc5418ceded51db08467fc4b62f32c5d9ebda55" +#define ETOMIC_BOBCONTRACT "0xfef736cfa3b884669a4e0efd6a081250cce228e7" #endif - -#define ETOMIC_SATOSHICAT "0000000000" + +#define EMPTY_ETH_TX_ID "0x0000000000000000000000000000000000000000000000000000000000000000" +#define ETH_FEE_ACCEPTOR "0x485d2cc2d13a9e12e4b53d606db1c8adc884fb8a" typedef struct { char from[65]; @@ -65,6 +63,7 @@ typedef struct { char depositId[70]; char aliceAddress[65]; char bobHash[65]; + uint64_t lockTime; } BobSendsEthDepositInput; typedef struct { @@ -73,6 +72,7 @@ typedef struct { char tokenAddress[65]; char aliceAddress[65]; char bobHash[65]; + uint64_t lockTime; } BobSendsErc20DepositInput; typedef struct { @@ -81,7 +81,6 @@ typedef struct { char tokenAddress[65]; char aliceAddress[65]; char bobSecret[70]; - char aliceCanClaimAfter[100]; } BobRefundsDepositInput; typedef struct { @@ -90,13 +89,13 @@ typedef struct { char tokenAddress[65]; char bobAddress[65]; char bobHash[65]; - char aliceCanClaimAfter[100]; } AliceClaimsBobDepositInput; typedef struct { char paymentId[70]; char aliceAddress[65]; char aliceHash[65]; + uint64_t lockTime; } BobSendsEthPaymentInput; typedef struct { @@ -105,6 +104,7 @@ typedef struct { char tokenAddress[65]; char aliceAddress[65]; char aliceHash[65]; + uint64_t lockTime; } BobSendsErc20PaymentInput; typedef struct { @@ -113,7 +113,6 @@ typedef struct { char tokenAddress[65]; char aliceAddress[65]; char aliceHash[65]; - char bobCanClaimAfter[100]; } BobReclaimsBobPaymentInput; typedef struct { @@ -122,29 +121,67 @@ typedef struct { char tokenAddress[65]; char aliceSecret[70]; char bobAddress[65]; - char bobCanClaimAfter[100]; } AliceSpendsBobPaymentInput; -char* approveErc20(char amount[100], char* from, char* secret); +typedef struct { + char tokenAddress[65]; + char owner[65]; + char spender[65]; + char amount[100]; + char secret[70]; +} ApproveErc20Input; + +char *approveErc20(ApproveErc20Input input); + char* aliceSendsEthPayment(AliceSendsEthPaymentInput input, BasicTxData txData); +uint8_t verifyAliceEthPaymentData(AliceSendsEthPaymentInput input, char *data); + char* aliceSendsErc20Payment(AliceSendsErc20PaymentInput input, BasicTxData txData); +uint8_t verifyAliceErc20PaymentData(AliceSendsErc20PaymentInput input, char *data); + char* aliceReclaimsAlicePayment(AliceReclaimsAlicePaymentInput input, BasicTxData txData); char* bobSpendsAlicePayment(BobSpendsAlicePaymentInput input, BasicTxData txData); + char* bobSendsEthDeposit(BobSendsEthDepositInput input, BasicTxData txData); +uint8_t verifyBobEthDepositData(BobSendsEthDepositInput input, char *data); + char* bobSendsErc20Deposit(BobSendsErc20DepositInput input, BasicTxData txData); +uint8_t verifyBobErc20DepositData(BobSendsErc20DepositInput input, char *data); + char* bobRefundsDeposit(BobRefundsDepositInput input, BasicTxData txData); char* aliceClaimsBobDeposit(AliceClaimsBobDepositInput input, BasicTxData txData); + char* bobSendsEthPayment(BobSendsEthPaymentInput input, BasicTxData txData); +uint8_t verifyBobEthPaymentData(BobSendsEthPaymentInput input, char *data); + char* bobSendsErc20Payment(BobSendsErc20PaymentInput input, BasicTxData txData); +uint8_t verifyBobErc20PaymentData(BobSendsErc20PaymentInput input, char *data); + char* bobReclaimsBobPayment(BobReclaimsBobPaymentInput input, BasicTxData txData); char* aliceSpendsBobPayment(AliceSpendsBobPaymentInput input, BasicTxData txData); + char* privKey2Addr(char* privKey); char* pubKey2Addr(char* pubKey); char* getPubKeyFromPriv(char* privKey); + +// returns satoshis, not wei! uint64_t getEthBalance(char* address); -uint64_t getErc20Balance(char* address, char tokenAddress[65]); +uint64_t getErc20BalanceSatoshi(char* address, char tokenAddress[65]); +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); + 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); + +uint8_t verifyAliceErc20FeeData(char* tokenAddress, char *to, char *amount, char *data); // Your prototype or Definition #ifdef __cplusplus } diff --git a/iguana/secp256k1/CMakeLists.txt b/iguana/secp256k1/CMakeLists.txt index ae62f1f16..d0e88a3bb 100644 --- a/iguana/secp256k1/CMakeLists.txt +++ b/iguana/secp256k1/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) file(GLOB sources "src/secp256k1.c") file(GLOB headers "src/*.h") -add_definitions(-DHAVE_CONFIG_H) +add_definitions(-DHAVE_CONFIG_H -DEXTERNAL_SECP256) add_library(libsecp256k1 ${sources} ${headers}) \ No newline at end of file diff --git a/iguana/secp256k1/src/secp256k1.c b/iguana/secp256k1/src/secp256k1.c index 922caf6cb..4407c6ed8 100644 --- a/iguana/secp256k1/src/secp256k1.c +++ b/iguana/secp256k1/src/secp256k1.c @@ -66,6 +66,8 @@ struct secp256k1_context_struct { secp256k1_callback error_callback; }; +#ifndef EXTERNAL_SECP256 + secp256k1_context* secp256k1_context_create(unsigned int flags) { secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); ret->illegal_callback = default_illegal_callback; @@ -137,39 +139,6 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co ctx->error_callback.data = data; } -static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { - if (sizeof(secp256k1_ge_storage) == 64) { - /* When the secp256k1_ge_storage type is exactly 64 byte, use its - * representation inside secp256k1_pubkey, as conversion is very fast. - * Note that secp256k1_pubkey_save must use the same representation. */ - secp256k1_ge_storage s; - memcpy(&s, &pubkey->data[0], 64); - secp256k1_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - secp256k1_fe x, y; - secp256k1_fe_set_b32(&x, pubkey->data); - secp256k1_fe_set_b32(&y, pubkey->data + 32); - secp256k1_ge_set_xy(ge, &x, &y); - } - ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); - return 1; -} - -static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { - if (sizeof(secp256k1_ge_storage) == 64) { - secp256k1_ge_storage s; - secp256k1_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, 64); - } else { - VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); - secp256k1_fe_normalize_var(&ge->x); - secp256k1_fe_normalize_var(&ge->y); - secp256k1_fe_get_b32(pubkey->data, &ge->x); - secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); - } -} - int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { secp256k1_ge Q; @@ -577,14 +546,49 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * # include "modules/ecdh/main_impl.h" #endif -#ifdef ENABLE_MODULE_SCHNORR -# include "modules/schnorr/main_impl.h" -#endif - #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/main_impl.h" #endif +#endif + +static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { + if (sizeof(secp256k1_ge_storage) == 64) { + /* When the secp256k1_ge_storage type is exactly 64 byte, use its + * representation inside secp256k1_pubkey, as conversion is very fast. + * Note that secp256k1_pubkey_save must use the same representation. */ + secp256k1_ge_storage s; + memcpy(&s, &pubkey->data[0], 64); + secp256k1_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe x, y; + secp256k1_fe_set_b32(&x, pubkey->data); + secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_ge_set_xy(ge, &x, &y); + } + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { + if (sizeof(secp256k1_ge_storage) == 64) { + secp256k1_ge_storage s; + secp256k1_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, 64); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(pubkey->data, &ge->x); + secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); + } +} + +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/main_impl.h" +#endif + #ifdef ENABLE_MODULE_RANGEPROOF # include "modules/rangeproof/main_impl.h" #endif