diff --git a/iguana/exchanges/LP_etomic.c b/iguana/exchanges/LP_etomic.c index c263738de..a52638ab7 100644 --- a/iguana/exchanges/LP_etomic.c +++ b/iguana/exchanges/LP_etomic.c @@ -404,3 +404,27 @@ int32_t LP_etomic_pub2addr(char *coinaddr,uint8_t pub64[64]) } return(-1); } + +int32_t LP_etomic_wait_for_confirmation(char *txId) +{ + EthTxReceipt receipt; + EthTxData txData; + do { + sleep(15); + printf("waiting for ETH txId to be confirmed: %s\n", txId); + receipt = getEthTxReceipt(txId); + if (receipt.confirmations < 1) { + txData = getEthTxData(txId); + if (txData.exists == 0) { + return(-1); + } + } + } while (receipt.confirmations < 1); + + if (strcmp(receipt.status, "0x1") != 0) { + printf("ETH txid %s receipt status failed\n", txId); + return(-1); + } + + return(receipt.confirmations); +} diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index dda7eb260..a96d197bc 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 @@ -104,7 +103,7 @@ int32_t LP_gettx_presence(int32_t *numconfirmsp,char *symbol,bits256 expectedtxi bits256 LP_broadcast(char *txname,char *symbol,char *txbytes,bits256 expectedtxid) { - char *retstr,*errstr; bits256 txid; uint8_t *ptr; cJSON *retjson,*errorobj; struct iguana_info *coin; int32_t i,totalretries=0,len,sentflag = 0; + char *retstr,*errstr; bits256 txid; uint8_t *ptr; cJSON *retjson,*errorobj; struct iguana_info *coin; int32_t i,totalretries=0,len,sentflag = 0,numconfirms=-1; coin = LP_coinfind(symbol); memset(&txid,0,sizeof(txid)); if ( txbytes == 0 || txbytes[0] == 0 ) @@ -120,7 +119,7 @@ bits256 LP_broadcast(char *txname,char *symbol,char *txbytes,bits256 expectedtxi for (i=0; i<2; i++) { //char str[65]; printf("LP_broadcast.%d (%s) %s i.%d sentflag.%d\n",i,symbol,bits256_str(str,expectedtxid),i,sentflag); - if ( sentflag == 0 && LP_gettx_presence(0,symbol,expectedtxid,0) != 0 ) + if ( sentflag == 0 && LP_gettx_presence(&numconfirms,symbol,expectedtxid,0) != 0 ) sentflag = 1; if ( sentflag == 0 && (retstr= LP_sendrawtransaction(symbol,txbytes)) != 0 ) { @@ -2204,6 +2203,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) { + if (LP_etomic_wait_for_confirmation(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); } @@ -2227,6 +2233,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) { + if (LP_etomic_wait_for_confirmation(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); @@ -2279,6 +2292,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) { + if (LP_etomic_wait_for_confirmation(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/etomicswap/bob.c b/iguana/exchanges/etomicswap/bob.c index 2ee3f5cc2..7239bb324 100644 --- a/iguana/exchanges/etomicswap/bob.c +++ b/iguana/exchanges/etomicswap/bob.c @@ -28,7 +28,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 +52,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 +75,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: @@ -88,7 +98,12 @@ int main(int argc, char** argv) 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: @@ -106,7 +121,12 @@ int main(int argc, char** argv) 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 +141,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 +164,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: @@ -158,7 +188,12 @@ int main(int argc, char** argv) 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: @@ -177,8 +212,12 @@ int main(int argc, char** argv) 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( @@ -187,8 +226,12 @@ int main(int argc, char** argv) getenv("BOB_PK") ); - 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_ETH_BALANCE: printf("%" PRIu64 "\n", getEthBalance(bobAddress)); @@ -199,9 +242,21 @@ int main(int argc, char** argv) 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; @@ -214,5 +269,6 @@ int main(int argc, char** argv) char weiBuffer[100]; satoshisToWei(weiBuffer, satoshis); printf("wei: %s\n", weiBuffer); + return 0; } diff --git a/iguana/exchanges/etomicswap/etomiccurl.c b/iguana/exchanges/etomicswap/etomiccurl.c index f80e87d3e..d39118e30 100644 --- a/iguana/exchanges/etomicswap/etomiccurl.c +++ b/iguana/exchanges/etomicswap/etomiccurl.c @@ -1,8 +1,5 @@ #include "etomiccurl.h" #include -#include -#include -#include "../../../includes/cJSON.h" static char *ethRpcUrl = ETOMIC_URL; @@ -36,6 +33,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 +88,145 @@ 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* sendRawTx(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); + } + cJSON_Delete(resultJson); return txId; } -int getNonce(char* address) +int64_t getNonce(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_getTransactionCount")); 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); + int64_t nonce = -1; + cJSON *nonceJson = sendRpcRequest("eth_getTransactionCount", params); + cJSON_Delete(params); + if (nonceJson != NULL && is_cJSON_String(nonceJson) && nonceJson != NULL) { + nonce = (int64_t) strtol(nonceJson->valuestring, NULL, 0); + } + cJSON_Delete(nonceJson); 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) { + 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; } diff --git a/iguana/exchanges/etomicswap/etomiccurl.h b/iguana/exchanges/etomicswap/etomiccurl.h index 3a0a9be1e..fcb768bd2 100644 --- a/iguana/exchanges/etomicswap/etomiccurl.h +++ b/iguana/exchanges/etomicswap/etomiccurl.h @@ -1,4 +1,8 @@ +#ifndef ETOMIC_CURL_HEADER +#define ETOMIC_CURL_HEADER + #include +#include #ifdef __cplusplus extern "C"{ @@ -14,15 +18,30 @@ extern "C"{ 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* 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(); #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..38efb0a08 100644 --- a/iguana/exchanges/etomicswap/etomiclib.cpp +++ b/iguana/exchanges/etomicswap/etomiclib.cpp @@ -77,8 +77,8 @@ char* aliceSendsEthPayment(AliceSendsEthPaymentInput input, BasicTxData txData) << toHex(jsToBytes(input.bobHash)) << "000000000000000000000000"; tx.data = jsToBytes(ss.str()); - char* rawTx = signTx(tx, txData.secretKey); - char* result = sendRawTx(rawTx); + char *rawTx = signTx(tx, txData.secretKey); + char *result = sendRawTx(rawTx); free(rawTx); return result; }