You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1092 lines
54 KiB

8 years ago
/******************************************************************************
* Copyright © 2014-2017 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
8 years ago
8 years ago
//
8 years ago
// LP_ordermatch.c
8 years ago
// marketmaker
//
7 years ago
uint64_t LP_txfeecalc(struct iguana_info *coin,uint64_t txfee)
8 years ago
{
7 years ago
if ( coin != 0 )
8 years ago
{
7 years ago
if ( strcmp(coin->symbol,"BTC") == 0 )
{
if ( txfee == 0 && (txfee= LP_getestimatedrate(coin) * LP_AVETXSIZE) < LP_MIN_TXFEE )
txfee = LP_MIN_TXFEE;
}
else txfee = coin->txfee;
if ( txfee < LP_MIN_TXFEE )
8 years ago
txfee = LP_MIN_TXFEE;
}
8 years ago
return(txfee);
}
void LP_txfees(uint64_t *txfeep,uint64_t *desttxfeep,char *base,char *rel)
{
7 years ago
*txfeep = LP_txfeecalc(LP_coinfind(base),0);
*desttxfeep = LP_txfeecalc(LP_coinfind(rel),0);
8 years ago
}
8 years ago
8 years ago
double LP_qprice_calc(int64_t *destsatoshisp,int64_t *satoshisp,double price,uint64_t b_satoshis,uint64_t txfee,uint64_t a_value,uint64_t maxdestsatoshis,uint64_t desttxfee)
{
uint64_t destsatoshis,satoshis;
a_value -= (desttxfee + 1);
destsatoshis = ((b_satoshis - txfee) * price);
if ( destsatoshis > a_value )
destsatoshis = a_value;
if ( maxdestsatoshis != 0 && destsatoshis > maxdestsatoshis-desttxfee-1 )
destsatoshis = maxdestsatoshis-desttxfee-1;
satoshis = (destsatoshis / price + 0.49) - txfee;
*destsatoshisp = destsatoshis;
*satoshisp = satoshis;
if ( satoshis > 0 )
return((double)destsatoshis / satoshis);
else return(0.);
}
8 years ago
struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srchash,bits256 desthash,char *src,uint64_t srcsatoshis,char *dest,uint64_t destsatoshis,uint32_t timestamp,uint32_t quotetime,int32_t DEXselector)
{
struct basilisk_request R;
memset(rp,0,sizeof(*rp));
rp->srchash = srchash;
rp->srcamount = srcsatoshis;
rp->timestamp = timestamp;
rp->DEXselector = DEXselector;
safecopy(rp->src,src,sizeof(rp->src));
safecopy(rp->dest,dest,sizeof(rp->dest));
R = *rp;
rp->requestid = basilisk_requestid(rp);
rp->quotetime = quotetime;
rp->desthash = desthash;
rp->destamount = destsatoshis;
rp->quoteid = basilisk_quoteid(rp);
8 years ago
printf("r.%u %u, q.%u %u: %s %.8f -> %s %.8f\n",rp->timestamp,rp->requestid,rp->quotetime,rp->quoteid,rp->src,dstr(rp->srcamount),rp->dest,dstr(rp->destamount));
8 years ago
return(rp);
}
cJSON *LP_quotejson(struct LP_quoteinfo *qp)
{
double price; cJSON *retjson = cJSON_CreateObject();
jaddstr(retjson,"base",qp->srccoin);
jaddstr(retjson,"rel",qp->destcoin);
if ( qp->coinaddr[0] != 0 )
jaddstr(retjson,"address",qp->coinaddr);
if ( qp->timestamp != 0 )
jaddnum(retjson,"timestamp",qp->timestamp);
if ( bits256_nonz(qp->txid) != 0 )
{
jaddbits256(retjson,"txid",qp->txid);
jaddnum(retjson,"vout",qp->vout);
}
if ( bits256_nonz(qp->srchash) != 0 )
jaddbits256(retjson,"srchash",qp->srchash);
if ( qp->txfee != 0 )
jadd64bits(retjson,"txfee",qp->txfee);
if ( qp->quotetime != 0 )
jaddnum(retjson,"quotetime",qp->quotetime);
if ( qp->satoshis != 0 )
jadd64bits(retjson,"satoshis",qp->satoshis);
if ( bits256_nonz(qp->desthash) != 0 )
jaddbits256(retjson,"desthash",qp->desthash);
if ( bits256_nonz(qp->txid2) != 0 )
{
jaddbits256(retjson,"txid2",qp->txid2);
jaddnum(retjson,"vout2",qp->vout2);
}
8 years ago
if ( bits256_nonz(qp->desttxid) != 0 )
8 years ago
{
if ( qp->destaddr[0] != 0 )
jaddstr(retjson,"destaddr",qp->destaddr);
jaddbits256(retjson,"desttxid",qp->desttxid);
jaddnum(retjson,"destvout",qp->destvout);
}
if ( bits256_nonz(qp->feetxid) != 0 )
{
jaddbits256(retjson,"feetxid",qp->feetxid);
jaddnum(retjson,"feevout",qp->feevout);
}
if ( qp->desttxfee != 0 )
jadd64bits(retjson,"desttxfee",qp->desttxfee);
8 years ago
if ( qp->destsatoshis != 0 )
{
jadd64bits(retjson,"destsatoshis",qp->destsatoshis);
if ( qp->satoshis != 0 )
{
8 years ago
price = (double)qp->destsatoshis / qp->satoshis;
8 years ago
jaddnum(retjson,"price",price);
}
}
8 years ago
return(retjson);
}
int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson)
{
safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin));
safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr));
safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin));
safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr));
qp->timestamp = juint(argjson,"timestamp");
qp->quotetime = juint(argjson,"quotetime");
qp->txid = jbits256(argjson,"txid");
qp->txid2 = jbits256(argjson,"txid2");
qp->vout = jint(argjson,"vout");
qp->vout2 = jint(argjson,"vout2");
qp->feevout = jint(argjson,"feevout");
qp->srchash = jbits256(argjson,"srchash");
qp->desttxid = jbits256(argjson,"desttxid");
qp->feetxid = jbits256(argjson,"feetxid");
qp->destvout = jint(argjson,"destvout");
qp->desthash = jbits256(argjson,"desthash");
8 years ago
qp->satoshis = j64bits(argjson,"satoshis");
qp->destsatoshis = j64bits(argjson,"destsatoshis");
8 years ago
qp->txfee = j64bits(argjson,"txfee");
qp->desttxfee = j64bits(argjson,"desttxfee");
return(0);
}
8 years ago
int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price,uint64_t satoshis,uint64_t destsatoshis)
8 years ago
{
memset(qp,0,sizeof(*qp));
8 years ago
if ( qp->timestamp == 0 )
qp->timestamp = (uint32_t)time(NULL);
8 years ago
safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin));
8 years ago
LP_txfees(&qp->txfee,&qp->desttxfee,utxo->coin,qp->destcoin);
8 years ago
qp->satoshis = satoshis;//(destsatoshis / price) + 0.49;
qp->destsatoshis = destsatoshis;
8 years ago
if ( utxo->iambob == 0 || qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) )
8 years ago
{
8 years ago
printf("quoteinit error.(%d %d %d %d) %.8f vs %.8f\n",utxo->iambob == 0,qp->txfee >= qp->satoshis,qp->txfee >= utxo->deposit.value,utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis),dstr(utxo->deposit.value),dstr(LP_DEPOSITSATOSHIS(qp->satoshis)));
8 years ago
return(-1);
8 years ago
}
8 years ago
qp->txid = utxo->payment.txid;
qp->vout = utxo->payment.vout;
qp->txid2 = utxo->deposit.txid;
qp->vout2 = utxo->deposit.vout;
8 years ago
if ( qp->desttxfee >= qp->destsatoshis )
8 years ago
{
printf("quoteinit desttxfee %.8f < %.8f destsatoshis\n",dstr(qp->desttxfee),dstr(qp->destsatoshis));
8 years ago
return(-2);
8 years ago
}
8 years ago
safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin));
safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr));
8 years ago
qp->srchash = utxo->pubkey;
8 years ago
return(0);
}
8 years ago
int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr)
8 years ago
{
qp->desttxid = desttxid;
qp->destvout = destvout;
qp->desthash = desthash;
8 years ago
qp->feetxid = feetxid;
qp->feevout = feevout;
8 years ago
safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr));
return(0);
}
char *LP_quotereceived(cJSON *argjson)
{
struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q;
LP_quoteparse(&Q,argjson);
8 years ago
price = (double)Q.destsatoshis / Q.satoshis;
8 years ago
if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 )
{
ptr->Q = Q;
8 years ago
printf(">>>>>>>>>> received quote %s/%s %.8f\n",Q.srccoin,Q.destcoin,price);
8 years ago
return(clonestr("{\"result\":\"updated\"}"));
} else return(clonestr("{\"error\":\"nullptr\"}"));
}
8 years ago
char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *rel,double price)
8 years ago
{
8 years ago
bits256 zero; char *msg; cJSON *reqjson = cJSON_CreateObject();
8 years ago
memset(zero.bytes,0,sizeof(zero));
jaddbits256(reqjson,"pubkey",LP_mypub25519);
8 years ago
jaddstr(reqjson,"base",base);
jaddstr(reqjson,"rel",rel);
jaddnum(reqjson,"price",price);
8 years ago
jaddstr(reqjson,"method","postprice");
msg = jprint(reqjson,1);
LP_broadcast_message(pubsock,base,rel,zero,msg);
8 years ago
return(clonestr("{\"result\":\"success\"}"));
}
char *LP_postedprice(cJSON *argjson)
{
8 years ago
bits256 pubkey; double price; char *base,*rel;
8 years ago
//printf("PRICE POSTED.(%s)\n",jprint(argjson,0));
8 years ago
if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL )
{
pubkey = jbits256(argjson,"pubkey");
if ( bits256_nonz(pubkey) != 0 )
{
LP_pricefeedupdate(pubkey,base,rel,price);
return(clonestr("{\"result\":\"success\"}"));
}
}
return(clonestr("{\"error\":\"missing fields in posted price\"}"));
}
8 years ago
int32_t LP_quote_checkmempool(struct LP_quoteinfo *qp)
8 years ago
{
8 years ago
int32_t selector,spendvini; bits256 spendtxid;
7 years ago
if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,qp->srccoin,qp->coinaddr,qp->txid,qp->vout,qp->txid2,qp->vout2)) >= 0 )
8 years ago
{
char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini);
return(-1);
}
7 years ago
if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,qp->destcoin,qp->destaddr,qp->desttxid,qp->destvout,qp->feetxid,qp->feevout)) >= 0 )
8 years ago
{
char str[65]; printf("LP_tradecommand dest selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini);
return(-1);
}
return(0);
}
7 years ago
double LP_quote_validate(struct LP_utxoinfo *autxo,struct LP_utxoinfo *butxo,struct LP_quoteinfo *qp,int32_t iambob)
8 years ago
{
8 years ago
double qprice; uint64_t txfee,desttxfee,srcvalue,srcvalue2,destvalue,destvalue2;
8 years ago
if ( LP_iseligible(&srcvalue,&srcvalue2,1,qp->srccoin,qp->txid,qp->vout,qp->satoshis,qp->txid2,qp->vout2) == 0 )
8 years ago
{
printf("bob not eligible\n");
return(-2);
}
8 years ago
if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 )
8 years ago
{
8 years ago
char str[65]; printf("alice not eligible (%.8f %.8f) %s/v%d\n",dstr(destvalue),dstr(destvalue2),bits256_str(str,qp->feetxid),qp->feevout);
8 years ago
return(-3);
}
if ( LP_quote_checkmempool(qp) < 0 )
return(-4);
7 years ago
//if ( iambob != 0 && (*butxop= LP_utxofind(1,qp->txid,qp->vout)) == 0 )
// return(-5);
if ( bits256_cmp(butxo->deposit.txid,qp->txid2) != 0 || butxo->deposit.vout != qp->vout2 )
8 years ago
return(-6);
7 years ago
if ( strcmp(butxo->coinaddr,qp->coinaddr) != 0 )
8 years ago
return(-7);
if ( iambob == 0 )
{
7 years ago
//if ( (*autxop= LP_utxofind(0,qp->desttxid,qp->destvout)) == 0 )
// return(-8);
if ( bits256_cmp(autxo->fee.txid,qp->feetxid) != 0 || autxo->fee.vout != qp->feevout )
8 years ago
return(-9);
7 years ago
if ( strcmp(autxo->coinaddr,qp->destaddr) != 0 )
8 years ago
return(-10);
}
8 years ago
if ( destvalue < qp->desttxfee+qp->destsatoshis || srcvalue < qp->txfee+qp->satoshis )
8 years ago
{
8 years ago
printf("destvalue %.8f srcvalue %.8f, destsatoshis %.8f or satoshis %.8f is too small txfees %.8f %.8f?\n",dstr(destvalue),dstr(srcvalue),dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->desttxfee),dstr(qp->txfee));
8 years ago
return(-11);
}
8 years ago
qprice = ((double)qp->destsatoshis / qp->satoshis);
8 years ago
if ( qp->satoshis < (srcvalue / LP_MINVOL) || srcvalue < qp->txfee*LP_MINSIZE_TXFEEMULT )
8 years ago
{
8 years ago
printf("utxo payment %.8f is less than %f covered by Q %.8f or <10x txfee %.8f\n",dstr(srcvalue),1./LP_MINVOL,dstr(qp->satoshis),dstr(qp->txfee));
8 years ago
return(-12);
}
8 years ago
if ( qp->destsatoshis < (destvalue / LP_MINCLIENTVOL) || destvalue < qp->desttxfee*LP_MINSIZE_TXFEEMULT )
8 years ago
{
8 years ago
printf("destsatoshis %.8f is less than %f of value %.8f or < 10x txfee %.8f\n",dstr(qp->destsatoshis),1./LP_MINCLIENTVOL,dstr(destvalue),dstr(qp->desttxfee));
8 years ago
return(-13);
}
8 years ago
LP_txfees(&txfee,&desttxfee,qp->srccoin,qp->destcoin);
printf("qprice %.8f <- %.8f/%.8f txfees.(%.8f %.8f) vs (%.8f %.8f)\n",qprice,dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->txfee),dstr(qp->desttxfee),dstr(txfee),dstr(desttxfee));
8 years ago
if ( qp->txfee < LP_REQUIRED_TXFEE*txfee || qp->desttxfee < LP_REQUIRED_TXFEE*desttxfee )
8 years ago
return(-14);
8 years ago
return(qprice);
8 years ago
}
8 years ago
int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout)
{
int32_t i,n = cJSON_GetArraySize(array); cJSON *item;
for (i=0; i<n; i++)
{
item = jitem(array,i);
if ( vout == jint(item,"vout") && bits256_cmp(txid,jbits256(item,"txid")) == 0 )
return(i);
}
return(-1);
}
8 years ago
double LP_query(void *ctx,char *myipaddr,int32_t mypubsock,char *method,struct LP_quoteinfo *qp)
8 years ago
{
8 years ago
cJSON *reqjson; char *msg; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo;
8 years ago
if ( strcmp(method,"request") == 0 )
{
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;
8 years ago
jaddbits256(reqjson,"pubkey",qp->srchash);
8 years ago
jaddstr(reqjson,"method",method);
msg = jprint(reqjson,1);
8 years ago
printf("QUERY.(%s)\n",msg);
8 years ago
LP_broadcast_message(LP_mypubsock,qp->srccoin,qp->destcoin,qp->srchash,msg);
8 years ago
for (i=0; i<30; i++)
8 years ago
{
8 years ago
if ( (price= LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout)) > SMALLVAL )
8 years ago
{
8 years ago
if ( flag == 0 || bits256_nonz(qp->desthash) != 0 )
8 years ago
{
8 years ago
printf("break out of loop.%d price %.8f %s/%s\n",i,price,qp->srccoin,qp->destcoin);
8 years ago
break;
8 years ago
}
}
8 years ago
usleep(100000);
}
return(price);
}
8 years ago
int32_t LP_nanobind(void *ctx,char *pairstr)
8 years ago
{
8 years ago
int32_t i,r,pairsock = -1; uint16_t mypullport; char bindaddr[128];
8 years ago
if ( LP_canbind != 0 )
8 years ago
{
8 years ago
if ( (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 )
printf("error creating utxo->pair\n");
else
8 years ago
{
8 years ago
for (i=0; i<10; i++)
{
r = (10000 + (rand() % 50000)) & 0xffff;
8 years ago
if ( LP_fixed_pairport != 0 )
r = LP_fixed_pairport;
8 years ago
nanomsg_transportname(0,pairstr,LP_myipaddr,r);
nanomsg_transportname(1,bindaddr,LP_myipaddr,r);
8 years ago
if ( nn_bind(pairsock,bindaddr) >= 0 )
{
8 years ago
//timeout = 1;
//nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout));
//nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout));
8 years ago
printf("nanobind %s to %d\n",pairstr,pairsock);
return(pairsock);
} else printf("error binding to %s for %s\n",bindaddr,pairstr);
8 years ago
if ( LP_fixed_pairport != 0 )
break;
8 years ago
}
}
8 years ago
} else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,"127.0.0.1",0,1);
8 years ago
return(pairsock);
8 years ago
}
8 years ago
int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *base,char *rel,double price,struct LP_quoteinfo *qp)
8 years ago
{
8 years ago
char pairstr[512],*msg; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; struct iguana_info *coin;
8 years ago
printf("LP_connectstartbob.(%s) with.(%s) %s\n",LP_myipaddr,jprint(argjson,0),LP_myipaddr);
8 years ago
qp->quotetime = (uint32_t)time(NULL);
8 years ago
if ( (coin= LP_coinfind(utxo->coin)) == 0 )
{
printf("cant find coin.%s\n",utxo->coin);
return(-1);
}
privkey = LP_privkey(utxo->coinaddr,coin->taddr);
8 years ago
if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypub25519,qp->srchash) == 0 )
8 years ago
{
8 years ago
if ( (pair= LP_nanobind(ctx,pairstr)) >= 0 )
8 years ago
{
8 years ago
LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis-qp->txfee,rel,qp->destsatoshis-qp->desttxfee,qp->timestamp,qp->quotetime,DEXselector);
8 years ago
swap = LP_swapinit(1,0,privkey,&qp->R,qp);
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 )
8 years ago
{
8 years ago
retjson = LP_quotejson(qp);
jaddstr(retjson,"method","connected");
jaddstr(retjson,"pair",pairstr);
jaddnum(retjson,"requestid",qp->R.requestid);
jaddnum(retjson,"quoteid",qp->R.quoteid);
8 years ago
char str[65]; printf("BOB pubsock.%d binds to %d (%s)\n",pubsock,pair,bits256_str(str,utxo->S.otherpubkey));
8 years ago
msg = jprint(retjson,1);
LP_broadcast_message(pubsock,base,rel,utxo->S.otherpubkey,msg);
8 years ago
retval = 0;
} else printf("error launching swaploop\n");
} else printf("couldnt bind to any port %s\n",pairstr);
}
else
{
8 years ago
printf("dest %.8f vs required %.8f (%d %d %d %d %d)\n",dstr(qp->destsatoshis),dstr(price*(utxo->S.satoshis-qp->txfee)),bits256_nonz(privkey) != 0 ,qp->timestamp == utxo->T.swappending-LP_RESERVETIME,qp->quotetime >= qp->timestamp-3,qp->quotetime < utxo->T.swappending,bits256_cmp(LP_mypub25519,qp->srchash) == 0);
8 years ago
}
8 years ago
if ( retval < 0 )
{
if ( pair >= 0 )
nn_close(pair);
LP_availableset(utxo);
8 years ago
} else LP_unavailableset(utxo,utxo->S.otherpubkey);
8 years ago
return(retval);
8 years ago
}
8 years ago
char *LP_connectedalice(cJSON *argjson) // alice
8 years ago
{
8 years ago
cJSON *retjson; double bid,ask,price,qprice; int32_t pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; struct iguana_info *coin;
8 years ago
if ( LP_quoteparse(&Q,argjson) < 0 )
clonestr("{\"error\":\"cant parse quote\"}");
8 years ago
if ( bits256_cmp(Q.desthash,LP_mypub25519) != 0 )
8 years ago
return(clonestr("{\"result\",\"update stats\"}"));
8 years ago
printf("CONNECTED.(%s)\n",jprint(argjson,0));
7 years ago
//if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,0)) <= SMALLVAL )
8 years ago
{
LP_availableset(autxo);
8 years ago
LP_pendingswaps--;
8 years ago
printf("quote validate error %.0f\n",qprice);
return(clonestr("{\"error\":\"quote validation error\"}"));
}
8 years ago
if ( LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin) <= SMALLVAL || bid <= SMALLVAL )
8 years ago
{
8 years ago
printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.destcoin,Q.srccoin,bid,ask);
8 years ago
LP_availableset(autxo);
8 years ago
LP_pendingswaps--;
8 years ago
return(clonestr("{\"error\":\"no price set\"}"));
}
8 years ago
printf("%s/%s bid %.8f ask %.8f\n",Q.srccoin,Q.destcoin,bid,ask);
8 years ago
//if ( (price= ask) == 0. )
8 years ago
price = bid;
8 years ago
/*if ( SATOSHIDEN*qprice > (SATOSHIDEN * price) * 1.001 + 10 )
8 years ago
{
8 years ago
printf("qprice %.8f too big vs %.8f\n",qprice,price);
8 years ago
LP_availableset(autxo);
8 years ago
LP_pendingswaps--;
8 years ago
return(clonestr("{\"error\":\"quote price too expensive\"}"));
8 years ago
}*/
8 years ago
if ( (coin= LP_coinfind(Q.destcoin)) == 0 )
{
8 years ago
LP_pendingswaps--;
8 years ago
return(clonestr("{\"error\":\"cant get alicecoin\"}"));
}
Q.privkey = LP_privkey(Q.destaddr,coin->taddr);
8 years ago
if ( bits256_nonz(Q.privkey) != 0 && Q.quotetime >= Q.timestamp-3 )
8 years ago
{
8 years ago
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 )
8 years ago
{
8 years ago
//timeout = 1;
//nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout));
//nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout));
8 years ago
LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis-Q.txfee,Q.destcoin,Q.destsatoshis-Q.desttxfee,Q.timestamp,Q.quotetime,DEXselector);
8 years ago
swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q);
swap->N.pair = pairsock;
8 years ago
autxo->S.swap = swap;
swap->utxo = autxo;
8 years ago
printf("alice pairstr.(%s) pairsock.%d\n",pairstr,pairsock);
8 years ago
if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 )
8 years ago
{
8 years ago
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");
8 years ago
} else printf("connect error %s\n",nn_strerror(nn_errno()));
8 years ago
printf("connected result.(%s)\n",jprint(retjson,0));
8 years ago
if ( jobj(retjson,"error") != 0 )
LP_availableset(autxo);
8 years ago
else LP_pendingswaps++;
8 years ago
return(jprint(retjson,1));
8 years ago
}
else
{
8 years ago
LP_availableset(autxo);
8 years ago
printf("no privkey found\n");
8 years ago
return(clonestr("{\"error\",\"no privkey\"}"));
8 years ago
}
8 years ago
}
8 years ago
int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen)
8 years ago
{
8 years ago
char *method,*msg; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo *autxo,*butxo; int32_t retval = -1; struct LP_quoteinfo Q;
8 years ago
if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) )
8 years ago
{
8 years ago
printf("TRADECOMMAND.(%s)\n",jprint(argjson,0));
8 years ago
retval = 1;
8 years ago
if ( LP_quoteparse(&Q,argjson) == 0 && bits256_cmp(LP_mypub25519,Q.srchash) == 0 )
8 years ago
{
8 years ago
if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || ask <= SMALLVAL )
8 years ago
{
8 years ago
printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin);
return(-3);
8 years ago
}
8 years ago
price = ask;
7 years ago
//if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,1)) <= SMALLVAL )
8 years ago
{
8 years ago
printf("quote validate error %.0f\n",qprice);
return(-4);
8 years ago
}
8 years ago
if ( qprice < (price - 0.00000001) * 0.9999 )
8 years ago
{
8 years ago
printf("(%.8f %.8f) quote price %.8f too low vs %.8f for %s/%s\n",bid,ask,qprice,price,Q.srccoin,Q.destcoin);
8 years ago
return(-5);
8 years ago
}
8 years ago
if ( butxo->S.swap == 0 && time(NULL) > butxo->T.swappending )
butxo->T.swappending = 0;
8 years ago
if ( strcmp(method,"request") == 0 ) // bob needs apayment + fee tx's
8 years ago
{
8 years ago
if ( LP_isavailable(butxo) > 0 )
8 years ago
{
8 years ago
butxo->T.swappending = Q.timestamp + LP_RESERVETIME;
retjson = LP_quotejson(&Q);
butxo->S.otherpubkey = jbits256(argjson,"desthash");
LP_unavailableset(butxo,butxo->S.otherpubkey);
jaddnum(retjson,"quotetime",juint(argjson,"quotetime"));
jaddnum(retjson,"pending",butxo->T.swappending);
jaddbits256(retjson,"desthash",butxo->S.otherpubkey);
jaddbits256(retjson,"pubkey",butxo->S.otherpubkey);
jaddstr(retjson,"method","reserved");
8 years ago
msg = jprint(retjson,1);
8 years ago
printf("set swappending.%u accept qprice %.8f, min %.8f\n(%s)",butxo->T.swappending,qprice,price,msg);
8 years ago
LP_broadcast_message(pubsock,Q.srccoin,Q.destcoin,butxo->S.otherpubkey,msg);
8 years ago
butxo->T.lasttime = (uint32_t)time(NULL);
} else printf("warning swappending.%u swap.%p\n",butxo->T.swappending,butxo->S.swap);
8 years ago
}
else if ( strcmp(method,"connect") == 0 ) // bob
{
retval = 4;
8 years ago
if ( butxo->T.swappending != 0 && butxo->S.swap == 0 )
8 years ago
LP_connectstartbob(ctx,pubsock,butxo,argjson,Q.srccoin,Q.destcoin,qprice,&Q);
8 years ago
else printf("pend.%u swap %p when connect came in (%s)\n",butxo->T.swappending,butxo->S.swap,jprint(argjson,0));
8 years ago
}
}
}
return(retval);
}
7 years ago
char *LP_bestfit(char *rel,double relvolume)
{
struct LP_utxoinfo *autxo;
if ( relvolume <= 0. || LP_priceinfofind(rel) == 0 )
return(clonestr("{\"error\":\"invalid parameter\"}"));
if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * relvolume)) == 0 )
return(clonestr("{\"error\":\"cant find utxo that is big enough\"}"));
return(jprint(LP_utxojson(autxo),1));
}
#ifdef oldway
8 years ago
struct LP_utxoinfo *LP_bestutxo(double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct LP_utxoinfo *autxo,char *base,double maxprice,int32_t duration,uint64_t txfee,uint64_t desttxfee,uint64_t maxdestsatoshis)
8 years ago
{
8 years ago
int64_t satoshis,destsatoshis; uint64_t val,val2; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item; struct LP_utxoinfo *butxo,*bestutxo = 0; int32_t i,n,j,vout,numasks; double bestmetric=0.,metric,vol,price,qprice,bestprice = 0.; struct LP_pubkeyinfo *pubp;
8 years ago
*ordermatchpricep = 0.;
8 years ago
*bestsatoshisp = *bestdestsatoshisp = 0;
8 years ago
if ( duration <= 0 )
duration = LP_ORDERBOOK_DURATION;
8 years ago
if ( maxprice <= 0. || LP_priceinfofind(base) == 0 )
return(0);
8 years ago
LP_txfees(&txfee,&desttxfee,base,autxo->coin);
8 years ago
if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 )
8 years ago
{
if ( (orderbook= cJSON_Parse(obookstr)) != 0 )
{
if ( (asks= jarray(&numasks,orderbook,"asks")) != 0 )
{
for (i=0; i<numasks; i++)
8 years ago
{
8 years ago
item = jitem(asks,i);
8 years ago
price = jdouble(item,"price");
8 years ago
if ( LP_pricevalid(price) > 0 && price <= maxprice )
8 years ago
{
8 years ago
//price *= 1.0001;
//if ( price > maxprice )
// price = maxprice;
8 years ago
pubkey = jbits256(item,"pubkey");
8 years ago
if ( bits256_cmp(pubkey,LP_mypub25519) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 && pubp->numerrors < LP_MAXPUBKEY_ERRORS )
8 years ago
{
8 years ago
if ( bestprice == 0. ) // assumes price ordered asks
bestprice = price;
7 years ago
printf("item.[%d] %s\n",i,jprint(item,0));
8 years ago
txid = jbits256(item,"txid");
vout = jint(item,"vout");
vol = jdouble(item,"volume");
8 years ago
metric = price / bestprice;
7 years ago
printf("maxdest %.8f metric %f vol %f add pings numutxos.%d min %.8f max %.8f\n",dstr(maxdestsatoshis),metric,vol,jint(item,"numutxos"),jdouble(item,"minvolume"),jdouble(item,"maxvolume"));
7 years ago
// check utxos > 1 for pubkey, SPV validate recv'ed
7 years ago
/*if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && (long long)(vol*SATOSHIDEN) == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 && butxo->T.bestflag == 0 )
8 years ago
{
7 years ago
printf("got butxo? %p\n",butxo);
8 years ago
if ( LP_iseligible(&val,&val2,butxo->iambob,butxo->coin,butxo->payment.txid,butxo->payment.vout,butxo->S.satoshis,butxo->deposit.txid,butxo->deposit.vout) > 0 )
8 years ago
{
8 years ago
destsatoshis = ((butxo->S.satoshis - txfee) * price);
8 years ago
satoshis = (destsatoshis / price + 0.49) - txfee;
if ( satoshis <= 0 )
continue;
qprice = (double)destsatoshis / satoshis;
8 years ago
n = (int32_t)((double)destsatoshis / desttxfee);
if ( n < 10 )
n = 10;
else n = 3;
for (j=0; j<n; j++)
8 years ago
{
if ( (qprice= LP_qprice_calc(&destsatoshis,&satoshis,(price*(100.+j))/100.,butxo->S.satoshis,txfee,autxo->payment.value,maxdestsatoshis,desttxfee)) > price+SMALLVAL )
break;
}
8 years ago
//printf("j.%d/%d qprice %.8f vs price %.8f best.(%.8f %.8f)\n",j,n,qprice,price,dstr(satoshis),dstr(destsatoshis));
8 years ago
if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value / LP_MINCLIENTVOL) && satoshis-txfee > (butxo->S.satoshis / LP_MINVOL) && satoshis <= butxo->payment.value-txfee )
8 years ago
{
8 years ago
printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric);
metric = dstr(destsatoshis) * metric * metric * metric;
if ( bestmetric == 0. || metric < bestmetric )
{
bestutxo = butxo;
*ordermatchpricep = price;
*bestdestsatoshisp = destsatoshis;
8 years ago
*bestsatoshisp = satoshis;
8 years ago
bestmetric = metric;
printf("set best!\n");
}
8 years ago
} // else printf("skip.(%d %d %d %d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f sats %.8f\n",metric < 1.2,destsatoshis > desttxfee,destsatoshis-desttxfee > (autxo->payment.value / LP_MINCLIENTVOL),satoshis-txfee > (butxo->S.satoshis / LP_MINVOL),satoshis < butxo->payment.value-txfee,metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee),dstr(satoshis));
8 years ago
}
8 years ago
else
{
8 years ago
printf("ineligible.(%.8f %.8f)\n",price,dstr(butxo->S.satoshis));
7 years ago
//if ( butxo->T.spentflag == 0 )
// butxo->T.spentflag = (uint32_t)time(NULL);
8 years ago
}
8 years ago
}
else
{
if ( butxo != 0 )
8 years ago
printf("%llu %llu %d %d %d: ",(long long)(vol*SATOSHIDEN),(long long)butxo->S.satoshis,vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0);
8 years ago
printf("cant find butxo.%p or value mismatch %.8f != %.8f or bestflag.%d\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0,butxo->T.bestflag);
7 years ago
}*/
8 years ago
} else printf("self trading or blacklisted peer\n");
8 years ago
}
else
{
8 years ago
if ( i == 0 )
printf("maxprice %.8f vs %.8f\n",maxprice,price);
8 years ago
break;
}
8 years ago
}
7 years ago
if ( bestutxo == 0 )
{
int32_t numrestraints;
for (i=numrestraints=0; i<numasks; i++)
{
item = jitem(asks,i);
pubkey = jbits256(item,"pubkey");
if ( bits256_cmp(pubkey,LP_mypub25519) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 )
{
txid = jbits256(item,"txid");
vout = jint(item,"vout");
if ( (butxo= LP_utxofind(1,txid,vout)) != 0 )
{
numrestraints++;
butxo->T.bestflag = 0;
pubp->numerrors = 0;
}
}
}
printf("no bob utxo found -> cleared %d restraints\n",numrestraints);
}
8 years ago
}
8 years ago
free_json(orderbook);
8 years ago
}
8 years ago
free(obookstr);
8 years ago
}
7 years ago
printf("bestutxo.%p %.8f %.8f\n",bestutxo,*ordermatchpricep,dstr(*bestdestsatoshisp));
8 years ago
if ( bestutxo == 0 || *ordermatchpricep == 0. || *bestdestsatoshisp == 0 )
return(0);
7 years ago
bestutxo->T.bestflag = 1;
8 years ago
int32_t changed;
LP_mypriceset(&changed,autxo->coin,base,1. / *ordermatchpricep);
8 years ago
return(bestutxo);
}
8 years ago
char *LP_ordermatch(char *base,int64_t txfee,double maxprice,double maxvolume,char *rel,bits256 txid,int32_t vout,bits256 feetxid,int32_t feevout,int64_t desttxfee,int32_t duration)
8 years ago
{
8 years ago
struct LP_quoteinfo Q; int64_t bestsatoshis=0,bestdestsatoshis = 0; double ordermatchprice = 0.; struct LP_utxoinfo *autxo,*bestutxo;
7 years ago
txfee = LP_txfeecalc(LP_coinfind(base),txfee);
desttxfee = LP_txfeecalc(LP_coinfind(rel),desttxfee);
8 years ago
if ( (autxo= LP_utxopairfind(0,txid,vout,feetxid,feevout)) == 0 )
return(clonestr("{\"error\":\"cant find alice utxopair\"}"));
8 years ago
if ( (bestutxo= LP_bestutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,SATOSHIDEN*maxvolume)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 )
8 years ago
return(clonestr("{\"error\":\"cant find ordermatch utxo\"}"));
8 years ago
if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 )
8 years ago
return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
8 years ago
if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 )
8 years ago
return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
8 years ago
return(jprint(LP_quotejson(&Q),1));
}
7 years ago
char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double maxprice,double relvolume,int32_t timeout,int32_t duration)
{
uint64_t desttxfee,txfee; int64_t bestsatoshis=0,bestdestsatoshis=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q;
if ( duration <= 0 )
duration = LP_ORDERBOOK_DURATION;
if ( timeout <= 0 )
timeout = LP_AUTOTRADE_TIMEOUT;
if ( maxprice <= 0. || relvolume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 )
return(clonestr("{\"error\":\"invalid parameter\"}"));
if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * relvolume)) == 0 )
return(clonestr("{\"error\":\"cant find utxo that is big enough\"}"));
LP_txfees(&txfee,&desttxfee,base,rel);
if ( (bestutxo= LP_bestutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,SATOSHIDEN*relvolume)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 )
{
printf("bestutxo.%p ordermatchprice %.8f bestdestsatoshis %.8f\n",bestutxo,ordermatchprice,dstr(bestdestsatoshis));
return(clonestr("{\"error\":\"cant find ordermatch utxo\"}"));
}
if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 )
return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 )
return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,0)) <= SMALLVAL )
{
printf("quote validate error %.0f\n",qprice);
return(clonestr("{\"error\":\"quote validation error\"}"));
}
printf("do quote.(%s)\n",jprint(LP_quotejson(&Q),1));
return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration));
}
#endif
8 years ago
char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *qp,double maxprice,int32_t timeout,int32_t duration)
8 years ago
{
7 years ago
struct LP_utxoinfo *aliceutxo; cJSON *bestitem=0; int32_t DEXselector=0; uint32_t expiration; double price; struct LP_pubkeyinfo *pubp;
8 years ago
if ( (aliceutxo= LP_utxopairfind(0,qp->desttxid,qp->destvout,qp->feetxid,qp->feevout)) == 0 )
8 years ago
{
char str[65],str2[65]; printf("dest.(%s)/v%d fee.(%s)/v%d\n",bits256_str(str,qp->desttxid),qp->destvout,bits256_str(str2,qp->feetxid),qp->feevout);
8 years ago
return(clonestr("{\"error\":\"cant find alice utxopair\"}"));
8 years ago
}
7 years ago
/*if ( (bobutxo= LP_utxopairfind(1,qp->txid,qp->vout,qp->txid2,qp->vout2)) == 0 )
8 years ago
return(clonestr("{\"error\":\"cant find bob utxopair\"}"));
7 years ago
bobutxo->T.bestflag = (uint32_t)time(NULL);*/
8 years ago
//if ( (retstr= LP_registerall(0)) != 0 )
// free(retstr);
8 years ago
price = LP_query(ctx,myipaddr,mypubsock,"request",qp);
8 years ago
bestitem = LP_quotejson(qp);
8 years ago
if ( LP_pricevalid(price) > 0 )
8 years ago
{
8 years ago
if ( price <= maxprice )
8 years ago
{
8 years ago
price = LP_query(ctx,myipaddr,mypubsock,"connect",qp);
7 years ago
LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis-qp->txfee,qp->destcoin,qp->destsatoshis-qp->desttxfee,qp->timestamp,qp->quotetime,DEXselector);
8 years ago
expiration = (uint32_t)time(NULL) + timeout;
while ( time(NULL) < expiration )
{
8 years ago
if ( aliceutxo->S.swap != 0 )
8 years ago
break;
sleep(1);
}
8 years ago
if ( aliceutxo->S.swap == 0 )
8 years ago
{
7 years ago
if ( (pubp= LP_pubkeyadd(qp->srchash)) != 0 )
8 years ago
pubp->numerrors++;
8 years ago
jaddstr(bestitem,"status","couldnt establish connection");
8 years ago
} else jaddstr(bestitem,"status","connected");
8 years ago
jaddnum(bestitem,"quotedprice",price);
jaddnum(bestitem,"maxprice",maxprice);
8 years ago
jaddnum(bestitem,"requestid",qp->R.requestid);
jaddnum(bestitem,"quoteid",qp->R.quoteid);
printf("Alice r.%u qp->%u\n",qp->R.requestid,qp->R.quoteid);
8 years ago
}
8 years ago
else
8 years ago
{
8 years ago
jaddnum(bestitem,"quotedprice",price);
jaddnum(bestitem,"maxprice",maxprice);
jaddstr(bestitem,"status","too expensive");
8 years ago
}
8 years ago
}
else
{
jaddnum(bestitem,"maxprice",maxprice);
8 years ago
jaddstr(bestitem,"status","no response to request");
8 years ago
}
8 years ago
if ( aliceutxo->S.swap == 0 )
LP_availableset(aliceutxo);
8 years ago
return(jprint(bestitem,0));
8 years ago
}
7 years ago
int32_t LP_nearest_utxovalue(struct LP_address_utxo **utxos,int32_t n,uint64_t targetval)
8 years ago
{
7 years ago
int32_t i,mini = -1; int64_t dist; uint64_t mindist = (1LL << 60);
for (i=0; i<n; i++)
{
if ( utxos[i] != 0 )
{
dist = (utxos[i]->U.value - targetval);
//printf("(%.8f %.8f %.8f).%d ",dstr(values[i]),dstr(dist),dstr(mindist),mini);
if ( dist >= 0 && dist < mindist )
{
mini = i;
mindist = dist;
}
}
}
return(mini);
}
7 years ago
struct LP_utxoinfo *LP_address_utxopair(int32_t relflag,struct LP_utxoinfo *utxo,struct LP_address_utxo **utxos,int32_t max,struct iguana_info *coin,char *coinaddr,uint64_t txfee,double volume,double price)
7 years ago
{
struct LP_address *ap; uint64_t targetval; int32_t m,mini; struct LP_address_utxo *up,*up2;
if ( (ap= LP_addressfind(coin,coinaddr)) != 0 )
{
if ( (m= LP_address_utxo_ptrs(utxos,max,ap)) > 1 )
{
7 years ago
if ( relflag != 0 )
targetval = SATOSHIDEN * (volume / price) + 2*txfee;
7 years ago
else targetval = SATOSHIDEN * (volume * price) + 2*txfee;
7 years ago
{
int32_t i;
for (i=0; i<m; i++)
printf("%.8f ",dstr(utxos[i]->U.value));
printf("targetval %.8f vol %.8f price %.8f txfee %.8f\n",dstr(targetval),volume,price,dstr(txfee));
7 years ago
//{"coin":"BTC","address":"1L7Kzud7jC3LnLyZmtg85XxxvADLuLwfwr","price":0.00050196,"numutxos":22,"minvolume":0.00011714,"maxvolume":0.10820861,"pubkey":"1bfcfc1d48dbe3e1332b09cb48e50e7789bdde2308b74f905299db12d093fa2d","age":13} 0.00011714 [0.00501960] 0.10820861
//0.00100000 0.00100000 0.00200000 0.08947953 0.10820861 0.03616972 0.00126502 0.04057810 0.00091512 0.00011714 0.00164483 0.00149051 0.00158423 0.00129022 0.03982604 0.03721034 0.00163831 0.00137594 0.00156398 0.02667164 0.00099693 0.01062943 targetval 0.00070641 vol 0.00501960 price 0.00050196 txfee 0.00035195
//ordermatch 0.00050196 12.99990000 0.00000251
7 years ago
}
7 years ago
if ( (mini= LP_nearest_utxovalue(utxos,m,targetval)) >= 0 )
{
up = utxos[mini];
utxos[mini] = 0;
targetval = (targetval / 8) * 9 + 2*txfee;
if ( (mini= LP_nearest_utxovalue(utxos,m,targetval)) >= 0 )
{
if ( up != 0 && (up2= utxos[mini]) != 0 )
{
safecopy(utxo->coin,coin->symbol,sizeof(utxo->coin));
safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr));
utxo->payment.txid = up->U.txid;
utxo->payment.vout = up->U.vout;
utxo->payment.value = up->U.value;
utxo->iambob = 1;
utxo->deposit.txid = up2->U.txid;
utxo->deposit.vout = up2->U.vout;
utxo->deposit.value = up2->U.value;
7 years ago
if ( relflag != 0 )
utxo->S.satoshis = SATOSHIDEN * (volume / price);
else utxo->S.satoshis = SATOSHIDEN * (volume * price);
7 years ago
return(utxo);
}
}
}
}
}
return(0);
}
struct LP_utxoinfo *LP_buyutxo(struct LP_utxoinfo *bestutxo,double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct LP_utxoinfo *autxo,char *base,double maxprice,int32_t duration,uint64_t txfee,uint64_t desttxfee,double relvolume,char *gui)
{
bits256 pubkey; char *obookstr,coinaddr[64]; cJSON *orderbook,*asks,*item; int32_t i,n,numasks,max = 1000; struct LP_address_utxo **utxos; double minvol,maxvol,price; struct LP_pubkeyinfo *pubp; struct iguana_info *basecoin;
*ordermatchpricep = 0.;
*bestsatoshisp = *bestdestsatoshisp = 0;
basecoin = LP_coinfind(base);
if ( duration <= 0 )
duration = LP_ORDERBOOK_DURATION;
if ( maxprice <= 0. || LP_priceinfofind(base) == 0 || basecoin == 0 )
return(0);
utxos = calloc(max,sizeof(*utxos));
LP_txfees(&txfee,&desttxfee,base,autxo->coin);
if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 )
{
if ( (orderbook= cJSON_Parse(obookstr)) != 0 )
{
if ( (asks= jarray(&numasks,orderbook,"asks")) != 0 )
{
for (i=0; i<numasks; i++)
{
item = jitem(asks,i);
price = jdouble(item,"price");
if ( LP_pricevalid(price) > 0 && price <= maxprice )
{
pubkey = jbits256(item,"pubkey");
if ( bits256_cmp(pubkey,LP_mypub25519) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 )
{
if ( (n= jint(item,"numutxos")) > 1 )
{
minvol = jdouble(item,"minvolume");
maxvol = jdouble(item,"maxvolume");
if ( relvolume >= minvol && relvolume <= maxvol )
{
bitcoin_address(coinaddr,basecoin->taddr,basecoin->pubtype,pubp->rmd160,sizeof(pubp->rmd160));
7 years ago
if ( (bestutxo= LP_address_utxopair(1,bestutxo,utxos,max,basecoin,coinaddr,txfee,relvolume,price)) != 0 )
7 years ago
{
bestutxo->pubkey = pubp->pubkey;
safecopy(bestutxo->gui,gui,sizeof(bestutxo->gui));
7 years ago
autxo->S.satoshis = bestutxo->S.satoshis * price;
7 years ago
*bestsatoshisp = bestutxo->S.satoshis;
*ordermatchpricep = price;
*bestdestsatoshisp = autxo->S.satoshis;
printf("ordermatch %.8f %.8f %.8f\n",price,dstr(*bestsatoshisp),dstr(*bestdestsatoshisp));
break;
}
}
}
} else printf("self trading or blacklisted peer\n");
}
else
{
if ( i == 0 )
printf("too expensive maxprice %.8f vs %.8f\n",maxprice,price);
break;
}
}
}
free_json(orderbook);
}
free(obookstr);
}
free(utxos);
if ( *ordermatchpricep == 0. || *bestdestsatoshisp == 0 )
return(0);
int32_t changed;
LP_mypriceset(&changed,autxo->coin,base,1. / *ordermatchpricep);
return(bestutxo);
}
7 years ago
struct LP_utxoinfo *LP_sellutxo(struct LP_utxoinfo *bestutxo,double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct LP_utxoinfo *autxo,char *rel,double minprice,int32_t duration,uint64_t txfee,uint64_t desttxfee,double basevolume,char *gui)
7 years ago
{
7 years ago
bits256 pubkey; char *obookstr,coinaddr[64]; cJSON *orderbook,*bids,*item; int32_t i,n,numasks,max = 1000; struct LP_address_utxo **utxos; double minvol,maxvol,price; struct LP_pubkeyinfo *pubp; struct iguana_info *relcoin;
7 years ago
*ordermatchpricep = 0.;
*bestsatoshisp = *bestdestsatoshisp = 0;
relcoin = LP_coinfind(rel);
if ( duration <= 0 )
duration = LP_ORDERBOOK_DURATION;
7 years ago
if ( minprice <= 0. || LP_priceinfofind(rel) == 0 || relcoin == 0 )
7 years ago
return(0);
utxos = calloc(max,sizeof(*utxos));
LP_txfees(&txfee,&desttxfee,autxo->coin,rel);
if ( (obookstr= LP_orderbook(autxo->coin,rel,duration)) != 0 )
{
if ( (orderbook= cJSON_Parse(obookstr)) != 0 )
{
7 years ago
if ( (bids= jarray(&numasks,orderbook,"bids")) != 0 )
7 years ago
{
for (i=0; i<numasks; i++)
{
7 years ago
item = jitem(bids,i);
7 years ago
price = jdouble(item,"price");
7 years ago
if ( LP_pricevalid(price) > 0 && price >= minprice )
7 years ago
{
pubkey = jbits256(item,"pubkey");
if ( bits256_cmp(pubkey,LP_mypub25519) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 )
{
if ( (n= jint(item,"numutxos")) > 1 )
{
minvol = jdouble(item,"minvolume");
maxvol = jdouble(item,"maxvolume");
7 years ago
if ( basevolume >= minvol/price && basevolume <= maxvol/price )
7 years ago
{
7 years ago
printf("%s %.8f [%.8f] %.8f\n",jprint(item,0),minvol,basevolume*price,maxvol);
7 years ago
bitcoin_address(coinaddr,relcoin->taddr,relcoin->pubtype,pubp->rmd160,sizeof(pubp->rmd160));
7 years ago
if ( (bestutxo= LP_address_utxopair(0,bestutxo,utxos,max,relcoin,coinaddr,desttxfee,basevolume,price)) != 0 )
7 years ago
{
bestutxo->pubkey = pubp->pubkey;
safecopy(bestutxo->gui,gui,sizeof(bestutxo->gui));
7 years ago
// ordermatch 0.00050029 12.99990000 0.00000250
// 0.00156398 0.01062943 0.00164483 0.00163831 0.00200000 0.00091512 0.03616972 0.00149051 0.00011714 0.03721034 0.02667164 0.00126502 0.03982604 0.00158423 0.00129022 0.04057810 0.00137594 0.00100000 0.00055601 0.00067499 0.00022800 0.12000000 0.03679745 0.00191550 0.00068144 0.00060983 0.00155659 0.03500084 0.00186860 0.00065110 0.00062265 0.00017046 0.00001468 0.00051851 0.00571714 0.00205292 0.00309702 0.03363277 targetval 0.00070640 vol 0.00500290 price 0.00050029 txfee 0.00035195
7 years ago
*bestsatoshisp = autxo->S.satoshis;
7 years ago
*ordermatchpricep = price;
7 years ago
*bestdestsatoshisp = bestutxo->S.satoshis;
7 years ago
printf("ordermatch %.8f %.8f %.8f\n",price,dstr(*bestsatoshisp),dstr(*bestdestsatoshisp));
break;
}
}
}
} else printf("self trading or blacklisted peer\n");
}
else
{
if ( i == 0 )
7 years ago
printf("too little minprice %.8f vs %.8f\n",minprice,price);
7 years ago
break;
}
}
}
free_json(orderbook);
}
free(obookstr);
}
free(utxos);
if ( *ordermatchpricep == 0. || *bestdestsatoshisp == 0 )
return(0);
int32_t changed;
LP_mypriceset(&changed,autxo->coin,rel,*ordermatchpricep);
return(bestutxo);
}
7 years ago
char *LP_autobuy(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double maxprice,double relvolume,int32_t timeout,int32_t duration,char *gui)
{
7 years ago
uint64_t desttxfee,txfee; int64_t bestsatoshis=0,bestdestsatoshis=0; struct LP_utxoinfo *autxo,_best,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q;
7 years ago
printf("LP_autobuy\n");
8 years ago
if ( duration <= 0 )
duration = LP_ORDERBOOK_DURATION;
if ( timeout <= 0 )
timeout = LP_AUTOTRADE_TIMEOUT;
if ( maxprice <= 0. || relvolume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 )
return(clonestr("{\"error\":\"invalid parameter\"}"));
if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * relvolume)) == 0 )
return(clonestr("{\"error\":\"cant find utxo that is big enough\"}"));
8 years ago
LP_txfees(&txfee,&desttxfee,base,rel);
7 years ago
memset(&_best,0,sizeof(_best));
if ( (bestutxo= LP_buyutxo(&_best,&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,relvolume,gui)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 )
{
printf("bestutxo.%p ordermatchprice %.8f bestdestsatoshis %.8f\n",bestutxo,ordermatchprice,dstr(bestdestsatoshis));
return(clonestr("{\"error\":\"cant find ordermatch utxo\"}"));
}
if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 )
return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 )
return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
7 years ago
if ( (qprice= LP_quote_validate(autxo,bestutxo,&Q,0)) <= SMALLVAL )
7 years ago
{
printf("quote validate error %.0f\n",qprice);
return(clonestr("{\"error\":\"quote validation error\"}"));
}
printf("do quote.(%s)\n",jprint(LP_quotejson(&Q),1));
7 years ago
return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration));
7 years ago
}
7 years ago
char *LP_autosell(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double minprice,double basevolume,int32_t timeout,int32_t duration,char *gui)
7 years ago
{
7 years ago
uint64_t desttxfee,txfee; int64_t bestsatoshis=0,bestdestsatoshis=0; struct LP_utxoinfo *butxo,_best,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q;
7 years ago
if ( duration <= 0 )
duration = LP_ORDERBOOK_DURATION;
if ( timeout <= 0 )
timeout = LP_AUTOTRADE_TIMEOUT;
7 years ago
if ( minprice <= 0. || basevolume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 )
7 years ago
return(clonestr("{\"error\":\"invalid parameter\"}"));
7 years ago
if ( (butxo= LP_utxo_bestfit(base,SATOSHIDEN * basevolume)) == 0 )
7 years ago
return(clonestr("{\"error\":\"cant find utxo that is big enough\"}"));
LP_txfees(&txfee,&desttxfee,base,rel);
7 years ago
if ( (bestutxo= LP_sellutxo(&_best,&ordermatchprice,&bestsatoshis,&bestdestsatoshis,butxo,rel,minprice,duration,txfee,desttxfee,basevolume,gui)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 )
8 years ago
{
printf("bestutxo.%p ordermatchprice %.8f bestdestsatoshis %.8f\n",bestutxo,ordermatchprice,dstr(bestdestsatoshis));
8 years ago
return(clonestr("{\"error\":\"cant find ordermatch utxo\"}"));
8 years ago
}
7 years ago
if ( LP_quoteinfoinit(&Q,bestutxo,base,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 )
8 years ago
return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
7 years ago
if ( LP_quotedestinfo(&Q,bestutxo->payment.txid,bestutxo->payment.vout,bestutxo->deposit.txid,bestutxo->deposit.vout,LP_mypub25519,bestutxo->coinaddr) < 0 )
8 years ago
return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
7 years ago
if ( (qprice= LP_quote_validate(bestutxo,butxo,&Q,0)) <= SMALLVAL )
8 years ago
{
printf("quote validate error %.0f\n",qprice);
return(clonestr("{\"error\":\"quote validation error\"}"));
}
8 years ago
printf("do quote.(%s)\n",jprint(LP_quotejson(&Q),1));
7 years ago
return(clonestr("{\"result\":\"success\"}"));
//return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration));
8 years ago
}
8 years ago