diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1d018dca9..a3c70645a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -18,219 +18,6 @@ // marketmaker // -// price query is redundant as there is a pricefeed for all pubkeys now -// get orderbook, find pubkey of the one offering it and directly reserve it -// then it is the same as current logic, just skip the "price" step -// "notified" push is wrong - -double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub) -{ - cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; - qp->desthash = mypub; - strcpy(qp->srccoin,base); - strcpy(qp->destcoin,rel); - qp->desthash = LP_mypubkey; - if ( strcmp(method,"request") == 0 ) - { - qp->quotetime = (uint32_t)time(NULL); - if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) - LP_unavailableset(utxo,qp->srchash); - else - { - printf("couldnt find my txid to make request\n"); - return(0.); - } - } - reqjson = LP_quotejson(qp); - if ( bits256_nonz(qp->desthash) != 0 ) - flag = 1; - jaddstr(reqjson,"method",method); - if ( strcmp(method,"price") != 0 ) - printf("QUERY.(%s)\n",jprint(reqjson,0)); - LP_forward(qp->srchash,jprint(reqjson,1),1); - for (i=0; i<30; i++) - { - if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) > SMALLVAL ) - { - if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) - { - //printf("break out of loop.%d price %.8f\n",i,price); - break; - } - } - usleep(100000); - } - return(price); -} - -int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) -{ - char *retstr,pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; - if ( (price= LP_price(base,rel)) > SMALLVAL ) - { - price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - if ( LP_quoteparse(&Q,argjson) < 0 ) - return(-2); - //printf("connect with.(%s)\n",jprint(argjson,0)); - Q.destsatoshis = Q.satoshis * price; - privkey = LP_privkey(utxo->coinaddr); - if ( bits256_nonz(utxo->S.mypub) == 0 ) - utxo->S.mypub = LP_pubkey(privkey); - if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) - { - nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); - if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating utxo->pair\n"); - else if ( nn_bind(pair,pairstr) >= 0 ) - { - LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - swap = LP_swapinit(1,0,privkey,&Q.R,&Q); - swap->N.pair = pair; - utxo->S.swap = swap; - swap->utxo = utxo; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) - { - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","connected"); - jaddstr(retjson,"pair",pairstr); - jaddnum(retjson,"requestid",Q.R.requestid); - jaddnum(retjson,"quoteid",Q.R.quoteid); - retstr = jprint(retjson,1); - if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else LP_forward(utxo->S.otherpubkey,retstr,1); - retval = 0; - } else printf("error launching swaploop\n"); - } else printf("printf error nn_connect to %s\n",pairstr); - } - else - { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); - } - } else printf("no price for %s/%s\n",base,rel); - if ( retval < 0 ) - { - if ( pair >= 0 ) - nn_close(pair); - LP_availableset(utxo); - } - return(retval); -} - -char *LP_connected(cJSON *argjson) // alice -{ - cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; - LP_quoteparse(&Q,argjson); - if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) - { - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) - { - char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(clonestr("{\"error\",\"src txid in mempool\"}")); - } - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) - { - char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(clonestr("{\"error\",\"dest txid in mempool\"}")); - } - retjson = cJSON_CreateObject(); - if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) - jaddstr(retjson,"error","couldnt create pairsock"); - else if ( nn_connect(pairsock,pairstr) >= 0 ) - { - LP_unavailableset(utxo,Q.srchash); - Q.privkey = LP_privkey(Q.destaddr); - LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); - swap->N.pair = pairsock; - utxo->S.swap = swap; - swap->utxo = utxo; - printf("alice pairstr.(%s)\n",pairstr); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) - { - jaddstr(retjson,"result","success"); - jadd(retjson,"trade",LP_quotejson(&Q)); - jaddnum(retjson,"requestid",Q.R.requestid); - jaddnum(retjson,"quoteid",Q.R.quoteid); - } else jaddstr(retjson,"error","couldnt aliceloop"); - } - return(jprint(retjson,1)); - } else return(clonestr("{\"result\",\"update stats\"}")); -} - -int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) -{ - char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; - if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) - { - retval = 1; - txid = jbits256(argjson,"txid"); - if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) - { - printf("LP_tradecommand.(%s)\n",jprint(argjson,0)); - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) - { - char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - utxo->T.spentflag = (uint32_t)time(NULL); - return(0); - } - if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) - utxo->T.swappending = 0; - if ( strcmp(method,"request") == 0 ) // bob - { - retval = 1; - if ( LP_isavailable(utxo) > 0 ) - { - if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) - { - price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - Q.timestamp = (uint32_t)time(NULL); - retjson = LP_quotejson(&Q); - utxo->S.otherpubkey = jbits256(argjson,"desthash"); - retval |= 2; - LP_unavailableset(utxo,jbits256(argjson,"desthash")); - jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); - jaddnum(retjson,"pending",utxo->T.swappending); - jaddbits256(retjson,"desthash",utxo->S.otherpubkey); - jaddstr(retjson,"method","reserved"); - retstr = jprint(retjson,1); - if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else LP_forward(utxo->S.otherpubkey,retstr,1); - utxo->T.lasttime = (uint32_t)time(NULL); - } else printf("null price\n"); - } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); - } - else if ( strcmp(method,"connect") == 0 ) // bob - { - retval = 4; - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,jstr(argjson,"destcoin"),jbits256(argjson,"desttxid"),jint(argjson,"destvout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"))) >= 0 ) - { - char str[65]; printf("LP_tradecommand fee selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(0); - } - if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) - LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); - else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); - } - } - } - return(retval); -} char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { @@ -271,7 +58,7 @@ myprice(base, rel)\n\ enable(coin)\n\ disable(coin)\n\ inventory(coin)\n\ -autotrade(base, rel, maxvolume, maxprice)\n\ +autotrade(base, rel, price, volume)\n\ swapstatus()\n\ swapstatus(requestid, quoteid)\n\ public API:\n \ @@ -361,21 +148,8 @@ forwardhex(pubkey,hex)\n\ return(jprint(retjson,1)); } } - else if ( (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) - { - bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; - txid = jbits256(argjson,"txid"); - if ( bits256_nonz(txid) == 0 ) - return(clonestr("{\"error\":\"invalid or missing txid\"}")); - if ( jobj(argjson,"vout") == 0 ) - return(clonestr("{\"error\":\"missing vout\"}")); - vout = jint(argjson,"vout"); - if ( (utxo= LP_utxofind(0,txid,vout)) == 0 ) - return(clonestr("{\"error\":\"txid/vout not found\"}")); - if ( strcmp(method,"candidates") == 0 ) - return(jprint(LP_tradecandidates(coin),1)); - else return(jprint(LP_autotrade(utxo,coin,jdouble(argjson,"maxprice")),1)); - } + else if ( strcmp(method,"autotrade") == 0 ) + return(LP_autotrade(base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); } else if ( strcmp(method,"swapstatus") == 0 ) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 87fe57170..7b4bd45aa 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -218,7 +218,7 @@ uint32_t basilisk_quoteid(struct basilisk_request *rp); struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); -double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); +//double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index eb6138967..252a5ccd4 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -483,7 +483,7 @@ cJSON *LP_orderbookjson(struct LP_orderbookentry *op) cJSON *item = cJSON_CreateObject(); if ( op->price > SMALLVAL ) { - jaddnum(item,"price",op->price ); + jaddnum(item,"price",op->price); jaddnum(item,"volume",dstr(op->basesatoshis)); jaddbits256(item,"txid",op->txid); jaddnum(item,"vout",op->vout); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index c1a104e3d..069d63575 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -145,22 +145,15 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * return(0); } -int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) +int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,uint32_t quotetime,uint64_t destsatoshis,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) { - if ( txfee != qp->txfee ) - { - if ( txfee >= value ) - return(-1); - qp->txfee = txfee; - qp->satoshis = value - txfee; - } - qp->timestamp = timestamp; qp->quotetime = quotetime; qp->destsatoshis = destsatoshis; - qp->desttxfee = desttxfee; qp->desttxid = desttxid; qp->destvout = destvout; qp->desthash = desthash; + qp->feetxid = feetxid; + qp->feevout = feevout; safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); return(0); } @@ -236,182 +229,291 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) return(-1); } -cJSON *LP_tradecandidates(char *base) +double LP_query(char *method,struct LP_quoteinfo *qp) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; - totaladded = 0; - HASH_ITER(hh,LP_peerinfos,peer,tmp) + cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; + if ( strcmp(method,"request") == 0 ) + { + qp->quotetime = (uint32_t)time(NULL); + if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) + LP_unavailableset(utxo,qp->srchash); + else + { + printf("couldnt find my txid to make request\n"); + return(0.); + } + } + reqjson = LP_quotejson(qp); + if ( bits256_nonz(qp->desthash) != 0 ) + flag = 1; + jaddstr(reqjson,"method",method); + printf("QUERY.(%s)\n",jprint(reqjson,0)); + LP_forward(qp->srchash,jprint(reqjson,1),1); + for (i=0; i<30; i++) { - printf("%s:%u %s\n",peer->ipaddr,peer->port,base); - n = added = 0; - if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) + if ( (price= LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout)) > SMALLVAL ) { - printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); - if ( (array= cJSON_Parse(utxostr)) != 0 ) + if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - retarray = cJSON_CreateArray(); - for (i=0; i SMALLVAL ) + { + price *= (1. + profitmargin); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + if ( LP_quoteparse(&Q,argjson) < 0 ) + return(-2); + printf("connect with.(%s)\n",jprint(argjson,0)); + Q.destsatoshis = Q.satoshis * price; + privkey = LP_privkey(utxo->coinaddr); + if ( bits256_nonz(utxo->S.mypub) == 0 ) + utxo->S.mypub = LP_pubkey(privkey); + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + { + printf("not eligible\n"); + return(-1); + } + if ( utxo->payment.value > (Q.satoshis << 1) ) + { + printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(utxo->payment.value),dstr(Q.satoshis)); + return(-1); + } + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + { + nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); + if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating utxo->pair\n"); + else if ( nn_bind(pair,pairstr) >= 0 ) + { + LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + swap = LP_swapinit(1,0,privkey,&Q.R,&Q); + swap->N.pair = pair; + utxo->S.swap = swap; + swap->utxo = utxo; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) + { + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","connected"); + jaddstr(retjson,"pair",pairstr); + jaddnum(retjson,"requestid",Q.R.requestid); + jaddnum(retjson,"quoteid",Q.R.quoteid); + retstr = jprint(retjson,1); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else LP_forward(utxo->S.otherpubkey,retstr,1); + retval = 0; + } else printf("error launching swaploop\n"); + } else printf("printf error nn_connect to %s\n",pairstr); + } + else { - printf("n.%d totaladded.%d vs added.%d\n",n,totaladded,added); - break; + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); } + } else printf("no price for %s/%s\n",base,rel); + if ( retval < 0 ) + { + if ( pair >= 0 ) + nn_close(pair); + LP_availableset(utxo); } - return(retarray); + return(retval); } -void LP_quotesinit(char *base,char *rel) +char *LP_connected(cJSON *argjson) // alice { - cJSON *array,*item; struct LP_quoteinfo Q; bits256 zero; int32_t i,n,iter; - memset(&zero,0,sizeof(zero)); - for (iter=0; iter<2; iter++) - if ( (array= LP_tradecandidates(iter == 0 ? base : rel)) != 0 ) + cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; + LP_quoteparse(&Q,argjson); + if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) { - //printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); - if ( (n= cJSON_GetArraySize(array)) > 0 ) + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) + { + char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(clonestr("{\"error\",\"src txid in mempool\"}")); + } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) + { + char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(clonestr("{\"error\",\"dest txid in mempool\"}")); + } + retjson = cJSON_CreateObject(); + if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + jaddstr(retjson,"error","couldnt create pairsock"); + else if ( nn_connect(pairsock,pairstr) >= 0 ) { - memset(&Q,0,sizeof(Q)); - for (i=0; iN.pair = pairsock; + utxo->S.swap = swap; + swap->utxo = utxo; + printf("alice pairstr.(%s)\n",pairstr); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) { - item = jitem(array,i); - LP_quoteparse(&Q,item); - if ( iter == 0 ) - LP_query("price",&Q,base,rel,zero); - else LP_query("price",&Q,rel,base,zero); - } + jaddstr(retjson,"result","success"); + jadd(retjson,"trade",LP_quotejson(&Q)); + jaddnum(retjson,"requestid",Q.R.requestid); + jaddnum(retjson,"quoteid",Q.R.quoteid); + } else jaddstr(retjson,"error","couldnt aliceloop"); } - free_json(array); - } + return(jprint(retjson,1)); + } else return(clonestr("{\"result\",\"update stats\"}")); } -cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) +int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - static bits256 zero; - int32_t i,n,besti,DEXselector=0; cJSON *array,*item,*bestitem=0; struct basilisk_request R; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; - bestprice = 0.; - if ( maxprice == 0. ) - maxprice = LP_price(base,myutxo->coin) / 0.975; - if ( (array= LP_tradecandidates(base)) != 0 ) + char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; + if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { - printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); - if ( (n= cJSON_GetArraySize(array)) > 0 ) + retval = 1; + txid = jbits256(argjson,"txid"); + if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - memset(prices,0,sizeof(prices)); - memset(Q,0,sizeof(Q)); - for (i=0; icoin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) { - item = jitem(array,i); - LP_quoteparse(&Q[i],item); - if ( (price= jdouble(item,"price")) == 0. ) - { - price = LP_query("price",&Q[i],base,myutxo->coin,zero); - Q[i].destsatoshis = price * Q[i].satoshis; - } - if ( (prices[i]= price) > SMALLVAL && (bestprice == 0. || price < bestprice) ) - bestprice = price; - char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + utxo->T.spentflag = (uint32_t)time(NULL); + return(0); } - if ( bestprice > SMALLVAL ) + if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) + utxo->T.swappending = 0; + if ( strcmp(method,"request") == 0 ) // bob { - bestmetric = 0.; - besti = -1; - for (i=0; i 0 ) { - if ( (price= prices[i]) > SMALLVAL && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) + if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) { - metric = price / bestprice; - printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); - if ( metric < 1.1 ) + price *= (1. + profitmargin); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { - metric = dstr(Q[i].destsatoshis) * metric * metric * metric; - printf("%f\n",metric); - if ( bestmetric == 0. || metric < bestmetric ) - { - besti = i; - bestmetric = metric; - } + printf("not eligible\n"); + return(-1); } - } else printf("(%f %f) ",dstr(myutxo->S.satoshis),dstr(Q[i].destsatoshis)); + Q.timestamp = (uint32_t)time(NULL); + retjson = LP_quotejson(&Q); + utxo->S.otherpubkey = jbits256(argjson,"desthash"); + retval |= 2; + LP_unavailableset(utxo,jbits256(argjson,"desthash")); + jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); + jaddnum(retjson,"pending",utxo->T.swappending); + jaddbits256(retjson,"desthash",utxo->S.otherpubkey); + jaddstr(retjson,"method","reserved"); + retstr = jprint(retjson,1); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else LP_forward(utxo->S.otherpubkey,retstr,1); + utxo->T.lasttime = (uint32_t)time(NULL); + } else printf("null price\n"); + } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); + } + else if ( strcmp(method,"connect") == 0 ) // bob + { + retval = 4; + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,jstr(argjson,"destcoin"),jbits256(argjson,"desttxid"),jint(argjson,"destvout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"))) >= 0 ) + { + char str[65]; printf("LP_tradecommand fee selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); } - printf("metrics, best %f\n",bestmetric); - if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) + if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) + LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); + else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); + } + } + } + return(retval); +} + +char *LP_autotrade(char *base,char *rel,double maxprice,double volume) +{ + uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) + return(clonestr("{\"error\":\"invalid parameter\"}")); + destsatoshis = SATOSHIDEN * volume; + if ( (autxo= LP_utxo_bestfit(rel,destsatoshis)) == 0 ) + return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); + bestmetric = ordermatchprice = 0.; + if ( (obookstr= LP_orderbook(base,rel)) != 0 ) + { + if ( (orderbook= cJSON_Parse(obookstr)) != 0 ) + { + if ( (asks= jarray(&numasks,orderbook,"asks")) != 0 ) + { + for (i=0; i SMALLVAL && price <= maxprice ) { - Q[i].desttxid = myutxo->payment.txid; - Q[i].destvout = myutxo->payment.vout; - Q[i].feetxid = myutxo->fee.txid; - Q[i].feevout = myutxo->fee.vout; - strcpy(Q[i].destaddr,myutxo->coinaddr); - Q[i].desthash = LP_mypubkey; - strcpy(Q[i].srccoin,base); - strcpy(Q[i].destcoin,myutxo->coin); - price = LP_query("request",&Q[i],base,myutxo->coin,myutxo->S.mypub); - if ( jobj(bestitem,"price") != 0 ) - jdelete(bestitem,"price"); - jaddnum(bestitem,"price",prices[i]); - if ( price <= maxprice ) - { - Q[i].desttxid = myutxo->payment.txid; - Q[i].destvout = myutxo->payment.vout; - Q[i].feetxid = myutxo->fee.txid; - Q[i].feevout = myutxo->fee.vout; - strcpy(Q[i].destaddr,myutxo->coinaddr); - Q[i].desthash = LP_mypubkey; - strcpy(Q[i].srccoin,base); - strcpy(Q[i].destcoin,myutxo->coin); - price = LP_query("connect",&Q[i],base,myutxo->coin,myutxo->S.mypub); - LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); - jaddstr(bestitem,"status","connected"); - jaddnum(bestitem,"requestid",R.requestid); - jaddnum(bestitem,"quoteid",R.quoteid); - printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); - } - else + pubkey = jbits256(item,"pubkey"); + if ( bits256_cmp(pubkey,LP_mypubkey) != 0 ) { - jaddstr(bestitem,"status","too expensive"); - jaddnum(bestitem,"price",price); - jaddnum(bestitem,"maxprice",maxprice); - jaddnum(bestitem,"bestprice",bestprice); + if ( bestprice == 0. ) // assumes price ordered asks + bestprice = price; + txid = jbits256(item,"txid"); + vout = jint(item,"vout"); + vol = jdouble(item,"volume"); + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + { + asatoshis = butxo->payment.value * price; + if ( asatoshis <= destsatoshis && destsatoshis > (asatoshis >> 1) ) + { + metric = price / bestprice; + printf("%f %f %f %f ",price,metric,dstr(asatoshis),metric * metric * metric); + if ( metric < 1.1 ) + { + metric = dstr(asatoshis) * metric * metric * metric; + printf("(%f) <- metric\n",metric); + if ( bestmetric == 0. || metric < bestmetric ) + { + bestutxo = butxo; + ordermatchprice = price; + bestmetric = metric; + } + } + } + } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } - } + } else break; } } - free_json(array); + free_json(orderbook); } + free(obookstr); } - if ( bestitem == 0 ) - return(cJSON_Parse("{\"error\":\"no match found\"}")); - return(bestitem); + if ( bestutxo == 0 || ordermatchprice == 0. ) + return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); + asatoshis = bestutxo->payment.value * ordermatchprice; + if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) + return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); + if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) + return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); + price = LP_query("request",&Q); + if ( price <= maxprice ) + { + bestitem = LP_quotejson(&Q); + price = LP_query("connect",&Q); + LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + jaddstr(bestitem,"status","connected"); + jaddnum(bestitem,"maxprice",maxprice); + jaddnum(bestitem,"requestid",Q.R.requestid); + jaddnum(bestitem,"quoteid",Q.R.quoteid); + printf("Alice r.%u q.%u\n",Q.R.requestid,Q.R.quoteid); + } else jaddstr(bestitem,"status","too expensive"); + return(jprint(bestitem,0)); } diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 2f2c39565..19e2adec8 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -1305,4 +1305,121 @@ int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct igu if ( LP_ismine(utxo) > 0 && strcmp(utxo->coin,base) == 0 ) LP_priceping(LP_mypubsock,utxo,rel,price * LP_profitratio); }*/ +/* +bestprice = 0.; +if ( (array= LP_tradecandidates(base)) != 0 ) +{ + printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + memset(prices,0,sizeof(prices)); + memset(Q,0,sizeof(Q)); + for (i=0; icoin,zero); + Q[i].destsatoshis = price * Q[i].satoshis; + } + if ( (prices[i]= price) > SMALLVAL && (bestprice == 0. || price < bestprice) ) + bestprice = price; + char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + } + if ( bestprice > SMALLVAL ) + { + bestmetric = 0.; + besti = -1; + for (i=0; i SMALLVAL && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) + { + metric = price / bestprice; + printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); + if ( metric < 1.1 ) + { + metric = dstr(Q[i].destsatoshis) * metric * metric * metric; + printf("%f\n",metric); + if ( bestmetric == 0. || metric < bestmetric ) + { + besti = i; + bestmetric = metric; + } + } + } else printf("(%f %f) ",dstr(myutxo->S.satoshis),dstr(Q[i].destsatoshis)); + } + printf("metrics, best %f\n",bestmetric); +*/ +/*cJSON *LP_tradecandidates(char *base) + { + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; + totaladded = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + printf("%s:%u %s\n",peer->ipaddr,peer->port,base); + n = added = 0; + if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) + { + printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); + if ( (array= cJSON_Parse(utxostr)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + retarray = cJSON_CreateArray(); + for (i=0; i 0 ) + { + memset(&Q,0,sizeof(Q)); + for (i=0; icoin,bits256_str(str,utxo->payment.txid)); + if ( strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && LP_ismine(utxo) > 0 ) + { + if ( utxo->payment.value >= destsatoshis && (bestutxo == 0 || utxo->payment.value < bestutxo->payment.value) ) + bestutxo = utxo; + } + } + return(bestutxo); +} + void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) { cJSON *argjson; struct _LP_utxoinfo u;