/****************************************************************************** * Copyright © 2014-2016 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. * * * ******************************************************************************/ #define _issue_curl(curl_handle,label,url) bitcoind_RPC(curl_handle,label,url,0,0,0) #define INSTANTDEX_MINVOL 75 #define INSTANTDEX_MINVOLPERC ((double)INSTANTDEX_MINVOL / 100.) #define INSTANTDEX_PRICESLIPPAGE 0.001 #define FINISH_HEIGHT 7 #define INSTANTDEX_TRIGGERDEADLINE 120 #define JUMPTRADE_SECONDS 100 #define INSTANTDEX_ACCT "4383817337783094122" #define INSTANTDEX_FEE ((long)(2.5 * SATOSHIDEN)) #include "../iguana777.h" #include "InstantDEX_quote.h" #define INSTANTDEX_LOCALAPI "allorderbooks", "orderbook", "lottostats", "LSUM", "makebasket", "disable", "enable", "peggyrates", "tradesequence", "placebid", "placeask", "orderstatus", "openorders", "cancelorder", "tradehistory", "balance", "allexchanges", typedef char *(*json_handler)(int32_t localaccess,int32_t valid,char *sender,cJSON **objs,int32_t numobjs,char *origargstr); queue_t InstantDEXQ,TelepathyQ,Pending_offersQ; cJSON *InstantDEX_lottostats(); //#include "NXT_tx.h" #include "trades.h" #include "quotes.h" #include "subatomic.h" #include "orderbooks.h" #include "exchangeparse.h" #include "exchange_trades.h" #include "exchanges/poloniex.c" #include "exchanges/bittrex.c" #include "exchanges/btce.c" #include "exchanges/bitfinex.c" #include "exchanges/btc38.c" #include "exchanges/huobi.c" #include "exchanges/lakebtc.c" #include "exchanges/quadriga.c" #include "exchanges/okcoin.c" #include "exchanges/coinbase.c" #include "exchanges/bitstamp.c" // {"plugin":"InstantDEX","method":"orderbook","baseid":"8688289798928624137","rel":"USD","exchange":"active","allfields":1} // {"plugin":"InstantDEX","method":"orderbook","baseid":"17554243582654188572","rel":"12071612744977229797","exchange":"active","allfields":1} // {"plugin":"InstantDEX","method":"orderbook","baseid":"6918149200730574743","rel":"XMR","exchange":"active","allfields":1} void idle() { char *jsonstr,*str; cJSON *json; int32_t n = 0; uint32_t nonce; /*printf("INSTANTDEX.readyflag.%d\n",INSTANTDEX.readyflag); while ( INSTANTDEX.readyflag == 0 ) sleep(1); printf("INSTANTDEX.readyflag.%d\n",INSTANTDEX.readyflag);*/ while ( 1 ) { if ( n == 0 ) sleep(1); n = 0; if ( (jsonstr= queue_dequeue(&InstantDEXQ,1)) != 0 ) { printf("Dequeued InstantDEX.(%s)\n",jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { //fprintf(stderr,"dequeued\n"); if ( (str= busdata_sync(&nonce,jsonstr,"allnodes",0)) != 0 ) { //fprintf(stderr,"busdata.(%s)\n",str); free(str); } free_json(json); n++; } else printf("error parsing (%s) from InstantDEXQ\n",jsonstr); free_queueitem(jsonstr); } } } uint32_t _get_NXTheight(uint32_t *firsttimep) { static uint32_t last,lastheight,lastNXTtime; cJSON *json; uint32_t height = 0; char cmd[256],*jsonstr; if ( time(NULL) > last+10 ) { sprintf(cmd,"requestType=getState"); if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) { //printf("(%s) -> (%s)\n",cmd,jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { if ( firsttimep != 0 ) lastNXTtime = *firsttimep = (uint32_t)get_cJSON_int(json,"time"); height = (int32_t)get_cJSON_int(json,"numberOfBlocks"); if ( height > 0 ) height--; lastheight = height; free_json(json); } free(jsonstr); } last = (uint32_t)time(NULL); } else { height = lastheight; if ( firsttimep != 0 ) *firsttimep = lastNXTtime; } return(height); } void idle2() { static double lastmilli; uint32_t NXTblock; //while ( INSTANTDEX.readyflag == 0 ) // sleep(1); while ( 1 ) { if ( milliseconds() < (lastmilli + 5000) ) sleep(1); NXTblock = _get_NXTheight(0); if ( 1 && NXTblock != prices777_NXTBLOCK ) { prices777_NXTBLOCK = NXTblock; InstantDEX_update(IGUANA_NXTADDR,IGUANA_NXTACCTSECRET);//,SUPERNET.); //fprintf(stderr,"done idle NXT\n"); } lastmilli = milliseconds(); } } cJSON *InstantDEX_lottostats() { char cmdstr[1024],NXTaddr[64],buf[1024],*jsonstr; struct destbuf receiverstr; cJSON *json,*array,*txobj; int32_t i,n,totaltickets = 0; uint64_t amount,senderbits; uint32_t timestamp = 0; if ( timestamp == 0 ) timestamp = 38785003; sprintf(cmdstr,"requestType=getBlockchainTransactions&account=%s×tamp=%u&type=0&subtype=0",INSTANTDEX_ACCT,timestamp); //printf("cmd.(%s)\n",cmdstr); if ( (jsonstr= issue_NXTPOST(cmdstr)) != 0 ) { // printf("jsonstr.(%s)\n",jsonstr); // mm string.({"requestProcessingTime":33,"transactions":[{"fullHash":"2a2aab3b84dadf092cf4cedcd58a8b5a436968e836338e361c45651bce0ef97e","confirmations":203,"signatureHash":"52a4a43d9055fe4861b3d13fbd03a42fecb8c9ad4ac06a54da7806a8acd9c5d1","transaction":"711527527619439146","amountNQT":"1100000000","transactionIndex":2,"ecBlockHeight":360943,"block":"6797727125503999830","recipientRS":"NXT-74VC-NKPE-RYCA-5LMPT","type":0,"feeNQT":"100000000","recipient":"4383817337783094122","version":1,"sender":"423766016895692955","timestamp":38929220,"ecBlockId":"10121077683890606382","height":360949,"subtype":0,"senderPublicKey":"4e5bbad625df3d536fa90b1e6a28c3f5a56e1fcbe34132391c8d3fd7f671cb19","deadline":1440,"blockTimestamp":38929430,"senderRS":"NXT-8E6V-YBWH-5VMR-26ESD","signature":"4318f36d9cf68ef0a8f58303beb0ed836b670914065a868053da5fe8b096bc0c268e682c0274e1614fc26f81be4564ca517d922deccf169eafa249a88de58036"}]}) if ( (json= cJSON_Parse(jsonstr)) != 0 ) { if ( (array= cJSON_GetObjectItem(json,"transactions")) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i= 2*INSTANTDEX_FEE ) totaltickets += 2; } } } } free_json(json); } free(jsonstr); } sprintf(buf,"{\"result\":\"lottostats\",\"totaltickets\":\"%d\"}",totaltickets); return(cJSON_Parse(buf)); } void set_best_amounts(int64_t *baseamountp,int64_t *relamountp,double price,double volume) { double checkprice,checkvol,distA,distB,metric,bestmetric = (1. / SMALLVAL); uint64_t baseamount,relamount,bestbaseamount = 0,bestrelamount = 0; int32_t i,j; baseamount = volume * SATOSHIDEN; relamount = ((price * volume) * SATOSHIDEN); //*baseamountp = baseamount, *relamountp = relamount; //return; for (i=-1; i<=1; i++) for (j=-1; j<=1; j++) { checkprice = prices777_price_volume(&checkvol,baseamount+i,relamount+j); distA = (checkprice - price); distA *= distA; distB = (checkvol - volume); distB *= distB; metric = sqrt(distA + distB); if ( metric < bestmetric ) { bestmetric = metric; bestbaseamount = baseamount + i; bestrelamount = relamount + j; //printf("i.%d j.%d metric. %f\n",i,j,metric); } } *baseamountp = bestbaseamount; *relamountp = bestrelamount; } int32_t bidask_parse(int32_t localaccess,struct destbuf *exchangestr,struct destbuf *name,struct destbuf *base,struct destbuf *rel,struct destbuf *gui,struct InstantDEX_quote *iQ,cJSON *json) { uint64_t basemult,relmult,baseamount,relamount; double price,volume; int32_t exchangeid,keysize,flag; char key[1024],buf[64],*methodstr; memset(iQ,0,sizeof(*iQ)); iQ->s.baseid = j64bits(json,"baseid"); iQ->s.relid = j64bits(json,"relid"); iQ->s.baseamount = j64bits(json,"baseamount"), iQ->s.relamount = j64bits(json,"relamount"); iQ->s.vol = jdouble(json,"volume"); iQ->s.price = jdouble(json,"price"); copy_cJSON(exchangestr,jobj(json,"exchange")); if ( exchangestr->buf[0] == 0 || find_exchange(&exchangeid,exchangestr->buf) == 0 ) exchangeid = -1; iQ->exchangeid = exchangeid; copy_cJSON(base,jobj(json,"base")); copy_cJSON(rel,jobj(json,"rel")); copy_cJSON(name,jobj(json,"name")); methodstr = jstr(json,"method"); if ( methodstr != 0 && (strcmp(methodstr,"placeask") == 0 || strcmp(methodstr,"ask") == 0) ) iQ->s.isask = 1; if ( iQ->s.vol < 0. ) { iQ->s.vol = -iQ->s.vol; iQ->s.isask ^= 1; } if ( methodstr != 0 && strcmp(exchangestr->buf,"wallet") == 0 && (iQ->s.baseid == NXT_ASSETID || strcmp(base->buf,"NXT") == 0) ) { flag = 1; if ( strcmp(methodstr,"placeask") == 0 ) methodstr = "placebid"; else if ( strcmp(methodstr,"placebid") == 0 ) methodstr = "placeask"; else if ( strcmp(methodstr,"ask") == 0 ) methodstr = "bid"; else if ( strcmp(methodstr,"bid") == 0 ) methodstr = "ask"; else flag = 0; if ( flag != 0 ) { iQ->s.baseid = iQ->s.relid, iQ->s.relid = NXT_ASSETID; strcpy(base->buf,rel->buf), strcpy(rel->buf,"NXT"); baseamount = iQ->s.baseamount; iQ->s.baseamount = iQ->s.relamount, iQ->s.relamount = baseamount; name->buf[0] = 0; if ( iQ->s.vol > SMALLVAL && iQ->s.price > SMALLVAL ) { iQ->s.vol *= iQ->s.price; iQ->s.price = 1. / iQ->s.price; } iQ->s.isask ^= 1; printf("INVERT\n"); } } if ( (iQ->s.timestamp= juint(json,"timestamp")) == 0 ) iQ->s.timestamp = (uint32_t)time(NULL); copy_cJSON(gui,jobj(json,"gui")), strncpy(iQ->gui,gui->buf,sizeof(iQ->gui)-1); iQ->s.automatch = juint(json,"automatch"); iQ->s.minperc = juint(json,"minperc"); if ( (iQ->s.duration= juint(json,"duration")) == 0 || iQ->s.duration > ORDERBOOK_EXPIRATION ) iQ->s.duration = ORDERBOOK_EXPIRATION; InstantDEX_name(key,&keysize,exchangestr->buf,name->buf,base->buf,&iQ->s.baseid,rel->buf,&iQ->s.relid); //printf(">>>>>>>>>>>> BASE.(%s) REL.(%s)\n",base->buf,rel->buf); iQ->s.basebits = stringbits(base->buf); iQ->s.relbits = stringbits(rel->buf); safecopy(iQ->base,base->buf,sizeof(iQ->base)); safecopy(iQ->rel,rel->buf,sizeof(iQ->rel)); iQ->s.offerNXT = j64bits(json,"offerNXT"); iQ->s.quoteid = j64bits(json,"quoteid"); if ( strcmp(exchangestr->buf,"jumblr") == 0 || strcmp(exchangestr->buf,"pangea") == 0 ) { if ( strcmp(exchangestr->buf,"pangea") == 0 ) { if ( juint(json,"rakemillis") != 0 ) iQ->s.minperc = juint(json,"rakemillis"); if ( j64bits(json,"bigblind") != 0 ) { iQ->s.baseamount = j64bits(json,"bigblind"); iQ->s.vol = ((double)iQ->s.baseamount / SATOSHIDEN); } if ( j64bits(json,"ante") != 0 ) iQ->s.relamount = j64bits(json,"ante"); iQ->s.minbuyin = juint(json,"minbuyin"); iQ->s.maxbuyin = juint(json,"maxbuyin"); /*if ( (iQ->s.maxrake= j64bits(json,"maxrake")) != 0 ) { if ( strcmp(base->buf,"BTC") == 0 && iQ->s.maxrake < SATOSHIDEN/10 ) iQ->s.maxrake = SATOSHIDEN/10; else if ( iQ->s.maxrake < 10*SATOSHIDEN ) iQ->s.maxrake = 10*SATOSHIDEN; }*/ } if ( iQ->s.price == 0. ) iQ->s.price = 1.; if ( iQ->s.vol == 0. ) iQ->s.vol = 1.; if ( iQ->s.baseamount == 0 ) iQ->s.baseamount = iQ->s.vol * SATOSHIDEN; if ( localaccess != 0 && strcmp(exchangestr->buf,"jumblr") == 0 ) { #ifdef later struct coin777 *coin; int32_t maxamount; if ( (coin= coin777_find(base->buf,0)) != 0 ) { if ( coin->jvin == 0 && coin->jvinaddr[0] == 0 ) { coin->jvin = -1; printf("initial state for jumblr.%s detected\n",coin->name); sleep(5); } if ( coin->jvin < 0 ) { printf("no %s unspents available for jumblr/pangea jvin.%d %.8f\n",coin->name,coin->jvin,dstr(coin->junspent)); return(-1); } maxamount = coin->junspent - coin->mgw.txfee*2 - (coin->junspent>>10); if ( iQ->s.baseamount > maxamount ) iQ->s.baseamount = maxamount; else if ( iQ->s.baseamount < coin->mgw.txfee ) { printf("jumblr/pangea amount %.8f less than txfee %.8f\n",dstr(iQ->s.baseamount),dstr(coin->mgw.txfee)); return(-1); } } else { printf("%s not initialized for jumblr\n",base->buf); return(-1); } #endif } } else { if ( iQ->s.baseamount == 0 || iQ->s.relamount == 0 ) { if ( iQ->s.price <= SMALLVAL || iQ->s.vol <= SMALLVAL ) return(-1); set_best_amounts(&iQ->s.baseamount,&iQ->s.relamount,iQ->s.price,iQ->s.vol); } } if ( iQ->s.quoteid == 0 ) iQ->s.quoteid = calc_quoteid(iQ); else if ( iQ->s.quoteid != calc_quoteid(iQ) ) { printf("bidask_parse quoteid.%llu != calc.%llu\n",(long long)iQ->s.quoteid,(long long)calc_quoteid(iQ)); return(-1); } if ( iQ->s.price > SMALLVAL && iQ->s.vol > SMALLVAL && iQ->s.baseid != 0 && iQ->s.relid != 0 ) { buf[0] = 0, _set_assetname(&basemult,buf,0,iQ->s.baseid); printf("baseid.%llu -> %s mult.%llu\n",(long long)iQ->s.baseid,buf,(long long)basemult); buf[0] = 0, _set_assetname(&relmult,buf,0,iQ->s.relid); printf("relid.%llu -> %s mult.%llu\n",(long long)iQ->s.relid,buf,(long long)relmult); //basemult = get_assetmult(iQ->baseid), relmult = get_assetmult(iQ->relid); baseamount = (iQ->s.baseamount + basemult/2) / basemult, baseamount *= basemult; relamount = (iQ->s.relamount + relmult/2) / relmult, relamount *= relmult; if ( iQ->s.price != 0. && iQ->s.vol != 0 ) { price = prices777_price_volume(&volume,baseamount,relamount); if ( fabs(iQ->s.price - price)/price > 0.001 ) { printf("cant create accurate price ref.(%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume); return(-1); } } } return(0); } char *InstantDEX(char *jsonstr,char *remoteaddr,int32_t localaccess) { char *prices777_allorderbooks(); char *InstantDEX_tradehistory(cJSON *json,int32_t firsti,int32_t endi); char *InstantDEX_cancelorder(cJSON *json,char *activenxt,char *secret,uint64_t sequenceid,uint64_t quoteid); struct destbuf exchangestr,method,gui,name,base,rel; double balance; char *retstr = 0,key[512],retbuf[1024],*activenxt,*secret,*coinstr; struct InstantDEX_quote iQ; struct exchange_info *exchange; cJSON *json; uint64_t assetbits,sequenceid; uint32_t maxdepth; int32_t invert=0,keysize,allfields; struct prices777 *prices = 0; //printf("INSTANTDEX.(%s)\n",jsonstr); //if ( INSTANTDEX.readyflag == 0 ) // return(0); if ( jsonstr != 0 && (json= cJSON_Parse(jsonstr)) != 0 ) { // test: asset/asset, asset/external, external/external, autofill and automatch // peggy integration if ( bidask_parse(localaccess,&exchangestr,&name,&base,&rel,&gui,&iQ,json) < 0 && (strcmp(exchangestr.buf,"jumblr") == 0 || strcmp(exchangestr.buf,"pangea") == 0) ) { //return(clonestr("{\"error\":\"invalid parameters\"}")); } if ( iQ.s.offerNXT == 0 ) iQ.s.offerNXT = IGUANA_MY64BITS; printf("isask.%d base.(%s) rel.(%s)\n",iQ.s.isask,base.buf,rel.buf); copy_cJSON(&method,jobj(json,"method")); if ( (sequenceid= j64bits(json,"orderid")) == 0 ) sequenceid = j64bits(json,"sequenceid"); allfields = juint(json,"allfields"); if ( (maxdepth= juint(json,"maxdepth")) <= 0 ) maxdepth = MAX_DEPTH; if ( exchangestr.buf[0] == 0 ) { if ( iQ.s.baseid != 0 && iQ.s.relid != 0 ) strcpy(exchangestr.buf,"nxtae"); else strcpy(exchangestr.buf,"basket"); } assetbits = InstantDEX_name(key,&keysize,exchangestr.buf,name.buf,base.buf,&iQ.s.baseid,rel.buf,&iQ.s.relid); //printf("2nd isask.%d base.(%s) rel.(%s)\n",iQ.s.isask,base.buf,rel.buf); exchange = exchange_find(exchangestr.buf); secret = jstr(json,"secret"), activenxt = jstr(json,"activenxt"); if ( secret == 0 ) { secret = IGUANA_NXTACCTSECRET; activenxt = IGUANA_NXTADDR; } if ( strcmp(method.buf,"exit") == 0 ) { printf("getchar and then exit\n"); getchar(); exit(0); } if ( strcmp(method.buf,"orderstatus") == 0 ) retstr = InstantDEX_orderstatus(json,sequenceid,iQ.s.quoteid); else if ( strcmp(method.buf,"cancelorder") == 0 ) retstr = InstantDEX_cancelorder(json,jstr(json,"activenxt"),jstr(json,"secret"),sequenceid,iQ.s.quoteid); else if ( strcmp(method.buf,"openorders") == 0 ) retstr = InstantDEX_openorders(json,IGUANA_NXTADDR,juint(json,"allorders")); else if ( strcmp(method.buf,"tradehistory") == 0 ) retstr = InstantDEX_tradehistory(json,juint(json,"firsti"),juint(json,"endi")); else if ( strcmp(method.buf,"withdraw") == 0 ) retstr = InstantDEX_withdraw(json); else if ( strcmp(method.buf,"balance") == 0 ) { if ( exchange != 0 && exchange->issue.trade != 0 ) { if ( exchange->issue.balances != 0 ) { if ( exchange->balancejson != 0 ) free_json(exchange->balancejson), exchange->balancejson = 0; exchange->lastbalancetime = (uint32_t)time(NULL); if ( (exchange->balancejson= (*exchange->issue.balances)(&exchange->cHandle,exchange)) != 0 ) { if ( (coinstr= jstr(json,"base")) != 0 ) retstr = (*exchange->issue.parsebalance)(exchange,&balance,coinstr); else retstr = jprint(exchange->balancejson,0); } else retstr = clonestr("{\"error\":\"balances null return\"}"); } else retstr = clonestr("{\"error\":\"no balances function\"}"); } else retstr = clonestr("{\"error\":\"cant find exchange trade or balances function\"}"); printf("%s ptr.%p trade.%p\n",exchangestr.buf,exchange,exchange!=0?exchange->issue.trade:0); } else if ( strcmp(method.buf,"allorderbooks") == 0 ) retstr = prices777_allorderbooks(); else if ( strcmp(method.buf,"allexchanges") == 0 ) retstr = jprint(exchanges_json(),1); else if ( strcmp(method.buf,"lottostats") == 0 ) retstr = jprint(InstantDEX_lottostats(),1); /* else if ( strcmp(method.buf,"tradesequence") == 0 ) { //printf("call tradesequence.(%s)\n",jsonstr); int32_t dotrade,numtrades; struct prices777_order trades[256]; struct pending_trade *pend; dotrade = juint(json,"dotrade"); retstr = InstantDEX_tradesequence(0,0,0,&numtrades,trades,(int32_t)(sizeof(trades)/sizeof(*trades)),dotrade,activenxt,secret,json); if ( dotrade != 0 ) { pend = calloc(1,sizeof(*pend)); pend->dir = iQ.s.isask == 0 ? 1 : -1, pend->price = iQ.s.price, pend->volume = iQ.s.vol, pend->orderid = iQ.s.quoteid; pend->tradesjson = json; pend->type = 'S'; pend->timestamp = (uint32_t)time(NULL); //InstantDEX_history(0,pend,0); queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); } }*/ else if ( strcmp(method.buf,"makebasket") == 0 ) { if ( (prices= prices777_makebasket(0,json,1,"basket",0,0)) != 0 ) retstr = clonestr("{\"result\":\"basket made\"}"); else retstr = clonestr("{\"error\":\"couldnt make basket\"}"); } else if ( strcmp(method.buf,"peggyrates") == 0 ) { //if ( SUPERNET.peggy != 0 ) // retstr = peggyrates(juint(json,"timestamp"),jstr(json,"name")); //else retstr = clonestr("{\"error\":\"peggy disabled\"}"); } else if ( strcmp(method.buf,"LSUM") == 0 ) { sprintf(retbuf,"{\"result\":\"%s\",\"amount\":%d}",(rand() & 1) ? "BUY" : "SELL",(rand() % 100) * 100000); retstr = clonestr(retbuf); } else if ( strcmp(method.buf,"placebid") == 0 || strcmp(method.buf,"placeask") == 0 ) return(InstantDEX_placebidask(0,sequenceid,exchangestr.buf,name.buf,base.buf,rel.buf,&iQ,jstr(json,"extra"),secret,activenxt,json)); else if ( strcmp(exchangestr.buf,"active") == 0 && strcmp(method.buf,"orderbook") == 0 ) retstr = prices777_activebooks(name.buf,base.buf,rel.buf,iQ.s.baseid,iQ.s.relid,maxdepth,allfields,strcmp(exchangestr.buf,"active") == 0 || juint(json,"tradeable")); else if ( (prices= prices777_find(&invert,iQ.s.baseid,iQ.s.relid,exchangestr.buf)) == 0 ) { if ( (prices= prices777_poll(exchangestr.buf,name.buf,base.buf,iQ.s.baseid,rel.buf,iQ.s.relid)) != 0 ) { if ( prices777_equiv(prices->baseid) == prices777_equiv(iQ.s.baseid) && prices777_equiv(prices->relid) == prices777_equiv(iQ.s.relid) ) invert = 0; else if ( prices777_equiv(prices->baseid) == prices777_equiv(iQ.s.relid) && prices777_equiv(prices->relid) == prices777_equiv(iQ.s.baseid) ) invert = 1; else invert = 0, printf("baserel not matching (%s %s) %llu %llu vs (%s %s) %llu %llu\n",prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,base.buf,rel.buf,(long long)iQ.s.baseid,(long long)iQ.s.relid); } } if ( retstr == 0 && prices != 0 ) { if ( strcmp(method.buf,"disablequotes") == 0 ) { if ( prices != 0 ) { if ( strcmp(prices->exchange,"unconf") == 0 ) return(clonestr("{\"error\":\"cannot disable unconf\"}")); prices->disabled = 1; return(clonestr("{\"result\":\"success\"}")); } else return(clonestr("{\"error\":\"no prices to disable\"}")); } else if ( strcmp(method.buf,"enablequotes") == 0 ) { if ( prices != 0 ) { prices->disabled = 0; return(clonestr("{\"result\":\"success\"}")); } else return(clonestr("{\"error\":\"no prices to enable\"}")); } else if ( strcmp(method.buf,"orderbook") == 0 ) { if ( maxdepth < MAX_DEPTH ) return(prices777_orderbook_jsonstr(invert,IGUANA_MY64BITS,prices,&prices->O,maxdepth,allfields)); else if ( (retstr= prices->orderbook_jsonstrs[invert][allfields]) == 0 ) { retstr = prices777_orderbook_jsonstr(invert,IGUANA_MY64BITS,prices,&prices->O,MAX_DEPTH,allfields); portable_mutex_lock(&prices->mutex); if ( prices->orderbook_jsonstrs[invert][allfields] != 0 ) free(prices->orderbook_jsonstrs[invert][allfields]); prices->orderbook_jsonstrs[invert][allfields] = retstr; portable_mutex_unlock(&prices->mutex); if ( retstr == 0 ) retstr = clonestr("{}"); } if ( retstr != 0 ) retstr = clonestr(retstr); } //else if ( strcmp(method.buf,"tradebot") == 0 ) // retstr = InstantDEX_tradebot(prices,json,&iQ,invert); } //if ( Debuglevel > 2 ) printf("(%s) %p exchange.(%s) base.(%s) %llu rel.(%s) %llu | name.(%s) %llu\n",retstr!=0?retstr:"",prices,exchangestr.buf,base.buf,(long long)iQ.s.baseid,rel.buf,(long long)iQ.s.relid,name.buf,(long long)assetbits); } return(retstr); } char *bidask_func(int32_t localaccess,int32_t valid,char *sender,cJSON *json,char *origargstr) { struct destbuf gui,exchangestr,name,base,rel,offerNXT; struct InstantDEX_quote iQ; copy_cJSON(&offerNXT,jobj(json,"offerNXT")); //printf("got (%s)\n",origargstr); if ( strcmp(IGUANA_NXTADDR,offerNXT.buf) != 0 ) { if ( bidask_parse(localaccess,&exchangestr,&name,&base,&rel,&gui,&iQ,json) == 0 ) return(InstantDEX_placebidask(sender,j64bits(json,"orderid"),exchangestr.buf,name.buf,base.buf,rel.buf,&iQ,jstr(json,"extra"),jstr(json,"secret"),jstr(json,"activenxt"),json)); else printf("error with incoming bidask\n"); } else fprintf(stderr,"got my bidask from network (%s)\n",origargstr); return(clonestr("{\"result\":\"got loopback bidask\"}")); }