Browse Source

Test

etomic
jl777 8 years ago
parent
commit
76a2dae871
  1. 232
      iguana/exchanges/LP_commands.c
  2. 2
      iguana/exchanges/LP_include.h
  3. 2
      iguana/exchanges/LP_prices.c
  4. 400
      iguana/exchanges/LP_quotes.c
  5. 117
      iguana/exchanges/LP_statemachine.c
  6. 17
      iguana/exchanges/LP_utxos.c

232
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 )
{

2
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);

2
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);

400
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<n; i++)
{
item = jitem(array,i);
LP_quoteparse(&Q,item);
safecopy(coinstr,jstr(item,"base"),sizeof(coinstr));
if ( strcmp(coinstr,base) == 0 )
{
if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 )
{
if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 )
{
jaddi(retarray,jduplicate(item));
added++;
totaladded++;
}
} else printf("ineligible.(%s)\n",jprint(item,0));
}
}
}
free_json(array);
//printf("break out of loop.%d price %.8f\n",i,price);
break;
}
free(utxostr);
}
if ( n == totaladded && added == 0 )
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 ( 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; i<n; i++)
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 )
{
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; i<n && i<sizeof(prices)/sizeof(*prices); i++)
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 )
{
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<n && i<sizeof(prices)/sizeof(*prices); i++)
retval = 1;
if ( LP_isavailable(utxo) > 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<numasks; i++)
{
i = besti;
bestprice = prices[i];
item = jitem(array,i);
bestitem = LP_quotejson(&Q[i]);
printf("bestprice %f vs maxprice %f (%s)\n",bestprice,maxprice,jprint(bestitem,0));
if ( maxprice == 0. || bestprice <= maxprice )
item = jitem(asks,i);
if ( (price= jdouble(item,"price")) > 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));
}

117
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; i<n && i<sizeof(prices)/sizeof(*prices); i++)
{
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));
}
if ( bestprice > SMALLVAL )
{
bestmetric = 0.;
besti = -1;
for (i=0; i<n && i<sizeof(prices)/sizeof(*prices); i++)
{
if ( (price= prices[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<n; i++)
{
item = jitem(array,i);
LP_quoteparse(&Q,item);
safecopy(coinstr,jstr(item,"base"),sizeof(coinstr));
if ( strcmp(coinstr,base) == 0 )
{
if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 )
{
if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 )
{
jaddi(retarray,jduplicate(item));
added++;
totaladded++;
}
} else printf("ineligible.(%s)\n",jprint(item,0));
}
}
}
free_json(array);
}
free(utxostr);
}
if ( n == totaladded && added == 0 )
{
printf("n.%d totaladded.%d vs added.%d\n",n,totaladded,added);
break;
}
}
return(retarray);
}
void LP_quotesinit(char *base,char *rel)
{
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 )
{
//printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array));
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
memset(&Q,0,sizeof(Q));
for (i=0; i<n; i++)
{
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);
}
}
free_json(array);
}
}*/

17
iguana/exchanges/LP_utxos.c

@ -274,6 +274,23 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la
return(jprint(utxosjson,1));
}
struct LP_utxoinfo *LP_utxo_bestfit(char *symbol,uint64_t destsatoshis)
{
struct LP_utxoinfo *utxo,*tmp,*bestutxo = 0;
if ( symbol == 0 || destsatoshis == 0 )
return(0);
HASH_ITER(hh,LP_utxoinfos[0],utxo,tmp)
{
//char str[65]; printf("check %s.%s\n",utxo->coin,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;

Loading…
Cancel
Save