diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 239ab6e6b..3c8ae9cf8 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -104,9 +104,11 @@ enable(coin)\n\ disable(coin)\n\ inventory(coin)\n\ bestfit(rel, relvolume)\n\ +lastnonce()\n\ buy(base, rel, price, relvolume, timeout=10, duration=3600, nonce)\n\ sell(base, rel, price, basevolume, timeout=10, duration=3600, nonce)\n\ withdraw(coin, outputs[])\n\ +sendrawtransaction(coin, signedtx)\n\ swapstatus()\n\ swapstatus(requestid, quoteid)\n\ public API:\n \ @@ -279,13 +281,17 @@ dividends(coin, height, )\n\ return(jprint(LP_electrumserver(ptr,jstr(argjson,"ipaddr"),juint(argjson,"port")),1)); } else return(clonestr("{\"error\":\"cant find coind\"}")); } + else if ( strcmp(method,"sendrawtransaction") == 0 ) + { + return(LP_sendrawtransaction(coin,jstr(argjson,"signedtx"))); + } else if ( strcmp(method,"withdraw") == 0 ) { if ( (ptr= LP_coinsearch(coin)) != 0 ) { if ( jobj(argjson,"outputs") == 0 ) return(clonestr("{\"error\":\"withdraw needs to have outputs\"}")); - //else return(LP_withdraw(ptr,argjson)); + else return(LP_withdraw(ptr,argjson)); } return(clonestr("{\"error\":\"cant find coind\"}")); } @@ -359,6 +365,13 @@ dividends(coin, height, )\n\ return(basilisk_swapentry(requestid,quoteid)); else return(basilisk_swaplist(0,0)); } + else if ( strcmp(method,"lastnonce") == 0 ) + { + cJSON *retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + jaddnum(retjson,"lastnonce",LP_lastnonce); + return(jprint(retjson,1)); + } else if ( strcmp(method,"myprices") == 0 ) return(LP_myprices()); else if ( strcmp(method,"trust") == 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 2cf2e8fc0..b816be396 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -332,5 +332,6 @@ struct LP_utxoinfo *_LP_utxofind(int32_t iambob,bits256 txid,int32_t vout); struct LP_utxoinfo *_LP_utxo2find(int32_t iambob,bits256 txid,int32_t vout); void LP_listunspent_query(char *symbol,char *coinaddr); +int32_t bitcoin_priv2wif(uint8_t wiftaddr,char *wifstr,bits256 privkey,uint8_t addrtype); #endif diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 961f36ef3..080400f5d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -171,7 +171,7 @@ void queue_loop(void *ignore) if ( duplicate > 0 ) { LP_Qfound++; - if ( (LP_Qfound % 10) == 0 ) + if ( (LP_Qfound % 100) == 0 ) printf("found.%u Q.%d err.%d match.%d\n",ptr->crc32,LP_Qenqueued,LP_Qerrors,LP_Qfound); flag = 1; } diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c7cffdaa3..7c2bc6f69 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -904,7 +904,7 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson, { if ( LP_isavailable(butxo) > 0 ) { - butxo->T.swappending = Q.timestamp + LP_RESERVETIME; + autxo->T.swappending = butxo->T.swappending = Q.timestamp + LP_RESERVETIME; retjson = LP_quotejson(&Q); butxo->S.otherpubkey = jbits256(argjson,"desthash"); LP_unavailableset(butxo,butxo->S.otherpubkey); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 1ebceefeb..ed1f832cd 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -419,6 +419,24 @@ int32_t LP_address_ismine(char *symbol,char *address) return(doneflag); } +int32_t LP_address_isvalid(char *symbol,char *address) +{ + int32_t isvalid = 0; cJSON *retjson; + if ( symbol == 0 || symbol[0] == 0 ) + return(0); + if ( (retjson= LP_validateaddress(symbol,address)) != 0 ) + { + if ( jobj(retjson,"isvalid") != 0 && is_cJSON_True(jobj(retjson,"isvalid")) != 0 ) + { + isvalid = 1; + //printf("%s ismine (%s)\n",address,jprint(retjson,0)); + } + //printf("%s\n",jprint(retjson,0)); + free_json(retjson); + } + return(isvalid); +} + cJSON *LP_listunspent(char *symbol,char *coinaddr) { char buf[128]; cJSON *retjson; struct iguana_info *coin; @@ -612,9 +630,9 @@ double LP_getestimatedrate(struct iguana_info *coin) char *LP_sendrawtransaction(char *symbol,char *signedtx) { cJSON *array,*errobj; char *paramstr,*tmpstr,*retstr=0; int32_t n,alreadyflag = 0; cJSON *retjson; struct iguana_info *coin; - if ( symbol == 0 || symbol[0] == 0 ) + if ( symbol == 0 || symbol[0] == 0 || signedtx == 0 || signedtx[0] == 0 ) { - printf("LP_sendrawtransaction null symbol\n"); + printf("LP_sendrawtransaction null symbol %p or signedtx.%p\n",symbol,signedtx); return(0); } coin = LP_coinfind(symbol); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 5213c3897..f7b7ead7f 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -724,18 +724,244 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch return(signedtx); } -/*char *LP_withdraw(struct iguana_info *coin,cJSON *argjson) +int32_t LP_vin_select(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct LP_address_utxo **utxos,int32_t numunspents,uint64_t value,int32_t maxmode) { - int32_t iter,i,datalen; char changeaddr[64],*signedtx=0; cJSON *retjson; bits256 signedtxid; uint64_t txfee,newtxfee=10000; + int32_t i,abovei,belowi; int64_t above,below,gap,atx_value; + abovei = belowi = -1; + for (above=below=i=0; iU.value) <= 0 ) + { + //printf("illegal value.%d\n",i); + continue; + } + if ( atx_value == value ) + { + *aboveip = *belowip = i; + *abovep = *belowp = 0; + return(i); + } + else if ( atx_value > value ) + { + gap = (atx_value - value); + if ( above == 0 || gap < above ) + { + above = gap; + abovei = i; + } + } else gap = (value - atx_value); + if ( below == 0 || gap < below ) + { + below = gap; + belowi = i; + } + } + *aboveip = abovei; + *abovep = above; + *belowip = belowi; + *belowp = below; + //printf("above.%d below.%d\n",abovei,belowi); + return(abovei >= 0 && above < (below>>1) ? abovei : belowi); +} + +cJSON *LP_inputjson(bits256 txid,int32_t vout,char *spendscriptstr) +{ + cJSON *sobj,*item = cJSON_CreateObject(); + jaddbits256(item,"txid",txid); + jaddnum(item,"vout",vout); + sobj = cJSON_CreateObject(); + jaddstr(sobj,"hex",spendscriptstr); + jadd(item,"scriptPubKey",sobj); + return(item); +} + +int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_t amount,struct vin_info *V,struct LP_address_utxo **utxos,int32_t numunspents,int32_t suppress_pubkeys,int32_t ignore_cltverr,bits256 privkey,cJSON *privkeys,cJSON *vins,uint8_t *script,int32_t scriptlen) +{ + char wifstr[128],spendscriptstr[128]; int32_t i,n,ind,abovei,belowi,maxmode=0; struct vin_info *vp; struct LP_address_utxo *up; int64_t above,below,remains = amount,total = 0; + *totalp = 0; + init_hexbytes_noT(spendscriptstr,script,scriptlen); + bitcoin_priv2wif(coin->wiftaddr,wifstr,privkey,coin->wiftype); + for (i=n=0; i= 0 ) + ind = abovei; + else ind = belowi; + if ( ind < 0 ) + { + printf("error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,numunspents,dstr(remains),dstr(amount),abovei,belowi,ind); + return(0); + } + up = utxos[ind]; + utxos[ind] = utxos[--numunspents]; + utxos[numunspents] = 0; + total += up->U.value; + remains -= up->U.value; + if ( remains <= 0 ) + break; + if ( numunspents == 0 ) + { + printf("total %.8f not enough for amount %.8f\n",dstr(total),dstr(amount)); + return(0); + } + vp = &V[n++]; + vp->N = vp->M = 1; + vp->signers[0].privkey = privkey; + jaddistr(privkeys,wifstr); + bitcoin_pubkey33(ctx,vp->signers[0].pubkey,privkey); + vp->suppress_pubkeys = suppress_pubkeys; + vp->ignore_cltverr = ignore_cltverr; + jaddi(vins,LP_inputjson(up->U.txid,up->U.vout,spendscriptstr)); + //printf("%s value %.8f -> remains %.8f\n",coinaddr,dstr(value),dstr(remains)); + } + *totalp = total; + return(n); +} + +char *LP_createrawtransaction(int32_t *numvinsp,struct iguana_info *coin,struct vin_info *V,int32_t max,bits256 privkey,cJSON *outputs,cJSON *vins,cJSON *privkeys) +{ + static void *ctx; + cJSON *txobj,*item; uint8_t addrtype,rmd160[20],script[64],spendscript[64]; char *coinaddr,*rawtxbytes; bits256 txid; uint32_t timestamp,locktime; int64_t change=0,adjust=0,total,value,amount = 0; int32_t i,scriptlen,spendlen,suppress_pubkeys,ignore_cltverr,numvouts=0,numvins=0,numutxos=0; struct LP_address_utxo *utxos[256]; struct LP_address *ap; + if ( ctx == 0 ) + ctx = bitcoin_ctx(); + *numvinsp = 0; + if ( sizeof(utxos)/sizeof(*utxos) != max ) + { + printf("LP_createrawtransaction: internal error %ld != max.%d\n",sizeof(utxos)/sizeof(*utxos),max); + return(0); + } + if ( coin == 0 || outputs == 0 || (numvouts= cJSON_GetArraySize(outputs)) <= 0 ) + { + printf("LP_createrawtransaction: illegal coin.%p outputs.%p or arraysize.%d, error\n",coin,outputs,numvouts); + return(0); + } + for (i=0; isymbol,coinaddr) <= 0 ) + { + printf("LP_createrawtransaction %s i.%d of %d is invalid\n",coinaddr,i,numvouts); + return(0); + } + if ( (value= j64bits(item,coinaddr)) <= 0 ) + { + printf("cant get value %s i.%d of %d %s\n",coinaddr,i,numvouts,jprint(outputs,0)); + return(0); + } + amount += value; + } + else + { + printf("cant get fieldname.%d of %d %s\n",i,numvouts,jprint(outputs,0)); + return(0); + } + } + LP_listunspent_issue(coin->symbol,coin->smartaddr,1); + if ( (ap= LP_addressfind(coin,coin->smartaddr)) == 0 ) + { + printf("LP_createrawtransaction: cant find address data\n"); + return(0); + } + memset(utxos,0,sizeof(utxos)); + if ( (numutxos= LP_address_utxo_ptrs(0,utxos,max,ap)) <= 0 ) + { + printf("LP_createrawtransaction: address_utxo_ptrs %d, error\n",numutxos); + return(0); + } + ignore_cltverr = 0; + suppress_pubkeys = 1; + scriptlen = bitcoin_standardspend(script,0,G.LP_myrmd160); + numvins = LP_vins_select(ctx,coin,&total,amount,V,utxos,numutxos,suppress_pubkeys,ignore_cltverr,privkey,privkeys,vins,script,scriptlen); + change = (total - amount); + timestamp = (uint32_t)time(NULL); + if ( strcmp("KMD",coin->symbol) == 0 ) + locktime = timestamp - 777; + else locktime = 0; + txobj = bitcoin_txcreate(coin->symbol,coin->isPoS,locktime,1,timestamp); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + if ( change < 6000 ) + { + adjust = change / numvouts; + change = 0; + } + for (i=0; itaddr,&addrtype,rmd160,coinaddr); + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,value + adjust); + } + else + { + printf("cant get fieldname.%d of %d %s\n",i,numvouts,jprint(outputs,0)); + return(0); + } + } + if ( change != 0 ) + txobj = bitcoin_txoutput(txobj,script,scriptlen,change); + if ( (rawtxbytes= bitcoin_json2hex(coin->isPoS,&txid,txobj,V)) != 0 ) + { + } else printf("error making rawtx suppress.%d\n",suppress_pubkeys); + free_json(privkeys); + free_json(txobj); + return(rawtxbytes); +} + +char *LP_withdraw(struct iguana_info *coin,cJSON *argjson) +{ + static void *ctx; + int32_t iter,completed=0,numvins,numvouts,datalen,suppress_pubkeys; bits256 privkey; char changeaddr[64],vinaddr[64],str[65],*signedtx=0,*rawtx=0; struct vin_info V[256]; cJSON *retjson,*outputs,*vins,*privkeys; struct iguana_msgtx msgtx; bits256 signedtxid; uint64_t txfee,newtxfee=10000; + if ( (outputs= jarray(&numvouts,argjson,"outputs")) == 0 ) + { + printf("no outputs in argjson (%s)\n",jprint(argjson,0)); + return(clonestr("{\"error\":\"no outputs specified\"}")); + } txfee = coin->txfee; + if ( ctx == 0 ) + ctx = bitcoin_ctx(); if ( txfee > 0 && txfee < 10000 ) txfee = 10000; - retjson = cJSON_CreateObject(); + suppress_pubkeys = 0; + memset(signedtxid.bytes,0,sizeof(signedtxid)); safecopy(changeaddr,coin->smartaddr,sizeof(changeaddr)); + safecopy(vinaddr,coin->smartaddr,sizeof(vinaddr)); + privkey = LP_privkey(vinaddr,coin->taddr); for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->wiftaddr,coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) + privkeys = cJSON_CreateArray(); + vins = cJSON_CreateArray(); + memset(V,0,sizeof(V)); + if ( (rawtx= LP_createrawtransaction(&numvins,coin,V,(int32_t)(sizeof(V)/sizeof(*V)),privkey,outputs,vins,privkeys)) != 0 ) { + completed = 0; + memset(&msgtx,0,sizeof(msgtx)); + memset(signedtxid.bytes,0,sizeof(signedtxid)); + if ( (completed= iguana_signrawtransaction(ctx,coin->symbol,coin->wiftaddr,coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&msgtx,&signedtx,&signedtxid,V,numvins,rawtx,vins,privkeys)) < 0 ) + printf("couldnt sign withdraw %s\n",bits256_str(str,signedtxid)); + else if ( completed == 0 ) + { + printf("incomplete signing withdraw (%s)\n",jprint(vins,0)); + if ( signedtx != 0 ) + free(signedtx), signedtx = 0; + } else printf("LP_withdraw %s -> %s\n",jprint(argjson,0),bits256_str(str,signedtxid)); datalen = (int32_t)strlen(signedtx) / 2; if ( strcmp(coin->symbol,"BTC") == 0 ) { @@ -743,11 +969,18 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); } else break; } else break; - if ( strcmp(str,"myfee") == 0 ) - break; + free(rawtx); + rawtx = 0; } + retjson = cJSON_CreateObject(); + if ( rawtx != 0 ) + jaddstr(retjson,"rawtx",rawtx); + if ( signedtx != 0 ) + jaddstr(retjson,"hex",signedtx); + jaddbits256(retjson,"txid",signedtxid); + jadd(retjson,"complete",completed!=0?jtrue():jfalse()); return(jprint(retjson,1)); -}*/ +} 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) { diff --git a/iguana/exchanges/install b/iguana/exchanges/install index 2aace6b1d..c624028e4 100755 --- a/iguana/exchanges/install +++ b/iguana/exchanges/install @@ -1,5 +1,5 @@ #!/bin/bash -cp setconfirms balance listunspent electrum snapshot_balance snapshot_loop secretaddresses dividends snapshot goals goal portfolio autoprice deletemessages getmessages debug register registerall buy sell bestfit orderbook client run_osx client_osx run coins disable enable myprice myprices getcoins getpeers getpeersIP getprices help inv setprice status ../dexscripts +cp setconfirms balance listunspent electrum snapshot_balance snapshot_loop secretaddresses dividends snapshot goals goal portfolio autoprice deletemessages getmessages debug buy sell bestfit orderbook client run_osx client_osx run coins disable enable myprice myprices getcoins getpeers getpeersIP getprices help inv setprice status ../dexscripts cp coins.json .. cd ../dexscripts #cp ../exchanges/passphrase ../exchanges/userpass . diff --git a/iguana/exchanges/register b/iguana/exchanges/register deleted file mode 100755 index d00160beb..000000000 --- a/iguana/exchanges/register +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -source userpass -curl --url "http://5.9.253.195:7783" --data "{\"userpass\":\"9bb4846d24136fc7c33515e45bccbab5c8fb7b57b411aa20057b371da9358255\",\"agent\":\"stats\",\"method\":\"register\",\"client\":\"6d3332be4904feafd326609bd76b66528dc7b2e2d75a7bd110c6bf8d19c4cf58\",\"pushaddr\":\"5.9.253.195\",\"pushport\":\"10000\"}" diff --git a/iguana/exchanges/registerall b/iguana/exchanges/registerall deleted file mode 100755 index 927f0b2f9..000000000 --- a/iguana/exchanges/registerall +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -source userpass -curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"registerall\",\"numnodes\":10}" diff --git a/iguana/exchanges/withdraw b/iguana/exchanges/withdraw new file mode 100755 index 000000000..1de924634 --- /dev/null +++ b/iguana/exchanges/withdraw @@ -0,0 +1,3 @@ +#!/bin/bash +source userpass +curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"withdraw\",\"coin\":\"KMD\",\"outputs\":[\"iRUgW6fLfVsLJ87Ng4zJTqNedJSKYQ9ToAf\":0.001, \"RUgW6fLfVsLJ87Ng4zJTqNedJSKYQ9ToAf\":0.002]}"