diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 38c1169bb..1dd67762f 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -313,7 +313,7 @@ struct iguana_info void *electrum; void *ctx; uint64_t maxamount,kmd_equiv,balanceA,balanceB,valuesumA,valuesumB; uint8_t pubkey33[33],zcash; - int32_t privkeydepth; + int32_t privkeydepth,bobfillheight; void *curl_handle; portable_mutex_t curl_mutex; bits256 cachedtxid,notarizationtxid; uint8_t *cachedtxiddata; int32_t cachedtxidlen; bits256 cachedmerkle,notarizedhash; int32_t cachedmerkleheight; @@ -532,6 +532,7 @@ void HashKeccak(uint8_t *hash,void *data,size_t len); void test_validate(struct iguana_info *coin,char *signedtx); void LP_instantdex_depositadd(char *coinaddr,bits256 txid); int64_t LP_instantdex_creditcalc(struct iguana_info *coin,int32_t dispflag,bits256 txid,char *refaddr,char *origcoinaddr); +char *LP_autofillbob(struct iguana_info *coin,uint64_t satoshis); void LP_ports(uint16_t *pullportp,uint16_t *pubportp,uint16_t *busportp,uint16_t netid); int32_t LP_destaddr(char *destaddr,cJSON *item); int32_t LP_waitmempool(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t duration); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1c58d9e58..bde3532cc 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -90,7 +90,7 @@ void LP_millistats_update(struct LP_millistats *mp) #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; +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,LP_gtcmutex; int32_t LP_canbind; char *Broadcaststr,*Reserved_msgs[2][1000]; int32_t num_Reserved_msgs[2],max_Reserved_msgs[2]; @@ -1110,6 +1110,7 @@ void LP_swapsloop(void *ctx) sleep(6); } } + LP_gtc_iteration(ctx,LP_myipaddr,LP_mypubsock); } } @@ -1473,6 +1474,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu portable_mutex_init(&LP_blockinit_mutex); portable_mutex_init(&LP_pendswap_mutex); portable_mutex_init(&LP_listmutex); + portable_mutex_init(&LP_gtcmutex); myipaddr = clonestr("127.0.0.1"); #ifndef _WIN32 #ifndef FROM_JS diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 1696f99a8..858aca8d6 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -18,6 +18,15 @@ // LP_ordermatch.c // marketmaker // + +struct LP_gtcorder +{ + struct LP_gtcorder *next,*prev; + struct LP_quoteinfo Q; + double maxprice; + uint32_t cancelled,pending; +} *GTCorders; + struct LP_quoteinfo LP_Alicequery,LP_Alicereserved; double LP_Alicemaxprice; bits256 LP_Alicedestpubkey,LP_bobs_reserved; @@ -567,10 +576,43 @@ int32_t LP_connectstartbob(void *ctx,int32_t pubsock,char *base,char *rel,double return(retval); } +void LP_gtc_iteration(void *ctx,char *myipaddr,int32_t mypubsock) +{ + struct LP_gtcorder *gtc,*tmp; struct LP_quoteinfo *qp; uint64_t destvalue,destvalue2; + if ( Alice_expiration != 0 ) + return; + DL_FOREACH_SAFE(GTCorders,gtc,tmp) + { + qp = >c->Q; + if ( gtc->cancelled == 0 && LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 ) + { + gtc->cancelled = (uint32_t)time(NULL); + LP_failedmsg(qp->R.requestid,qp->R.quoteid,-9997,qp->uuidstr); + } + if ( gtc->cancelled != 0 ) + { + portable_mutex_lock(&LP_gtcmutex); + DL_DELETE(GTCorders,gtc); + free(gtc); + portable_mutex_unlock(&LP_gtcmutex); + } + else + { + if ( time(NULL) > gtc->pending+LP_AUTOTRADE_TIMEOUT*10 ) + { + qp->timestamp = (uint32_t)time(NULL); + LP_query(ctx,myipaddr,mypubsock,"request",qp); + LP_Alicequery = *qp, LP_Alicemaxprice = gtc->maxprice, Alice_expiration = qp->timestamp + 2*LP_AUTOTRADE_TIMEOUT, LP_Alicedestpubkey = qp->srchash; + char str[65]; printf("LP_gtc fill.%d gtc.%d %s/%s %.8f vol %.8f dest.(%s) maxprice %.8f etomicdest.(%s) uuid.%s fill.%d gtc.%d\n",qp->fill,qp->gtc,qp->srccoin,qp->destcoin,dstr(qp->satoshis),dstr(qp->destsatoshis),bits256_str(str,LP_Alicedestpubkey),gtc->maxprice,qp->etomicdest,qp->uuidstr,qp->fill,qp->gtc); + break; + } + } + } +} + char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *qp,double maxprice,int32_t timeout,int32_t duration,uint32_t tradeid,bits256 destpubkey,char *uuidstr) { - double price; - price = 0.; + struct LP_gtcorder *gtc; memset(qp->txid.bytes,0,sizeof(qp->txid)); qp->txid2 = qp->txid; qp->aliceid = LP_aliceid_calc(qp->desttxid,qp->destvout,qp->feetxid,qp->feevout); @@ -578,8 +620,20 @@ char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *q qp->tradeid = LP_rand(); qp->srchash = destpubkey; strncpy(qp->uuidstr,uuidstr,sizeof(qp->uuidstr)-1); + qp->timestamp = (uint32_t)time(NULL); + if ( qp->gtc != 0 ) + { + strcpy(&qp->uuidstr[strlen(qp->uuidstr)-6],"cccccc"); + gtc = calloc(1,sizeof(*gtc)); + gtc->Q = *qp; + gtc->maxprice = maxprice; + gtc->pending = (uint32_t)time(NULL); + portable_mutex_lock(&LP_gtcmutex); + DL_APPEND(GTCorders,gtc); + portable_mutex_unlock(&LP_gtcmutex); + } LP_query(ctx,myipaddr,mypubsock,"request",qp); - LP_Alicequery = *qp, LP_Alicemaxprice = maxprice, Alice_expiration = qp->timestamp + timeout, LP_Alicedestpubkey = destpubkey; + LP_Alicequery = *qp, LP_Alicemaxprice = maxprice, Alice_expiration = qp->timestamp + timeout, LP_Alicedestpubkey = qp->srchash; char str[65]; printf("LP_trade fill.%d gtc.%d %s/%s %.8f vol %.8f dest.(%s) maxprice %.8f etomicdest.(%s) uuid.%s fill.%d gtc.%d\n",qp->fill,qp->gtc,qp->srccoin,qp->destcoin,dstr(qp->satoshis),dstr(qp->destsatoshis),bits256_str(str,LP_Alicedestpubkey),maxprice,qp->etomicdest,qp->uuidstr,qp->fill,qp->gtc); return(LP_recent_swaps(0,uuidstr)); } @@ -628,16 +682,45 @@ char *LP_cancel_order(char *uuidstr) int32_t num = 0; cJSON *retjson; if ( uuidstr != 0 ) { - num = LP_trades_canceluuid(uuidstr); - retjson = cJSON_CreateObject(); - jaddstr(retjson,"result","success"); - jaddnum(retjson,"numentries",num); - if ( strcmp(LP_Alicequery.uuidstr,uuidstr) == 0 ) + if ( uuidstr[0] == 'G' ) { - LP_failedmsg(LP_Alicequery.R.requestid,LP_Alicequery.R.quoteid,-9998,LP_Alicequery.uuidstr); - LP_alicequery_clear(); - jaddstr(retjson,"status","uuid canceled"); - } else jaddstr(retjson,"status","will stop trade negotiation, but if swap started it wont cancel"); + struct LP_gtcorder *gtc,*tmp; + DL_FOREACH_SAFE(GTCorders,gtc,tmp) + { + if ( strcmp(gtc->Q.uuidstr,uuidstr) == 0 ) + { + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"cancelled",uuidstr); + jaddnum(retjson,"pending",gtc->pending); + if ( gtc->cancelled == 0 ) + { + gtc->cancelled = (uint32_t)time(NULL); + jaddstr(retjson,"status","uuid canceled"); + LP_failedmsg(gtc->Q.R.requestid,gtc->Q.R.quoteid,-9997,gtc->Q.uuidstr); + } + else + { + jaddstr(retjson,"status","uuid already canceled"); + LP_failedmsg(gtc->Q.R.requestid,gtc->Q.R.quoteid,-9996,gtc->Q.uuidstr); + } + } + } + return(clonestr("{\"error\":\"gtc uuid not found\"}")); + } + else + { + num = LP_trades_canceluuid(uuidstr); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + jaddnum(retjson,"numentries",num); + if ( strcmp(LP_Alicequery.uuidstr,uuidstr) == 0 ) + { + LP_failedmsg(LP_Alicequery.R.requestid,LP_Alicequery.R.quoteid,-9998,LP_Alicequery.uuidstr); + LP_alicequery_clear(); + jaddstr(retjson,"status","uuid canceled"); + } else jaddstr(retjson,"status","will stop trade negotiation, but if swap started it wont cancel"); + } return(jprint(retjson,1)); } return(clonestr("{\"error\":\"uuid not cancellable\"}")); @@ -917,7 +1000,7 @@ double LP_trades_pricevalidate(struct LP_quoteinfo *qp,struct iguana_info *coin, struct LP_quoteinfo *LP_trades_gotrequest(void *ctx,struct LP_quoteinfo *qp,struct LP_quoteinfo *newqp,char *pairstr) { int32_t voliters=10,priceiters=33; - double price=0.,p=0.,qprice,myprice,bestprice,range,bid,ask; struct iguana_info *coin,*othercoin; struct LP_utxoinfo A,B,*autxo,*butxo; cJSON *reqjson; char str[65]; struct LP_address_utxo *utxos[4096]; int32_t i,j,r,counter,max = (int32_t)(sizeof(utxos)/sizeof(*utxos)); + double price=0.,p=0.,qprice,myprice,bestprice,range,bid,ask; uint64_t satoshis; struct iguana_info *coin,*othercoin; struct LP_utxoinfo A,B,*autxo,*butxo; cJSON *reqjson,*retjson; char str[65],*retstr,*txidstr,*hexstr; struct LP_address_utxo *utxos[4096]; int32_t i,j,notarized,r,num,counter,max = (int32_t)(sizeof(utxos)/sizeof(*utxos)); *newqp = *qp; qp = newqp; printf("bob %s received REQUEST.(%s) fill.%d gtc.%d\n",bits256_str(str,G.LP_mypub25519),qp->uuidstr+32,qp->fill,qp->gtc); @@ -1017,6 +1100,8 @@ printf("bob %s received REQUEST.(%s) fill.%d gtc.%d\n",bits256_str(str,G.LP_mypu qp->quotetime = (uint32_t)time(NULL); break; } + if ( qp->fill != 0 ) + break; qp->destsatoshis = (qp->destsatoshis * 2) / 3; } if ( butxo != 0 && j < voliters ) @@ -1049,7 +1134,29 @@ printf("bob %s received REQUEST.(%s) fill.%d gtc.%d\n",bits256_str(str,G.LP_mypu } else if ( qp->fill != 0 || i == priceiters ) { - printf("i.%d cant find utxopair aliceid.%llu %s/%s %.8f -> relvol %.8f\n",i,(long long)qp->aliceid,qp->srccoin,qp->destcoin,dstr(LP_basesatoshis(dstr(qp->destsatoshis),price,qp->txfee,qp->desttxfee)),dstr(qp->destsatoshis)); + printf("i.%d cant find utxopair aliceid.%llu %s/%s %.8f -> relvol %.8f txfee %.8f\n",i,(long long)qp->aliceid,qp->srccoin,qp->destcoin,dstr(LP_basesatoshis(dstr(qp->destsatoshis),price,qp->txfee,qp->desttxfee)),dstr(qp->destsatoshis),dstr(qp->txfee)); + if ( qp->gtc != 0 && qp->fill != 0 && coin != 0 && LP_getheight(¬arized,coin) > coin->bobfillheight+3 ) + { + satoshis = LP_basesatoshis(dstr(qp->destsatoshis),price,qp->txfee,qp->desttxfee) + 3*qp->txfee; + LP_address_utxo_reset(&num,coin); + if ( (retstr= LP_autofillbob(coin,satoshis*1.02)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (hexstr= jstr(retjson,"hex")) != 0 ) + { + if ( (txidstr= LP_sendrawtransaction(coin->symbol,hexstr,0)) != 0 ) + { + printf("autofill created %s\n",txidstr); + free(txidstr); + coin->bobfillheight = LP_getheight(¬arized,coin); + } + } + free_json(retjson); + } + free(retstr); + } + } return(0); } else @@ -1668,8 +1775,8 @@ char *LP_autobuy(void *ctx,int32_t fomoflag,char *myipaddr,int32_t mypubsock,cha } } int32_t changed; - Q.gtc = gtcflag; Q.fill = fillflag; + Q.gtc = gtcflag; LP_mypriceset(&changed,rel,base,1. / maxprice); LP_mypriceset(&changed,base,rel,0.); if ( uuidstr == 0 || uuidstr[0] == 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 0e59fc626..b41a809fa 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -1038,7 +1038,7 @@ cJSON *LP_blockjson(int32_t *heightp,char *symbol,char *blockhashstr,int32_t hei coin = LP_coinfind(symbol); if ( coin == 0 || coin->electrum != 0 ) { - printf("unexpected electrum path for %s\n",symbol); + //printf("unexpected electrum path for %s\n",symbol); return(0); } if ( blockhashstr == 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 91e5f7f93..f7352fe36 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1887,7 +1887,7 @@ char *LP_withdraw(struct iguana_info *coin,cJSON *argjson) if ( autofee != 0 && iter == 0 && strcmp(coin->symbol,"BTC") == 0 ) { txfee = newtxfee = LP_txfeecalc(coin,0,datalen); - printf("txfee %.8f -> newtxfee %.8f, numvins.%d\n",dstr(txfee),dstr(newtxfee),numvins); + printf("txfee %.8f -> newtxfee %.8f, numvins.%d datalen.%d\n",dstr(txfee),dstr(newtxfee),numvins,datalen); for (i=0; ietomic[0] == 0 ) + { + if ( coin->electrum != 0 ) + balance = LP_unspents_load(coin->symbol,coin->smartaddr); + else balance = LP_RTsmartbalance(coin); + if ( strcmp("BTC",coin->symbol) == 0 ) + txfee = LP_txfeecalc(coin,0,1000); + balance -= (txfee + 1000000); + if ( balance < (satoshis<<2) ) + return(clonestr("{\"error\":\"couldnt autofill balance too small\"}")); + if ( balance > satoshis+3*txfee && balance >= (txfee + 1000000) ) + { + argjson = cJSON_CreateObject(); + outputs = cJSON_CreateArray(); + item = cJSON_CreateObject(); + jaddnum(item,coin->smartaddr,dstr(satoshis + 3000000)); + jaddi(outputs,item); + item = cJSON_CreateObject(); + jaddnum(item,coin->smartaddr,dstr(LP_DEPOSITSATOSHIS(satoshis) + 3000000)); + jaddi(outputs,item); + item = cJSON_CreateObject(); + jaddnum(item,coin->smartaddr,0.0001); + jaddi(outputs,item); + jadd(argjson,"outputs",outputs); + jaddnum(argjson,"broadcast",0); + jaddstr(argjson,"coin",coin->symbol); + retstr = LP_withdraw(coin,argjson); + free_json(argjson); + return(retstr); + } else return(clonestr("{\"error\":\"balance too small to autosplit, please make more deposits\"}")); + } + return(clonestr("{\"error\":\"couldnt autofill etomic needs separate support\"}")); +} + char *LP_movecoinbases(char *symbol) { static bits256 zero; bits256 utxotxid,txid; struct iguana_info *coin; cJSON *retjson,*outputs,*argjson,*txids,*unspents,*item,*gen,*output; int32_t i,n,utxovout; char *retstr,*hexstr;