/****************************************************************************** * Copyright © 2014-2015 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. * * * ******************************************************************************/ #ifndef xcode_trades_h #define xcode_trades_h struct tradehistory { uint64_t assetid,purchased,sold; }; struct tradehistory *_update_tradehistory(struct tradehistory *hist,uint64_t assetid,uint64_t purchased,uint64_t sold) { int32_t i = 0; if ( hist == 0 ) hist = calloc(1,sizeof(*hist)); if ( hist[i].assetid != 0 ) { for (i=0; hist[i].assetid!=0; i++) if ( hist[i].assetid == assetid ) break; } if ( hist[i].assetid == 0 ) { hist = realloc(hist,(i+2) * sizeof(*hist)); memset(&hist[i],0,2 * sizeof(hist[i])); hist[i].assetid = assetid; } if ( hist[i].assetid == assetid ) { hist[i].purchased += purchased; hist[i].sold += sold; printf("hist[%d] %llu +%llu -%llu -> (%llu %llu)\n",i,(long long)hist[i].assetid,(long long)purchased,(long long)sold,(long long)hist[i].purchased,(long long)hist[i].sold); } else printf("_update_tradehistory: impossible case!\n"); return(hist); } struct tradehistory *update_tradehistory(struct tradehistory *hist,uint64_t srcasset,uint64_t srcamount,uint64_t destasset,uint64_t destamount) { hist = _update_tradehistory(hist,srcasset,0,srcamount); hist = _update_tradehistory(hist,destasset,destamount,0); return(hist); } cJSON *_tradehistory_json(struct tradehistory *asset) { cJSON *json = cJSON_CreateObject(); char numstr[64]; sprintf(numstr,"%llu",(long long)asset->assetid), cJSON_AddItemToObject(json,"assetid",cJSON_CreateString(numstr)); sprintf(numstr,"%.8f",dstr(asset->purchased)), cJSON_AddItemToObject(json,"purchased",cJSON_CreateString(numstr)); sprintf(numstr,"%.8f",dstr(asset->sold)), cJSON_AddItemToObject(json,"sold",cJSON_CreateString(numstr)); sprintf(numstr,"%.8f",dstr(asset->purchased) - dstr(asset->sold)), cJSON_AddItemToObject(json,"net",cJSON_CreateString(numstr)); return(json); } cJSON *tradehistory_json(struct tradehistory *hist,cJSON *array) { int32_t i; char assetname[64],numstr[64]; cJSON *assets,*netpos,*item,*json = cJSON_CreateObject(); cJSON_AddItemToObject(json,"rawtrades",array); assets = cJSON_CreateArray(); netpos = cJSON_CreateArray(); for (i=0; hist[i].assetid!=0; i++) { cJSON_AddItemToArray(assets,_tradehistory_json(&hist[i])); item = cJSON_CreateObject(); get_assetname(assetname,hist[i].assetid); cJSON_AddItemToObject(item,"asset",cJSON_CreateString(assetname)); sprintf(numstr,"%.8f",dstr(hist[i].purchased) - dstr(hist[i].sold)), cJSON_AddItemToObject(item,"net",cJSON_CreateString(numstr)); cJSON_AddItemToArray(netpos,item); } cJSON_AddItemToObject(json,"assets",assets); cJSON_AddItemToObject(json,"netpositions",netpos); return(json); } cJSON *tabulate_trade_history(uint64_t mynxt64bits,cJSON *array) { int32_t i,n; cJSON *item; long balancing; struct tradehistory *hist = 0; uint64_t src64bits,srcamount,srcasset,dest64bits,destamount,destasset,jump64bits,jumpamount,jumpasset; //{"requestType":"processjumptrade","NXT":"5277534112615305538","assetA":"5527630","amountA":"6700000000","other":"1510821971811852351","assetB":"12982485703607823902","amountB":"100000000","feeA":"250000000","balancing":0,"feeAtxid":"1234468909119892020","triggerhash":"34ea5aaeeeb62111a825a94c366b4ae3d12bb73f9a3413a27d1b480f6029a73c"} if ( array != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i %llu) via %llu\n",(long long)mynxt64bits,(long long)src64bits,(long long)dest64bits,(long long)jump64bits); } else printf("illegal tabulate_trade_entry %llu: %llu %llu %llu || %llu %llu %llu\n",(long long)mynxt64bits,(long long)src64bits,(long long)srcamount,(long long)srcasset,(long long)dest64bits,(long long)destamount,(long long)destasset); } } if ( hist != 0 ) { array = tradehistory_json(hist,array); free(hist); } return(array); } cJSON *get_tradehistory(char *refNXTaddr,uint32_t timestamp) { char cmdstr[1024],NXTaddr[64],*jsonstr; struct destbuf receiverstr,message,newtriggerhash,triggerhash; cJSON *json,*array,*txobj,*msgobj,*attachment,*retjson = 0,*histarray = 0; int32_t i,j,n,m,duplicates = 0; uint64_t senderbits; if ( timestamp == 0 ) timestamp = 38785003; sprintf(cmdstr,"requestType=getBlockchainTransactions&account=%s×tamp=%u&withMessage=true",refNXTaddr,timestamp); if ( (jsonstr= issue_NXTPOST(cmdstr)) != 0 ) { 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 ",message); unstringify(message.buf); if ( (msgobj= cJSON_Parse(message.buf)) != 0 ) { //printf("(%s)\n",message); if ( histarray == 0 ) histarray = cJSON_CreateArray(), j = m = 0; else { copy_cJSON(&newtriggerhash,cJSON_GetObjectItem(msgobj,"triggerhash")); m = cJSON_GetArraySize(histarray); for (j=0; jquoteid)) != 0 ) { iQ->s.closed = 1; delete_iQ(pend->quoteid); } else printf("free_pending: cant find pending tx for %llu\n",(long long)pend->quoteid); if ( pend->triggertx != 0 ) free(pend->triggertx); if ( pend->txbytes != 0 ) free(pend->txbytes); if ( pend->tradesjson != 0 ) free_json(pend->tradesjson); free(pend); } /*void oldInstantDEX_history(int32_t action,struct pending_trade *pend,char *str) { uint8_t txbuf[32768]; char *tmpstr; uint16_t n; long len = 0; // struct pending_trade { struct queueitem DL; struct prices777_order order; uint64_t triggertxid,txid,quoteid,orderid; struct prices777 *prices; char *triggertx,*txbytes; cJSON *tradesjson; double price,volume; uint32_t timestamp; int32_t dir,type; }; memcpy(&txbuf[len],&action,sizeof(action)), len += sizeof(action); if ( action == 0 ) { memcpy(&txbuf[len],pend,sizeof(*pend)), len += sizeof(*pend); if ( pend->triggertx != 0 ) { n = (uint16_t)strlen(pend->triggertx) + 1; memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); memcpy(&txbuf[len],pend->triggertx,n), len += n; } if ( pend->txbytes != 0 ) { n = (uint16_t)strlen(pend->txbytes) + 1; memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); memcpy(&txbuf[len],pend->txbytes,n), len += n; } if ( pend->tradesjson != 0 ) { tmpstr = jprint(pend->tradesjson,0); n = (uint16_t)strlen(tmpstr) + 1; memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); memcpy(&txbuf[len],tmpstr,n), len += n; free(tmpstr); } } else { memcpy(&txbuf[len],&pend->orderid,sizeof(pend->orderid)), len += sizeof(pend->orderid); memcpy(&txbuf[len],&pend->quoteid,sizeof(pend->quoteid)), len += sizeof(pend->quoteid); } if ( str != 0 ) { n = (uint16_t)strlen(str) + 1; memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); memcpy(&txbuf[len],str,n), len += n; } else { n = 0; memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); } txind777_create(INSTANTDEX.history,INSTANTDEX.numhist,pend->timestamp,txbuf,len); txinds777_flush(INSTANTDEX.history,INSTANTDEX.numhist,pend->timestamp); INSTANTDEX.numhist++; }*/ char *InstantDEX_loadhistory(struct pending_trade *pend,int32_t *actionp,uint8_t *txbuf,int32_t size) { char *tmpstr,*str = 0; uint16_t n; long len = 0; memcpy(actionp,&txbuf[len],sizeof(*actionp)), len += sizeof(*actionp); if ( *actionp == 0 ) { memcpy(pend,&txbuf[len],sizeof(*pend)), len += sizeof(*pend); //printf("pendsize.%ld trigger.%p tx.%p json.%p\n",(long)sizeof(*pend),pend->triggertx,pend->txbytes,pend->tradesjson); if ( pend->triggertx != 0 ) { memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); pend->triggertx = calloc(1,n); memcpy(pend->triggertx,&txbuf[len],n), len += n; } if ( pend->txbytes != 0 ) { memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); pend->txbytes = calloc(1,n); memcpy(pend->txbytes,&txbuf[len],n), len += n; } if ( pend->tradesjson != 0 ) { memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); tmpstr = calloc(1,n); memcpy(tmpstr,&txbuf[len],n), len += n; if ( (pend->tradesjson= cJSON_Parse(tmpstr)) == 0 ) printf("cant parse.(%s)\n",tmpstr); free(tmpstr); } } else { memcpy(&pend->orderid,&txbuf[len],sizeof(pend->orderid)), len += sizeof(pend->orderid); memcpy(&pend->quoteid,&txbuf[len],sizeof(pend->quoteid)), len += sizeof(pend->quoteid); } memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); if ( n != 0 ) { str = calloc(1,n); memcpy(str,&txbuf[len],n), len += n; } if ( len != size ) printf("loadhistory warning: len.%ld != size.%d\n",len,size); return(str); } struct pending_trade *InstantDEX_historyi(int32_t *actionp,char **strp,int32_t i,uint8_t *txbuf,int32_t maxsize) { struct pending_trade *pend = 0; /* void *ptr; int32_t size; *strp = 0; txinds777_seek(INSTANTDEX.history,i); if ( (ptr= txinds777_read(&size,txbuf,INSTANTDEX.history)) == 0 || size <= 0 || size > maxsize ) { printf("InstantDEX_inithistory: error reading entry.%d | ptr.%p size.%d\n",i,ptr,maxsize); return(0); } pend = calloc(1,sizeof(*pend)); *strp = InstantDEX_loadhistory(pend,actionp,ptr,size);*/ return(pend); } int32_t oldInstantDEX_inithistory(int32_t firsti,int32_t endi) { int32_t i,action; uint8_t txbuf[32768]; char *str; struct pending_trade *pend; printf("InstantDEX_inithistory firsti.%d endi.%d\n",firsti,endi); for (i=firsti; itype,pend->type!=0?pend->type:'0',action,(long long)pend->orderid,(long long)pend->quoteid,str!=0?str:""); if ( str != 0 ) free(str); free_pending(pend); } } return(i); } cJSON *InstantDEX_tradeitem(struct pending_trade *pend) { // struct pending_trade { struct queueitem DL; struct prices777_order order; uint64_t triggertxid,txid,quoteid,orderid; struct prices777 *prices; char *triggertx,*txbytes; cJSON *tradesjson; double price,volume; uint32_t timestamp; int32_t dir,type; }; struct InstantDEX_quote *iQ; char str[64]; cJSON *json = cJSON_CreateObject(); str[0] = (pend->type == 0) ? '0' : pend->type; str[1] = 0; jaddstr(json,"type",str); jaddnum(json,"timestamp",pend->timestamp); jadd64bits(json,"orderid",pend->orderid), jadd64bits(json,"quoteid",pend->quoteid); if ( (iQ= find_iQ(pend->quoteid)) != 0 ) { if ( iQ->s.baseid != 0 && iQ->s.relid != 0 ) jadd64bits(json,"baseid",iQ->s.baseid), jadd64bits(json,"relid",iQ->s.relid); if ( iQ->s.baseamount != 0 && iQ->s.relamount != 0 ) jaddnum(json,"baseqty",iQ->s.baseamount), jaddnum(json,"relqty",iQ->s.relamount); } else printf("tradeitem cant find quoteid.%llu\n",(long long)pend->quoteid); if ( pend->dir != 0 ) jaddnum(json,"dir",pend->dir); if ( pend->price > SMALLVAL && pend->volume > SMALLVAL ) jaddnum(json,"price",pend->price), jaddnum(json,"volume",pend->volume); if ( pend->triggertxid != 0 ) jadd64bits(json,"triggertxid",pend->triggertxid); if ( pend->txid != 0 ) jadd64bits(json,"txid",pend->txid); if ( pend->triggertx != 0 ) jaddstr(json,"triggertx",pend->triggertx); if ( pend->txbytes != 0 ) jaddstr(json,"txbytes",pend->txbytes); return(json); } char *InstantDEX_withdraw(cJSON *argjson) { char *exchangestr,*str; struct exchange_info *exchange; int32_t exchangeid; if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) { if ( exchange->issue.withdraw != 0 ) { if ( (str= (*exchange->issue.withdraw)(&exchange->cHandle,exchange,argjson)) == 0 ) str = clonestr("{\"result\":\"nothing returned from exchange\"}"); return(str); } else return(clonestr("{\"error\":\"no withdraw function\"}")); } return(clonestr("{\"error\":\"withdraw is not yet\"}")); } char *InstantDEX_tradehistory(cJSON *argjson,int32_t firsti,int32_t endi) { /* cJSON *json,*array,*item,*tmp; int32_t exchangeid,i,action; uint8_t txbuf[32768]; char *str,*exchangestr; struct pending_trade *pend; struct exchange_info *exchange; if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) { if ( exchange->issue.tradehistory != 0 ) { if ( (str= (*exchange->issue.tradehistory)(&exchange->cHandle,exchange,argjson)) == 0 ) str = clonestr("{\"result\":\"nothing returned from exchange\"}"); return(str); } else return(clonestr("{\"error\":\"no tradehistory function\"}")); } json = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( endi == 0 ) endi = INSTANTDEX.numhist-1; if ( endi < firsti ) endi = firsti; for (i=firsti; i<=endi; i++) { if ( (pend= InstantDEX_historyi(&action,&str,i,txbuf,sizeof(txbuf))) != 0 ) { item = cJSON_CreateObject(); jaddnum(item,"i",i); jaddnum(item,"action",action); jadd(item,"trade",InstantDEX_tradeitem(pend)); if ( pend->tradesjson != 0 ) jadd(item,"trades",cJSON_Duplicate(pend->tradesjson,1)); if ( str != 0 ) { if ( (tmp= cJSON_Parse(str)) != 0 ) jadd(item,"str",tmp); free(str); } free_pending(pend); jaddi(array,item); } } jadd(json,"tradehistory",array); jaddnum(json,"numentries",INSTANTDEX.numhist); return(jprint(json,1));*/ return(0); } int32_t substr128(char *dest,char *src) { char zeroes[129],*match; int32_t i; for (i=0; i<128; i++) zeroes[i] = '0'; zeroes[i] = 0; strcpy(dest,src); if ( (match= strstr(dest,zeroes)) != 0 ) { strcpy(match,"Z"); for (i=0; match[128+i]!=0; i++) match[i+1] = match[128+i]; match[i+1] = 0; } //printf("substr128.(%s) -> (%s)\n",src,dest); return(0); } uint64_t gen_NXTtx(struct NXTtx *tx,uint64_t dest64bits,uint64_t assetidbits,uint64_t qty,uint64_t orderid,uint64_t quoteid,int32_t deadline,char *reftx,char *phaselink,uint32_t finishheight,char *phasesecret) { char secret[8192],cmd[16384],destNXTaddr[64],assetidstr[64],hexstr[64],*retstr; uint8_t msgbuf[17]; cJSON *json; int32_t len; uint64_t phasecost = 0; if ( deadline > 1000 ) deadline = 1000; expand_nxt64bits(destNXTaddr,dest64bits); memset(tx,0,sizeof(*tx)); if ( ((phasesecret != 0 && phasesecret[0] != 0) || (phaselink!= 0 && phaselink[0] != 0)) && finishheight <= _get_NXTheight(0) ) { printf("finish height.%u must be in the future.%u\n",finishheight,_get_NXTheight(0)); return(0); } if ( phaselink != 0 || phasesecret != 0 ) phasecost = MIN_NQTFEE; cmd[0] = 0; if ( assetidbits == NXT_ASSETID ) sprintf(cmd,"requestType=sendMoney&amountNQT=%lld",(long long)qty); else { expand_nxt64bits(assetidstr,assetidbits); if ( is_mscoin(assetidstr) == 0 ) sprintf(cmd,"requestType=transferAsset&asset=%s&quantityQNT=%lld",assetidstr,(long long)qty); else sprintf(cmd,"requestType=transferCurrency¤cy=%s&units=%lld",assetidstr,(long long)qty); } if ( quoteid != 0 ) { len = 0; printf("serialize buffer\n"); //len = txind777_txbuf(msgbuf,len,orderid,sizeof(orderid)); //len = txind777_txbuf(msgbuf,len,quoteid,sizeof(quoteid)); init_hexbytes_noT(hexstr,msgbuf,len); sprintf(cmd+strlen(cmd),"&messageIsText=true&message=%s",hexstr); } if ( cmd[0] != 0 ) { escape_code(secret,IGUANA_NXTACCTSECRET); sprintf(cmd+strlen(cmd),"&deadline=%u&feeNQT=%lld&secretPhrase=%s&recipient=%s&broadcast=false",deadline,(long long)MIN_NQTFEE+phasecost,secret,destNXTaddr); if ( reftx != 0 && reftx[0] != 0 ) sprintf(cmd+strlen(cmd),"&referencedTransactionFullHash=%s",reftx); if ( phaselink != 0 && phaselink[0] != 0 ) sprintf(cmd+strlen(cmd),"&phased=true&phasingFinishHeight=%u&phasingVotingModel=4&phasingQuorum=1&phasingLinkedFullHash=%s",finishheight,phaselink); else if ( phasesecret != 0 && phasesecret[0] != 0 ) sprintf(cmd+strlen(cmd),"&phased=true&phasingFinishHeight=%u&phasingVotingModel=5&phasingHashedSecretAlgorithm=62&phasingQuorum=1&phasingHashedSecret=%s",finishheight,phasesecret); //printf("generated cmd.(%s)\n",cmd); if ( (retstr= issue_NXTPOST(cmd)) != 0 ) { //printf("(%s)\n",retstr); if ( (json= cJSON_Parse(retstr)) != 0 ) { if ( extract_cJSON_str(tx->txbytes,MAX_JSON_FIELD,json,"transactionBytes") > 0 && extract_cJSON_str(tx->utxbytes,MAX_JSON_FIELD,json,"unsignedTransactionBytes") > 0 && extract_cJSON_str(tx->fullhash,MAX_JSON_FIELD,json,"fullHash") > 0 && extract_cJSON_str(tx->sighash,MAX_JSON_FIELD,json,"signatureHash") > 0 ) { tx->txid = j64bits(json,"transaction"); substr128(tx->utxbytes2,tx->utxbytes); } free_json(json); } free(retstr); } } return(tx->txid); } struct NXTtx *fee_triggerhash(char *triggerhash,uint64_t orderid,uint64_t quoteid,int32_t deadline) { static struct NXTtx fee; if ( fee.fullhash[0] == 0 ) gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,0,0,0,0); strcpy(triggerhash,fee.fullhash); return(&fee); } uint64_t InstantDEX_swapstr(char *sendphased,char *phasesecret,uint64_t *txidp,char *triggertx,char *txbytes,char *swapstr,uint64_t orderid,struct prices777_order *order,char *triggerhash,char *phaselink,int32_t finishheight) { struct NXTtx fee,sendtx; uint64_t otherqty = 0,otherassetbits = 0,assetidbits = 0,qty = 0; int32_t deadline = INSTANTDEX_TRIGGERDEADLINE; if ( finishheight != 0 ) { if ( finishheight > FINISH_HEIGHT ) deadline *= (finishheight / FINISH_HEIGHT); finishheight += _get_NXTheight(0); } swapstr[0] = triggertx[0] = txbytes[0] = 0; *txidp = 0; gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,order->s.quoteid,deadline,triggerhash,0,0,0); strcpy(triggertx,fee.txbytes); if ( order->s.baseamount < 0 ) assetidbits = order->s.baseid, qty = -order->s.baseamount, otherassetbits = order->s.relid, otherqty = order->s.relamount; else if ( order->s.relamount < 0 ) assetidbits = order->s.relid, qty = -order->s.relamount, otherassetbits = order->s.baseid, otherqty = order->s.baseamount; printf("genNXTtx.(%llu/%llu) finish at %u vs %u lag %u deadline %d assetidbits.%llu sendphased.(%s)\n",(long long)orderid,(long long)order->s.quoteid,finishheight,_get_NXTheight(0),finishheight-_get_NXTheight(0),deadline,(long long)assetidbits,sendphased!=0?sendphased:""); if ( sendphased != 0 && assetidbits != 0 && qty != 0 ) { if ( triggerhash == 0 || triggerhash[0] == 0 ) triggerhash = fee.fullhash; gen_NXTtx(&sendtx,order->s.offerNXT,assetidbits,qty,orderid,order->s.quoteid,deadline,triggerhash,phaselink,finishheight,phasesecret); *txidp = sendtx.txid; strcpy(txbytes,sendtx.txbytes); sprintf(swapstr,",\"F\":\"%u\",\"T\":\"%s\",\"FH\":\"%s\",\"U\":\"%s\",\"S\":\"%s\",\"a\":\"%llu\",\"q\":\"%llu\"}",finishheight,fee.fullhash,sendtx.fullhash,sendtx.utxbytes2,sendtx.sighash,(long long)otherassetbits,(long long)otherqty); } else sprintf(swapstr,",\"F\":\"%u\",\"T\":\"%s\",\"a\":\"%llu\",\"q\":\"%llu\"}",finishheight,fee.fullhash,(long long)otherassetbits,(long long)otherqty); return(fee.txid); } uint64_t prices777_swapbuf(char *sendphased,char *phasesecret,uint64_t *txidp,char *triggertx,char *txbytes,char *swapbuf,char *exchangestr,char *base,char *rel,struct prices777_order *order,uint64_t orderid,int32_t finishoffset,char *triggerhash) { char swapstr[4096],*str; uint64_t txid = 0; *txidp = 0; if ( strcmp(exchangestr,"wallet") == 0 ) str = "swap"; else { str = order->wt > 0. ? "buy" : (order->wt < 0. ? "sell" : "swap"); //printf("not wallet!\n"); getchar(); } if ( finishoffset == 0 ) finishoffset = FINISH_HEIGHT; sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%llu\",\"fillNXT\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"%s\",\"exchange\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\",\"baseid\":\"%llu\",\"relid\":\"%llu\",\"baseqty\":\"%lld\",\"relqty\":\"%lld\"}",(long long)orderid,(long long)order->s.quoteid,(long long)order->s.offerNXT,IGUANA_NXTADDR,str,exchangestr,base,rel,(long long)order->s.baseid,(long long)order->s.relid,(long long)order->s.baseamount,(long long)order->s.relamount); if ( order->s.price > SMALLVAL ) sprintf(swapbuf + strlen(swapbuf) - 1,",\"price\":%.8f,\"volume\":%.8f}",order->s.price,order->s.vol); txid = InstantDEX_swapstr(sendphased,phasesecret,txidp,triggertx,txbytes,swapstr,orderid,order,triggerhash,0,finishoffset); strcpy(swapbuf+strlen(swapbuf)-1,swapstr); //printf("swapbuf.(%s)\n",swapbuf); return(txid); } char *prices777_finishswap(int32_t dotrade,int32_t type,struct pending_trade *pend,char *swapbuf,char *triggertx,char *txbytes) { uint32_t nonce; char *str; if ( triggertx[0] != 0 ) pend->triggertx = clonestr(triggertx); if ( txbytes[0] != 0 ) pend->txbytes = clonestr(txbytes); pend->order.s.swap = 1; pend->tradesjson = cJSON_Parse(swapbuf); pend->type = type; printf("quoteid.%llu and pending.%d\n",(long long)pend->order.s.quoteid,pend->order.s.pending); if ( dotrade != 0 ) { if ( (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) free(str); pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); } //InstantDEX_history(0,pend,swapbuf); return(clonestr(swapbuf)); } /*int32_t subatomic_pubkeyhash(char *pubkeystr,char *pkhash,struct coin777 *coin,uint64_t quoteid) { printf("subatomic pubkeyhash not yet\n"); char tmpswapaddr[128],swapacct[128]; uint8_t tmpbuf[128]; struct destbuf pubkey; sprintf(swapacct,"atomic.%llu",(long long)quoteid); pkhash[0] = pubkeystr[0] = 0; if ( get_acct_coinaddr(tmpswapaddr,coin->name,coin->serverport,coin->userpass,swapacct) != 0 ) { get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,tmpswapaddr); strcpy(pubkeystr,pubkey.buf); calc_OP_HASH160(pkhash,tmpbuf,pubkey.buf); return(0); } return(-1); }*/ int32_t complete_swap(struct InstantDEX_quote *iQ,uint64_t orderid,uint64_t quoteid,int32_t err) { /*int32_t errcode=-1,errcode2=-2; char *txstr,*txstr2; int32_t iter; struct pending_trade *pend; for (iter=0; iter<2; iter++) { while ( (pend= queue_dequeue(&Pending_offersQ.pingpong[iter],0)) != 0 ) { if ( pend->quoteid == quoteid ) { if ( err == 0 && issue_broadcastTransaction(&errcode2,&txstr2,pend->txbytes,IGUANA_NXTACCTSECRET) == pend->txid && errcode2 == 0 ) { if ( err == 0 && (issue_broadcastTransaction(&errcode,&txstr,pend->triggertx,IGUANA_NXTACCTSECRET) != pend->triggertxid || errcode != 0) ) err = -13; } if ( err == 0 && errcode == 0 && errcode2 == 0 ) { iQ->s.matched = 1; //InstantDEX_history(1,pend,0); } //else InstantDEX_history(-1,pend,0); printf("errs.(%d %d %d) COMPLETED %llu/%llu %d %f %f with txids %llu %llu\n",err,errcode,errcode2,(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume,(long long)pend->triggertxid,(long long)pend->txid); pend->queueflag = 1; pend->finishtime = (uint32_t)time(NULL); return(1); } queue_enqueue("requeue",&Pending_offersQ.pingpong[iter ^ 1],&pend->DL,0); } }*/ printf("complete swap is notyet\n"); return(-1); } char *prices777_tradewallet(struct pending_trade *pend) { printf("tradewallet is not yet\n"); return(0); /* struct coin777 *recvcoin,*sendcoin; cJSON *walletitem,*item; char fieldA[64],fieldB[64],triggertx[4096],txbytes[4096],fieldpkhash[64],refredeemscript[2048],scriptPubKey[128],p2shaddr[64]; char swapbuf[8192],buf[1024],*rpubA=0,*rpubB=0,*rpkhash=0,*spubA=0,*spubB=0,*spkhash=0,*recvstr=0; char *sendstr=0,*refundtx,*redeemscript,*str; int32_t finishin,deadline; uint32_t nonce; uint64_t sendamount,recvamount,sendasset,recvasset; struct destbuf base,rel; if ( pend->item != 0 && (item= jitem(pend->item,0)) != 0 && (walletitem= jobj(item,"wallet")) != 0 ) { finishin = (pend->extra[0] == 0) ? 200 : myatoi(pend->extra,10000); if ( finishin < FINISH_HEIGHT ) finishin = FINISH_HEIGHT; copy_cJSON(&base,jobj(item,"base")); copy_cJSON(&rel,jobj(item,"rel")); if ( (recvamount= j64bits(item,"recvbase")) != 0 && (sendamount= j64bits(item,"sendrel")) != 0 ) recvstr = base.buf, sendstr = rel.buf, recvasset = pend->order.s.baseid, sendasset = pend->order.s.relid; else if ( (recvamount= j64bits(item,"recvrel")) != 0 && (sendamount= j64bits(item,"sendbase")) != 0 ) recvstr = rel.buf, sendstr = base.buf, recvasset = pend->order.s.relid, sendasset = pend->order.s.baseid; else { return(clonestr("{\"error\":\"need recvbase/sendrel or recvrel/sendbase\"}\n")); } recvcoin = coin777_find(recvstr,1), sendcoin = coin777_find(sendstr,1); // placeask -> recvbase/sendrel, placebid -> sendbase/recvrel, it is relative to the one that placed quote if ( strcmp(recvstr,"NXT") != 0 ) // placeask COIN/NXT or placebid NXT/COIN { if ( recvamount < recvcoin->mgw.txfee ) { printf("recvamount %.8f < txfee %.8f\n",dstr(recvamount),dstr(recvcoin->mgw.txfee)); return(clonestr("{\"error\":\"amount too small\"}\n")); } sprintf(fieldA,"%spubA",recvstr), rpubA = jstr(walletitem,fieldA); sprintf(fieldB,"%spubB",recvstr), rpubB = jstr(walletitem,fieldB); sprintf(fieldpkhash,"%spkhash",recvstr), rpkhash = jstr(walletitem,fieldpkhash); if ( rpubA[0] != 0 && rpubB != 0 && rpkhash != 0 ) // Alice for recvcoin -> Bob, Bob sends NXT -> Alice { if ( recvcoin->funding.signedtransaction[0] == 0 && (refundtx= subatomic_fundingtx(refredeemscript,&recvcoin->funding,recvcoin,rpubA,rpubB,rpkhash,recvamount,finishin)) != 0 ) { deadline = 3600; gen_NXTtx(&recvcoin->trigger,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,pend->orderid,pend->order.s.quoteid,deadline,0,0,0,0); sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%llu\",\"fillNXT\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"wallet\",\"recvamount\":\"%lld\",\"rtx\":\"%s\",\"rs\":\"%s\",\"recvcoin\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"trigger\":\"%s\",\"sendasset\":\"%llu\",\"sendqty\":\"%llu\",\"base\":\"%s\",\"rel\":\"%s\"}",(long long)pend->orderid,(long long)pend->order.s.quoteid,(long long)pend->order.s.offerNXT,SUPERNET.NXTADDR,(long long)recvamount,refundtx,refredeemscript,recvstr,fieldA,rpubA,fieldB,rpubB,fieldpkhash,rpkhash,recvcoin->trigger.fullhash,(long long)sendasset,(long long)sendamount,pend->prices->base,pend->prices->rel); recvcoin->refundtx = refundtx; pend->order.s.swap = 1; if ( pend->dotrade != 0 && (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) { pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); } return(clonestr(swapbuf)); } else return(clonestr("{\"error\":\"cant create refundtx, maybe already pending\"}\n")); } else { sprintf(buf,"{\"error\":\"sendNXT recvstr.(%s) rpubA.(%s) without %s rpubB.%p or %s rpkhash.%p\"}\n",recvstr,rpubA,fieldB,rpubB,fieldpkhash,rpkhash); return(clonestr(buf)); } } else if ( strcmp(sendstr,"NXT") != 0 ) { if ( sendamount < sendcoin->mgw.txfee ) { printf("sendamount %.8f < txfee %.8f\n",dstr(sendamount),dstr(sendcoin->mgw.txfee)); return(clonestr("{\"error\":\"amount too small\"}\n")); } sprintf(fieldA,"%spubA",sendstr), spubA = jstr(walletitem,fieldA); sprintf(fieldB,"%spubB",sendstr), spubB = jstr(walletitem,fieldB); sprintf(fieldpkhash,"%spkhash",sendstr), spkhash = jstr(walletitem,fieldpkhash); if ( spubA != 0 && spubB != 0 && spkhash[0] != 0 ) // Bob <- sendcoin from Alice, send NXT -> Alice { if ( (redeemscript= create_atomictx_scripts(sendcoin->p2shtype,scriptPubKey,p2shaddr,spubA,spubB,spkhash)) != 0 ) { pend->triggertxid = prices777_swapbuf("yes",spkhash,&pend->txid,triggertx,txbytes,swapbuf,"wallet",pend->prices->base,pend->prices->rel,&pend->order,pend->orderid,finishin,0); sprintf(swapbuf+strlen(swapbuf)-1,",\"sendcoin\":\"%s\",\"sendamount\":\"%llu\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"recvasset\":\"%llu\",\"recvqty\":\"%llu\"}",sendstr,(long long)sendamount,fieldA,spubA,fieldB,spubB,fieldpkhash,spkhash,(long long)recvasset,(long long)recvamount); free(redeemscript); pend->order.s.swap = 1; if ( pend->dotrade != 0 && (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) { free(str); pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); } return(clonestr(swapbuf)); } } else { sprintf(buf,"{\"error\":\"recvNXT sendstr.(%s) spubA.(%s) without %s spubB.(%s) or %s spkhash.(%s)\"}\n",sendstr,spubA,fieldB,spubB,fieldpkhash,spkhash); return(clonestr(buf)); } } else if ( rpubA[0] != 0 && rpubB != 0 && rpkhash != 0 && spubA != 0 && spubB != 0 && spkhash[0] != 0 && (strcmp(sendstr,"BTC") == 0 || strcmp(recvstr,"BTC") == 0) ) { if ( recvcoin->funding.signedtransaction[0] == 0 && (refundtx= subatomic_fundingtx(refredeemscript,&recvcoin->funding,recvcoin,rpubA,rpubB,rpkhash,recvamount,finishin)) != 0 ) { if ( (redeemscript= create_atomictx_scripts(sendcoin->p2shtype,scriptPubKey,p2shaddr,spubA,spubB,spkhash)) != 0 ) { pend->triggertxid = prices777_swapbuf(0,0,&pend->txid,triggertx,txbytes,swapbuf,"wallet",pend->prices->base,pend->prices->rel,&pend->order,pend->orderid,finishin,0); sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%llu\",\"fillNXT\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"wallet\",\"sendcoin\":\"%s\",\"recvcoin\":\"%s\",\"sendamount\":\"%lld\",\"recvamount\":\"%lld\",\"base\":\"%s\",\"rel\":\"%s\"}",(long long)pend->orderid,(long long)pend->order.s.quoteid,(long long)pend->order.s.offerNXT,SUPERNET.NXTADDR,sendstr,recvstr,(long long)sendamount,(long long)recvamount,pend->prices->base,pend->prices->rel); sprintf(swapbuf+strlen(swapbuf)-1,",\"rtx\":\"%s\",\"rs\":\"%s\",\"rpubA\":\"%s\",\"rpubB\":\"%s\",\"rpkhash\":\"%s\",\"pubA\":\"%s\",\"pubB\":\"%s\",\"pkhash\":\"%s\"}",refundtx,refredeemscript,rpubA,rpubB,rpkhash,spubA,spubB,spkhash); free(redeemscript); free(refundtx); pend->order.s.swap = 1; if ( pend->dotrade != 0 && (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) { free(str); pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); } return(clonestr(swapbuf)); } free(refundtx); } else return(clonestr("{\"error\":\"cant create refundtx, maybe already pending\"}\n")); } else return(clonestr("{\"error\":\"one of wallets must be NXT or BTC\"}\n")); printf("wallet swap finishin.%d trigger.%llu swapbuf.(%s)\n",finishin,(long long)pend->triggertxid,swapbuf); return(prices777_finishswap(pend->dotrade,'A',pend,swapbuf,triggertx,txbytes)); } else return(clonestr("{\"error\":\"need to have trades[] json item\"}\n"));*/ } struct pending_trade *prices777_createpending(int32_t *curlingp,void *bot,void **cHandlep,int32_t dotrade,cJSON *item,char *activenxt,char *secret,struct prices777 *prices,int32_t dir,double price,double volume,struct InstantDEX_quote *iQ,struct prices777_order *order,uint64_t orderid,char *extra) { struct InstantDEX_quote _iQ; struct exchange_info *exchange; struct pending_trade *pend; char swapbuf[8192],triggertx[4096],txbytes[4096]; if ( (exchange= find_exchange(0,prices->exchange)) == 0 && exchange->issue.trade != 0 ) { printf("prices777_trade: need to have supported exchange\n"); return(0); } if ( cHandlep == 0 ) cHandlep = &exchange->cHandle; if ( iQ == 0 && order == 0 ) { printf("prices777_trade: need to have either iQ or order\n"); return(0); } else if ( iQ == 0 && (iQ= find_iQ(order->s.quoteid)) == 0 ) { iQ = &_iQ; memset(&_iQ,0,sizeof(_iQ)); iQ->s = order->s; iQ->exchangeid = prices->exchangeid; if ( iQ->s.timestamp == 0 ) iQ->s.timestamp = (uint32_t)time(NULL); iQ = create_iQ(iQ,0); } else iQ = create_iQ(iQ,0); pend = calloc(1,sizeof(*pend)); pend->bot = bot; safecopy((char *)pend->nxtsecret,secret,sizeof(pend->nxtsecret)); pend->size = (int32_t)sizeof(*pend); pend->my64bits = calc_nxt64bits(activenxt); triggertx[0] = txbytes[0] = swapbuf[0] = 0; pend->prices = prices, pend->dir = dir, pend->price = price, pend->volume = volume, pend->orderid = orderid; iQ->s.pending = 1; pend->curlingp = curlingp; pend->quoteid = iQ->s.quoteid; if ( order != 0 ) pend->order = *order; else pend->order.s = iQ->s; pend->timestamp = (uint32_t)time(NULL); pend->expiration = pend->timestamp + 60; pend->cHandlep = cHandlep; pend->dotrade = dotrade; pend->item = item; pend->exchange = exchange; safecopy(pend->extra,extra,sizeof(pend->extra)); return(pend); } char *prices777_issuepending(struct pending_trade *pend) { char swapbuf[8192],triggertx[4096],txbytes[4096],*retstr; struct prices777 *prices; struct exchange_info *exchange; if ( (prices= pend->prices) == 0 || (exchange= pend->exchange) == 0 ) retstr = clonestr("{\"error\":\"no prices ptr\"}"); else if ( strcmp(prices->exchange,"wallet") == 0 ) retstr = prices777_tradewallet(pend); else if ( strcmp(prices->exchange,INSTANTDEX_NAME) == 0 ) { pend->expiration = pend->timestamp + INSTANTDEX_TRIGGERDEADLINE*60; pend->triggertxid = prices777_swapbuf("yes",0,&pend->txid,triggertx,txbytes,swapbuf,prices->exchange,prices->base,prices->rel,&pend->order,pend->orderid,myatoi(pend->extra,10000),0); retstr = prices777_finishswap(pend->dotrade,'T',pend,swapbuf,triggertx,txbytes); } else if ( strcmp(prices->exchange,"nxtae") == 0 ) { pend->type = 'N'; retstr = fill_nxtae(pend->dotrade,&pend->txid,pend->my64bits,(char *)pend->nxtsecret,pend->dir,pend->price,pend->volume,prices->baseid,prices->relid); if ( pend->dotrade != 0 ) { pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); } } else { if ( exchange->issue.trade != 0 ) { printf(" issue dir.%d %s/%s price %f vol %f -> %s\n",pend->dir,prices->base,prices->rel,pend->price,pend->volume,prices->exchange); retstr = pend->extra; if ( pend->curlingp != 0 ) *pend->curlingp = 1; if ( (pend->txid= (*exchange->issue.trade)(pend->cHandlep,pend->dotrade,&retstr,exchange,prices->base,prices->rel,pend->dir,pend->price,pend->volume)) != 0 ) { pend->queueflag = 1; pend->finishtime = (uint32_t)time(NULL); } else printf("no txid from trade\n"); if ( pend->curlingp != 0 ) *pend->curlingp = 0; if ( retstr != 0 ) { if ( pend->dotrade != 0 ) { pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); } printf("returning.%p (%s)\n",retstr,retstr); } } else retstr = clonestr("{\"error\":\"no trade function for exchange\"}\n"); } if ( retstr == 0 ) retstr = clonestr("{\"error\":\"no response\"}"); return(retstr); } char *prices777_trade(int32_t *curlingp,void *bot,struct pending_trade **pendp,void **cHandlep,int32_t dotrade,cJSON *item,char *activenxt,char *secret,struct prices777 *prices,int32_t dir,double price,double volume,struct InstantDEX_quote *iQ,struct prices777_order *order,uint64_t orderid,char *extra) { struct pending_trade *pend; char *retstr; if ( pendp != 0 ) *pendp = 0; if ( (pend= prices777_createpending(curlingp,bot,cHandlep,dotrade,item,activenxt,secret,prices,dir,price,volume,iQ,order,orderid,extra)) != 0 ) { if ( bot == 0 || dotrade == 0 ) retstr = prices777_issuepending(pend); else if ( pend->queueflag != 0 ) retstr = clonestr("{\"result\":\"pending_trade created\"}"); else retstr = clonestr("{\"error\":\"pending_trade couldnt be created\"}"); if ( pend->queueflag == 0 ) free_pending(pend), pend = 0; else if ( pendp != 0 ) *pendp = pend; return(retstr); } else return(clonestr("{\"error\":\"couldnt createpending\"}")); } char *issue_calculateFullHash(char *unsignedtxbytes,char *sighash) { char cmd[4096]; sprintf(cmd,"requestType=calculateFullHash&unsignedTransactionBytes=%s&signatureHash=%s",unsignedtxbytes,sighash); return(issue_NXTPOST(cmd)); } char *issue_parseTransaction(char *txbytes) { char cmd[4096],*retstr = 0; sprintf(cmd,"requestType=parseTransaction&transactionBytes=%s",txbytes); retstr = issue_NXTPOST(cmd); //printf("issue_parseTransaction.%s %s\n",txbytes,retstr); if ( retstr != 0 ) { //printf("(%s) -> (%s)\n",cmd,retstr); //retstr = parse_NXTresults(0,"sender","",results_processor,jsonstr,strlen(jsonstr)); //free(jsonstr); } else printf("error getting txbytes.%s\n",txbytes); return(retstr); } uint64_t issue_broadcastTransaction(int32_t *errcodep,char **retstrp,char *txbytes,char *NXTACCTSECRET) { cJSON *json,*errjson; uint64_t txid = 0; char cmd[4096],secret[8192],*retstr; escape_code(secret,NXTACCTSECRET); sprintf(cmd,"requestType=broadcastTransaction&secretPhrase=%s&transactionBytes=%s",secret,txbytes); retstr = issue_NXTPOST(cmd); *errcodep = -1; if ( retstrp != 0 ) *retstrp = retstr; if ( retstr != 0 ) { //printf("(%s) -> (%s)\n",cmd,retstr); //printf("broadcast got.(%s)\n",retstr); if ( (json= cJSON_Parse(retstr)) != 0 ) { errjson = cJSON_GetObjectItem(json,"errorCode"); if ( errjson != 0 ) { //printf("ERROR broadcasting.(%s)\n",retstr); *errcodep = (int32_t)get_cJSON_int(json,"errorCode"); } else { if ( (txid = get_satoshi_obj(json,"transaction")) != 0 ) *errcodep = 0; } } if ( retstrp == 0 ) free(retstr); } return(txid); } char *issue_signTransaction(char *txbytes,char *NXTACCTSECRET) { char cmd[4096],secret[8192]; escape_code(secret,NXTACCTSECRET); sprintf(cmd,"requestType=signTransaction&secretPhrase=%s&unsignedTransactionBytes=%s",secret,txbytes); return(issue_NXTPOST(cmd)); } char *issue_approveTransaction(char *fullhash,char *revealed,char *message,char *NXTACCTSECRET) { char cmd[4096],secret[8192]; escape_code(secret,NXTACCTSECRET); sprintf(cmd,"requestType=approveTransaction&secretPhrase=%s&transactionFullHash=%s&revealedSecret=%s&messageIsText=true&feeNQT=%lld&deadline=%d&message=%s",secret,fullhash,revealed,(long long)MIN_NQTFEE,DEFAULT_NXT_DEADLINE,message); printf("submit approve.(%s)\n",cmd); return(issue_NXTPOST(cmd)); } uint32_t issue_getTime() { char cmd[4096],*jsonstr; cJSON *json; uint32_t timestamp = 0; //sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr); sprintf(cmd,"requestType=getTime"); if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) { if ( (json= cJSON_Parse(jsonstr)) != 0 ) timestamp = juint(json,"time"), free_json(json); free(jsonstr); } return(timestamp); } int32_t swap_verifyNXT(uint32_t *finishp,uint32_t *deadlinep,cJSON *origjson,char *offerNXT,char *exchangestr,uint64_t orderid,uint64_t quoteid,struct InstantDEX_quote *iQ,char *phasedtx) { char UTX[32768],*triggerhash,*utx,*sighash,*jsonstr=0,*parsed,*fullhash,*cmpstr; cJSON *json=0,*txobj,*attachment; int32_t retval = -1; uint64_t otherbits,otherqty,recvasset; struct destbuf calchash; int64_t recvqty; uint32_t i,j,timestamp,now,finishheight; *finishp = 0; if ( (triggerhash= jstr(origjson,"T")) == 0 ) triggerhash = jstr(origjson,"trigger"); otherbits = j64bits(origjson,"a"); otherqty = j64bits(origjson,"q"); fullhash = jstr(origjson,"FH"); finishheight = juint(origjson,"F"); if ( phasedtx == 0 ) { utx = jstr(origjson,"U"); if ( utx != 0 && strlen(utx) > sizeof(UTX) ) { printf("UTX overflow\n"); return(-1); } else if ( utx != 0 ) { for (i=0; utx[i]!=0; i++) if ( utx[i] == 'Z' ) { memcpy(UTX,utx,i); for (j=0; j<128; j++) UTX[i+j] = '0'; UTX[i+j] = 0; strcat(UTX,utx+i+1); break; } } sighash = jstr(origjson,"S"); if ( iQ->s.isask == 0 ) recvasset = iQ->s.baseid, recvqty = iQ->s.baseamount / get_assetmult(recvasset); else recvasset = iQ->s.relid, recvqty = iQ->s.relamount / get_assetmult(recvasset); printf("utx.(%s) -> UTX.(%s) sighash.(%s)\n",utx,UTX,sighash); } else { recvqty = otherqty; recvasset = otherbits; } if ( phasedtx != 0 || (jsonstr= issue_calculateFullHash(UTX,sighash)) != 0 ) { if ( phasedtx != 0 || (json= cJSON_Parse(jsonstr)) != 0 ) { copy_cJSON(&calchash,jobj(json,"fullHash")); if ( phasedtx != 0 || strcmp(calchash.buf,fullhash) == 0 ) { if ( (parsed= issue_parseTransaction(phasedtx != 0 ? phasedtx : UTX)) != 0 ) { _stripwhite(parsed,' '); //printf("iQ (%llu/%llu) otherbits.%llu qty %llu PARSED OFFER.(%s) triggerhash.(%s) (%s) offer sender.%s\n",(long long)iQ->s.baseid,(long long)iQ->s.relid,(long long)otherbits,(long long)otherqty,parsed,fullhash,calchash,sender); if ( (txobj= cJSON_Parse(parsed)) != 0 ) { *deadlinep = juint(txobj,"deadline"); timestamp = juint(txobj,"timestamp"); now = issue_getTime(); if ( (attachment= jobj(txobj,"attachment")) != 0 ) *finishp = juint(attachment,"phasingFinishHeight"); cmpstr = jstr(txobj,"referencedTransactionFullHash"); if ( *deadlinep >= INSTANTDEX_TRIGGERDEADLINE/2 && ((long)now - timestamp) < 60 && (cmpstr == 0 || triggerhash == 0 || (cmpstr != 0 && triggerhash != 0 && strcmp(cmpstr,triggerhash) == 0)) ) { // https://nxtforum.org/nrs-releases/nrs-v1-5-15/msg191715/#msg191715 printf("GEN RESPONDTX lag.%d deadline.%d (recv.%llu %lld) recv.(%llu %lld) orderid.%llu/%llx quoteid.%llu/%llx\n",now-timestamp,*deadlinep,(long long)recvasset,(long long)recvqty,(long long)recvasset,(long long)recvqty,(long long)orderid,(long long)orderid,(long long)quoteid,(long long)quoteid); if ( InstantDEX_verify(IGUANA_MY64BITS,recvasset,recvqty,txobj,recvasset,recvqty) == 0 ) retval = 0; else printf("(%s) didnt validate against quoteid.%llu\n",parsed,(long long)quoteid); } else fprintf(stderr,"swap rejects tx deadline %d >= INSTANTDEX_TRIGGERDEADLINE/2 && (now %d - %d timestamp) %d < 60\n",*deadlinep,now,timestamp,now-timestamp); free_json(txobj); } else fprintf(stderr,"swap cant parse tx.(%s)\n",parsed); free(parsed); } else fprintf(stderr,"swap cant parse UTX.(%s)\n",UTX); } else fprintf(stderr,"mismatch (%s) != (%s)\n",calchash.buf,fullhash); if ( json != 0 ) free_json(json); } else fprintf(stderr,"swap cant parse.(%s)\n",jsonstr); if ( jsonstr != 0 ) free(jsonstr); } else fprintf(stderr,"calchash.(%s)\n",jsonstr); return(retval); } struct pending_trade *pending_swap(char **strp,int32_t type,uint64_t orderid,uint64_t quoteid,char *triggerhash,char *fullhash,char *txstr,char *txstr2) { struct pending_trade *pend; cJSON *retjson; pend = calloc(1,sizeof(*pend)); pend->orderid = orderid, pend->quoteid = quoteid; if ( triggerhash != 0 ) pend->triggertx = clonestr(triggerhash); if ( fullhash != 0 ) pend->txbytes = clonestr(fullhash); pend->type = type; if ( txstr != 0 && txstr2 != 0 ) { retjson = cJSON_CreateObject(); jadd(retjson,"fee",cJSON_Parse(txstr)); jadd(retjson,"responsetx",cJSON_Parse(txstr2)); *strp = jprint(retjson,0); pend->tradesjson = retjson; } pend->timestamp = (uint32_t)time(NULL); return(pend); } char *swap_responseNXT(int32_t type,char *offerNXT,uint64_t otherbits,uint64_t otherqty,uint64_t orderid,uint64_t quoteid,int32_t deadline,char *triggerhash,char *phaselink,int32_t finishheight,struct InstantDEX_quote *iQ) { struct NXTtx fee,responsetx; int32_t errcode,errcode2; char *txstr,*txstr2,*str = 0; struct pending_trade *pend; gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,triggerhash,0,0,0); gen_NXTtx(&responsetx,calc_nxt64bits(offerNXT),otherbits,otherqty,orderid,quoteid,deadline,triggerhash,phaselink,finishheight,0); if ( (fee.txid= issue_broadcastTransaction(&errcode,&txstr,fee.txbytes,IGUANA_NXTACCTSECRET)) != 0 ) { if ( (responsetx.txid= issue_broadcastTransaction(&errcode2,&txstr2,responsetx.txbytes,IGUANA_NXTACCTSECRET)) != 0 ) { if ( (pend= pending_swap(&str,type,orderid,quoteid,triggerhash,phaselink,txstr,txstr2)) != 0 && str != 0 ) { iQ->s.pending = iQ->s.swap = 1; //InstantDEX_history(0,pend,str); pend->queueflag = 1; queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); printf("BROADCAST fee.txid %llu and %llu (%s %s)\n",(long long)fee.txid,(long long)responsetx.txid,fee.fullhash,responsetx.fullhash); } } else printf("error.%d broadcasting responsetx.(%s) %s\n",errcode2,responsetx.txbytes,txstr2); } else printf("error.%d broadcasting feetx.(%s) %s\n",errcode,fee.txbytes,txstr); if ( str == 0 ) str = clonestr("{\"error\":\"swap_responseNXT error responding\"}"); return(str); } int32_t extract_pkhash(char *pubkeystr,char *pkhash,char *script) { int32_t len; uint8_t rmd160[20],data[4096],*ptr; decode_hex(data,(int32_t)strlen(script)>>1,script); len = data[0]; ptr = &data[len + 1]; len = *ptr++; if ( len == 33 ) { init_hexbytes_noT(pubkeystr,ptr,33); calc_OP_HASH160(pkhash,rmd160,pubkeystr); printf("pkhash.(%s)\n",pkhash); return(0); } return(-1); } char *swap_func(int32_t localaccess,int32_t valid,char *sender,cJSON *origjson,char *origargstr) { /*char script[4096],hexstr[128],*str,*base,*rel,*txstr,*phasedtx,*cointxid,*signedtx,*jsonstr; uint8_t msgbuf[512]; struct pending_trade *pend; struct prices777_order order; struct InstantDEX_quote *iQ,_iQ; cJSON *json; uint32_t deadline,finishheight,nonce,isask; int32_t errcode,myoffer,myfill,len; struct NXTtx sendtx,fee; struct destbuf spendtxid,reftx; struct destbuf offerNXT,exchange; uint64_t otherbits,otherqty,quoteid,orderid,recvasset,recvqty,sendasset,sendqty,fillNXT,destbits,value; char pubkeystr[128],pkhash[64],swapbuf[4096],refredeemscript[1024],vintxid[128],*triggerhash,*fullhash,*dest,deststr[64];*/ struct destbuf offerNXT,exchange; uint32_t deadline,finishheight,isask; char *triggerhash,*fullhash; int32_t myoffer,myfill; struct InstantDEX_quote *iQ,_iQ; struct prices777_order order; uint64_t otherbits,otherqty,quoteid,orderid,fillNXT; copy_cJSON(&offerNXT,jobj(origjson,"offerNXT")); fillNXT = j64bits(origjson,"fillNXT"); copy_cJSON(&exchange,jobj(origjson,"exchange")); finishheight = juint(origjson,"F"); if ( (triggerhash= jstr(origjson,"T")) == 0 ) triggerhash = jstr(origjson,"trigger"); myoffer = strcmp(IGUANA_NXTADDR,offerNXT.buf) == 0; myfill = (IGUANA_MY64BITS == fillNXT); //printf("swap_func got (%s)\n",origargstr); if ( myoffer+myfill != 0 ) { orderid = j64bits(origjson,"orderid"); quoteid = j64bits(origjson,"quoteid"); if ( (iQ= find_iQ(quoteid)) == 0 ) { fprintf(stderr,"swap_func: cant find quoteid.%llu\n",(long long)quoteid); iQ = &_iQ, memset(iQ,0,sizeof(*iQ)); //return(clonestr("{\"error\":\"cant find quoteid\"}")); } if ( iQ->s.responded != 0 ) { fprintf(stderr,"already responded quoteid.%llu\n",(long long)iQ->s.quoteid); return(0); } isask = iQ->s.isask; memset(&order,0,sizeof(order)); order.s = iQ->s; #ifdef notyet if ( strcmp("wallet",exchange.buf) == 0 ) { uint64_t sendamount,recvamount; struct coin777 *recvcoin,*sendcoin; char refundsig[512],fieldA[64],fieldB[64],fieldpkhash[64]; char *recvstr,*sendstr,*spendtx,*refundtx,*redeemscript,*rpubA,*rpubB,*rpkhash,*spubA,*spubB,*spkhash; recvcoin = sendcoin = 0; sendamount = recvamount = 0; if ( (recvstr= jstr(origjson,"recvcoin")) != 0 ) recvcoin = coin777_find(recvstr,0); if ( (sendstr= jstr(origjson,"sendcoin")) != 0 ) sendcoin = coin777_find(sendstr,0); if ( iQ->s.baseid == NXT_ASSETID ) isask ^= 1; //printf("recvstr.%p sendstr.%p\n",recvstr,sendstr); if ( recvstr != 0 && sendstr != 0 ) { if ( (sendamount= j64bits(origjson,"sendamount")) != 0 && (recvamount= j64bits(origjson,"recvamount")) != 0 && sendcoin != 0 && recvcoin != 0 && (refundtx= jstr(origjson,"rtx")) != 0 && (redeemscript= jstr(origjson,"rs")) != 0 && (rpubA= jstr(origjson,"rpubA")) != 0 && (rpubB= jstr(origjson,"rpubB")) != 0 && (rpkhash= jstr(origjson,"rpkhash")) != 0 && triggerhash != 0 && (spubA= jstr(origjson,"spubA")) != 0 && (spubB= jstr(origjson,"spubB")) != 0 && (spkhash= jstr(origjson,"spkhash")) != 0 ) { } } else if ( recvstr != 0 ) { //printf("INCOMINGRECV.(%s)\n",origargstr); sprintf(fieldA,"%spubA",recvcoin->name); sprintf(fieldB,"%spubB",recvcoin->name); sprintf(fieldpkhash,"%spkhash",recvcoin->name); if ( (recvamount= j64bits(origjson,"recvamount")) != 0 && recvcoin != 0 && (rpubA= jstr(origjson,fieldA)) != 0 && (rpubB= jstr(origjson,fieldB)) != 0 && (rpkhash= jstr(origjson,fieldpkhash)) != 0 ) { if ( ((isask != 0 && myoffer != 0) || (isask == 0 && myfill != 0)) && j64bits(origjson,"fill") != IGUANA_MY64BITS && (refundtx= jstr(origjson,"rtx")) != 0 && (redeemscript= jstr(origjson,"rs")) != 0 ) // Bob: sends NXT to Alice, recvs recvcoin { subatomic_pubkeyhash(pubkeystr,pkhash,recvcoin,quoteid); //printf("CALC >>>>>>>>>> (%s) vs (%s)\n",pkhash,rpkhash); if ( (base= jstr(origjson,"base")) != 0 && (rel= jstr(origjson,"rel")) != 0 && (sendasset= j64bits(origjson,"sendasset")) != 0 && (sendqty= j64bits(origjson,"sendqty")) != 0 ) { //printf("inside (%s/%s) sendasset.%llu sendqty.%llu rpkhash.(%s)\n",base,rel,(long long)sendasset,(long long)sendqty,rpkhash); if ( (spendtx= subatomic_spendtx(&spendtxid,vintxid,refundsig,recvcoin,rpubA,rpubB,pubkeystr,recvamount,refundtx,redeemscript)) != 0 ) { finishheight = 60; deadline = 3600*4; if ( (pend= pending_swap(&str,'A',orderid,quoteid,0,0,0,0)) != 0 ) { if ( isask == 0 ) destbits = calc_nxt64bits(offerNXT.buf); else destbits = fillNXT; gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,triggerhash,0,0,0); issue_broadcastTransaction(&errcode,&txstr,fee.txbytes,IGUANA_NXTACCTSECRET); gen_NXTtx(&sendtx,destbits,sendasset,sendqty,orderid,quoteid,deadline,triggerhash,0,_get_NXTheight(0)+finishheight,rpkhash); //issue_broadcastTransaction(&errcode,&txstr,sendtx.txbytes,IGUANA_NXTACCTSECRET); printf(">>>>>>>>>>>> broadcast fee and phased.(%s) trigger.%s\n",sendtx.txbytes,triggerhash); sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%s\",\"fillNXT\":\"%llu\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"wallet\",\"recvcoin\":\"%s\",\"recvamount\":\"%lld\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"refundsig\":\"%s\",\"phasedtx\":\"%s\",\"spendtxid\":\"%s\",\"a\":\"%llu\",\"q\":\"%llu\",\"trigger\":\"%s\",\"fill\":\"%llu\"}",(long long)orderid,(long long)quoteid,offerNXT.buf,(long long)fillNXT,recvcoin->name,(long long)recvamount,fieldA,rpubA,fieldB,rpubB,fieldpkhash,rpkhash,refundsig,sendtx.txbytes,spendtxid.buf,(long long)sendasset,(long long)sendqty,triggerhash,(long long)IGUANA_MY64BITS); if ( (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) free(str); // poll for vin then broadcast spendtx printf(">>>>>>>>>>>>>>>>>>>> wait for (%s) then send SPENDTX.(%s)\n",vintxid,spendtx); if ( (value= wait_for_txid(script,recvcoin,vintxid,0,recvamount,recvcoin->minconfirms,0)) != 0 ) { signedtx = malloc(strlen(spendtx) + 16); sprintf(signedtx,"[\"%s\"]",spendtx); if ( (cointxid= bitcoind_passthru(recvcoin->name,recvcoin->serverport,recvcoin->userpass,"sendrawtransaction",signedtx)) != 0 ) { printf(">>>>>>>>>>>>> BROADCAST SPENDTX.(%s) (%s)\n",signedtx,cointxid); free(cointxid); } free(signedtx); } printf("ATOMIC SWAP.%llu finished\n",(long long)quoteid); iQ->s.closed = 1; delete_iQ(quoteid); } else printf("cant get pending_swap pend.%p\n",pend); free(spendtx); return(clonestr(swapbuf)); } else printf("error generating spendtx\n"); } else printf("mismatched recv (%s vs %s) or (%s)\n",recvcoin->atomicrecvpubkey,rpubB,rpkhash); } else if ( j64bits(origjson,"fill") != IGUANA_MY64BITS && (str= jstr(origjson,"refundsig")) != 0 && str[0] != 0 && (phasedtx= jstr(origjson,"phasedtx")) != 0 && phasedtx[0] != 0 ) // Alice to verify NXTtx and send recvcoin { if ( isask != 0 ) dest = offerNXT.buf; else { expand_nxt64bits(deststr,fillNXT); dest = deststr; } if ( swap_verifyNXT(&finishheight,&deadline,origjson,dest,exchange.buf,orderid,quoteid,iQ,phasedtx) == 0 ) { if ( recvcoin->refundtx != 0 && (recvcoin->signedrefund= subatomic_validate(recvcoin,rpubA,rpubB,rpkhash,recvcoin->refundtx,str)) != 0 ) { free(recvcoin->refundtx), recvcoin->refundtx = 0; issue_broadcastTransaction(&errcode,&txstr,recvcoin->trigger.txbytes,IGUANA_NXTACCTSECRET); issue_broadcastTransaction(&errcode,&txstr,phasedtx,IGUANA_NXTACCTSECRET); printf(">>>>>>>>>>>>>>>>>>>>>>>>>>> ISSUE TRIGGER.(%s) phased.(%s).%d | signedrefund.(%s)\n",recvcoin->trigger.txbytes,txstr!=0?txstr:"phasedsubmit error",errcode,recvcoin->signedrefund); signedtx = malloc(strlen(recvcoin->funding.signedtransaction) + 16); sprintf(signedtx,"[\"%s\"]",recvcoin->funding.signedtransaction); if ( (cointxid= bitcoind_passthru(recvcoin->name,recvcoin->serverport,recvcoin->userpass,"sendrawtransaction",signedtx)) != 0 ) { printf(">>>>>>>>>>>>> FUNDING BROADCAST.(%s) (%s)\n",recvcoin->funding.signedtransaction,cointxid); free(cointxid); } else printf("error sendrawtransaction.(%s)\n",recvcoin->funding.signedtransaction); free(signedtx); copy_cJSON(&spendtxid,jobj(origjson,"spendtxid")); printf("wait for spendtx.(%s)\n",spendtxid.buf); if ( (value= wait_for_txid(script,recvcoin,spendtxid.buf,0,recvamount-recvcoin->mgw.txfee,0,0)) != 0 ) { iQ->s.responded = 1; if ( extract_pkhash(pubkeystr,pkhash,script) == 0 ) { if ( strcmp(pkhash,rpkhash) == 0 ) { reftx.buf[0] = 0; if ( (jsonstr= issue_parseTransaction(phasedtx)) != 0 ) { if ( (json= cJSON_Parse(jsonstr)) != 0 ) { copy_cJSON(&reftx,jobj(json,"fullHash")); free_json(json); } free(jsonstr); } len = 0; len = txind777_txbuf(msgbuf,len,orderid,sizeof(orderid)); len = txind777_txbuf(msgbuf,len,quoteid,sizeof(quoteid)); init_hexbytes_noT(hexstr,msgbuf,len); if ( (str= issue_approveTransaction(reftx.buf,pubkeystr,hexstr,IGUANA_NXTACCTSECRET)) != 0 ) { printf("fullhash.(%s) pubkey.(%s) pkhash.(%s) APPROVED.(%s)\n",reftx.buf,pubkeystr,pkhash,str); free(str); } else printf("error sending in approval\n"); } else printf("script.(%s) -> pkhash.(%s) vs rpkhash.(%s)\n",script,pkhash,rpkhash); } else printf("unexpected end of script.(%s) (%s)\n",script,str); } printf("FINISHED ATOMIC SWAP of quoteid.%llu\n",(long long)quoteid); iQ->s.closed = 1; memset(&recvcoin->trigger,0,sizeof(recvcoin->trigger)); memset(&recvcoin->funding,0,sizeof(recvcoin->funding)); free(recvcoin->signedrefund), recvcoin->signedrefund = 0; delete_iQ(quoteid); } else printf("refund tx didnt verify\n"); } else printf("NXT tx didnt verify\n"); } //else printf("myfill.%d myoffer.%d recv mismatch isask.%d\n",myfill,myoffer,iQ->s.isask); //printf("recv failed\n"); return(clonestr("{\"result\":\"recv failed\"}")); } } else if ( sendstr != 0 ) // Alice sendcoin -> Bob, recvs NXT { //printf("INCOMINGSEND.(%s)\n",origargstr); sprintf(fieldA,"%spubA",sendcoin->name); sprintf(fieldB,"%spubB",sendcoin->name); sprintf(fieldpkhash,"%spkhash",sendcoin->name); if ( ((isask == 0 && myoffer != 0) || (isask != 0 && myfill != 0)) && (sendamount= j64bits(origjson,"sendamount")) != 0 && sendcoin != 0 && triggerhash != 0 && (spubA= jstr(origjson,fieldA)) != 0 && (spubB= jstr(origjson,fieldB)) != 0 && (spkhash= jstr(origjson,fieldpkhash)) != 0 ) { if ( (base= jstr(origjson,"base")) != 0 && (rel= jstr(origjson,"rel")) != 0 && (recvasset= j64bits(origjson,"recvasset")) != 0 && (recvqty= j64bits(origjson,"recvqty")) != 0 ) { if ( sendcoin->funding.signedtransaction[0] == 0 && (refundtx= subatomic_fundingtx(refredeemscript,&sendcoin->funding,sendcoin,spubA,spubB,spkhash,sendamount,10)) != 0 ) { deadline = 3600; gen_NXTtx(&sendcoin->trigger,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,0,0,0,0); sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%s\",\"fillNXT\":\"%llu\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"%s\",\"recvamount\":\"%lld\",\"rtx\":\"%s\",\"rs\":\"%s\",\"recvcoin\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"trigger\":\"%s\",\"sendasset\":\"%llu\",\"sendqty\":\"%llu\",\"base\":\"%s\",\"rel\":\"%s\",\"fill\":\"%llu\"}",(long long)orderid,(long long)quoteid,offerNXT.buf,(long long)fillNXT,exchange.buf,(long long)sendamount,refundtx,refredeemscript,sendstr,fieldA,spubA,fieldB,spubB,fieldpkhash,spkhash,sendcoin->trigger.fullhash,(long long)recvasset,(long long)recvqty,base,rel,(long long)IGUANA_MY64BITS); sendcoin->refundtx = refundtx; if ( (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) free(str); return(clonestr(swapbuf)); //printf("BUSDATA.(%s)\n",swapbuf); } else return(clonestr("{\"error\":\"cant create refundtx, maybe already pending\"}\n")); } //else printf("mismatched send (%s vs %s) or (%s)\n",sendcoin->atomicrecvpubkey,spubB,spkhash); } else printf("myfill.%d myoffer.%d send mismatch isask.%d\n",myfill,myoffer,iQ->s.isask); } return(clonestr("{\"result\":\"processed wallet swap\"}")); } #endif if ( myoffer != 0 && swap_verifyNXT(&finishheight,&deadline,origjson,offerNXT.buf,exchange.buf,orderid,quoteid,iQ,0) == 0 ) { otherbits = j64bits(origjson,"a"); otherqty = j64bits(origjson,"q"); fullhash = jstr(origjson,"FH"); finishheight = juint(origjson,"F"); return(swap_responseNXT('R',offerNXT.buf,otherbits,otherqty,orderid,quoteid,deadline,triggerhash,fullhash,finishheight,iQ)); } else printf("myfill.%d myoffer.%d swap mismatch\n",myfill,myoffer); } return(clonestr("{\"result\":\"processed swap\"}")); } int32_t match_unconfirmed(char *sender,char *hexstr,cJSON *txobj,char *txidstr,char *account,uint64_t amount,uint64_t qty,uint64_t assetid,char *recipient) { // ok, the bug here is that on a delayed respondtx, the originator should refuse to release the trigger (and the money tx) uint64_t orderid,quoteid,recvasset,sendasset; int64_t recvqty,sendqty; uint32_t bidask,deadline,timestamp,now; struct InstantDEX_quote *iQ; decode_hex((void *)&orderid,sizeof(orderid),hexstr); decode_hex((void *)"eid,sizeof(quoteid),hexstr+16); //printf("match_unconfirmed.(%s) orderid.%llu %llx quoteid.%llu %llx\n",hexstr,(long long)orderid,(long long)orderid,(long long)quoteid,(long long)quoteid); deadline = juint(txobj,"deadline"); timestamp = juint(txobj,"timestamp"); now = issue_getTime(); //printf("deadline.%u now.%u timestamp.%u lag %ld\n",deadline,now,timestamp,((long)now - timestamp)); if ( deadline < INSTANTDEX_TRIGGERDEADLINE/2 || ((long)now - timestamp) > 60*2 ) return(0); if ( (iQ= find_iQ(quoteid)) != 0 && iQ->s.closed == 0 && iQ->s.pending != 0 && (iQ->s.responded == 0 || iQ->s.feepaid == 0) ) { if ( Debuglevel > 2 ) printf("match unconfirmed %llu/%llu %p swap.%d feepaid.%d responded.%d sender.(%s) -> recv.(%s) me.(%s) offer.(%llu)\n",(long long)orderid,(long long)quoteid,iQ,iQ->s.swap,iQ->s.feepaid,iQ->s.responded,sender,recipient,IGUANA_NXTADDR,(long long)iQ->s.offerNXT); if ( iQ->s.swap != 0 && (strcmp(recipient,INSTANTDEX_ACCT) == 0 || strcmp(recipient,IGUANA_NXTADDR) == 0) ) { if ( iQ->s.feepaid == 0 ) { if ( verify_NXTtx(txobj,NXT_ASSETID,INSTANTDEX_FEE,calc_nxt64bits(INSTANTDEX_ACCT)) == 0 ) { iQ->s.feepaid = 1; printf("FEE DETECTED\n"); } else printf("notfee: dest.%s src.%s amount.%llu qty.%llu assetid.%llu\n",recipient,sender,(long long)amount,(long long)qty,(long long)assetid); } if ( iQ->s.responded == 0 ) { bidask = iQ->s.isask; if ( iQ->s.offerNXT == IGUANA_MY64BITS ) bidask ^= 1; if ( bidask != 0 ) { sendasset = iQ->s.relid, sendqty = iQ->s.relamount; recvasset = iQ->s.baseid, recvqty = iQ->s.baseamount; } else { sendasset = iQ->s.baseid, sendqty = iQ->s.baseamount; recvasset = iQ->s.relid, recvqty = iQ->s.relamount; } sendqty /= get_assetmult(sendasset); recvqty /= get_assetmult(recvasset); if ( Debuglevel > 2 ) printf("sendasset.%llu sendqty.%llu mult.%llu, recvasset.%llu recvqty.%llu mult.%llu\n",(long long)sendasset,(long long)sendqty,(long long)get_assetmult(sendasset),(long long)recvasset,(long long)recvqty,(long long)get_assetmult(recvasset)); if ( InstantDEX_verify(IGUANA_MY64BITS,sendasset,sendqty,txobj,recvasset,recvqty) == 0 ) { iQ->s.responded = 1; printf("iQ: %llu/%llu %lld/%lld | recv %llu %lld offerNXT.%llu\n",(long long)iQ->s.baseid,(long long)iQ->s.relid,(long long)iQ->s.baseamount,(long long)iQ->s.relamount,(long long)recvasset,(long long)recvqty,(long long)iQ->s.offerNXT); printf("RESPONSE DETECTED\n"); } } if ( iQ->s.responded != 0 && iQ->s.feepaid != 0 ) { printf("both detected offer.%llu my64bits.%llu\n",(long long)iQ->s.offerNXT,(long long)IGUANA_MY64BITS); complete_swap(iQ,orderid,quoteid,iQ->s.offerNXT == IGUANA_MY64BITS); } } } return(-1); } int32_t is_unfunded_order(uint64_t nxt64bits,uint64_t assetid,uint64_t amount) { char assetidstr[64],NXTaddr[64],cmd[1024],*jsonstr; int64_t ap_mult,unconfirmed,balance = 0; cJSON *json; expand_nxt64bits(NXTaddr,nxt64bits); if ( assetid == NXT_ASSETID ) { sprintf(cmd,"requestType=getAccount&account=%s",NXTaddr); if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) { if ( (json= cJSON_Parse(jsonstr)) != 0 ) { balance = get_API_nxt64bits(cJSON_GetObjectItem(json,"balanceNQT")); free_json(json); } free(jsonstr); } strcpy(assetidstr,"NXT"); } else { expand_nxt64bits(assetidstr,assetid); if ( (ap_mult= assetmult(assetidstr)) != 0 ) { expand_nxt64bits(NXTaddr,nxt64bits); balance = ap_mult * get_asset_quantity(&unconfirmed,NXTaddr,assetidstr); } } if ( balance < amount ) { printf("balance %.8f < amount %.8f for asset.%s\n",dstr(balance),dstr(amount),assetidstr); return(1); } return(0); } cJSON *InstantDEX_tradejson(int32_t *curlingp,void *bot,struct pending_trade **pendp,void **cHandlep,cJSON *item,char *activenxt,char *secret,struct prices777_order *order,int32_t dotrade,uint64_t orderid,char *extra) { char swapbuf[8192],buf[8192],triggertx[4096],txbytes[4096],*retstr,*exchange; uint64_t txid,qty,avail,priceNQT; struct prices777 *prices; cJSON *json = 0; if ( pendp != 0 ) *pendp = 0; if ( (prices= order->source) != 0 ) { exchange = prices->exchange; swapbuf[0] = 0; if ( dotrade == 0 ) { if ( strcmp(exchange,INSTANTDEX_NAME) != 0 && strcmp(exchange,"wallet") != 0 ) { sprintf(buf,"{\"orderid\":\"%llu\",\"trade\":\"%s\",\"exchange\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\",\"baseid\":\"%llu\",\"relid\":\"%llu\",\"price\":%.8f,\"volume\":%.8f,\"extra\":\"%s\"}",(long long)orderid,order->wt > 0. ? "buy" : "sell",exchange,prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,order->s.price,order->s.vol,extra!=0?extra:""); if ( strcmp(exchange,"nxtae") == 0 ) { qty = calc_asset_qty(&avail,&priceNQT,activenxt,0,prices->baseid,order->s.price,order->s.vol); sprintf(buf+strlen(buf)-1,",\"priceNQT\":\"%llu\",\"quantityQNT\":\"%llu\",\"avail\":\"%llu\"}",(long long)priceNQT,(long long)qty,(long long)avail); if ( qty == 0 ) sprintf(buf+strlen(buf)-1,",\"error\":\"insufficient balance\"}"); } return(cJSON_Parse(buf)); } else { //{"inverted":0,"contract":"MMNXT/Jay","baseid":"979292558519844732","relid":"8688289798928624137","bids":[{"plugin":"Inst // antDEX","method":"tradesequence","dotrade":1,"price":2,"volume":2,"trades":[]}],"asks":[],"numbids":1,"numasks":0,"lastb // id":2,"lastask":0,"NXT":"11471677413693100042","timestamp":1440587058,"maxdepth":25} prices777_swapbuf("yes",0,&txid,triggertx,txbytes,swapbuf,prices->exchange,prices->base,prices->rel,order,orderid,extra==0?0:myatoi(extra,10000),0); return(cJSON_Parse(swapbuf)); } } retstr = prices777_trade(curlingp,bot,pendp,cHandlep,dotrade,item,activenxt,secret,prices,order->wt,order->s.price,order->s.vol,0,order,orderid,extra); if ( retstr != 0 ) { json = cJSON_Parse(retstr); free(retstr); } } return(json); } char *InstantDEX_dotrades(int32_t curlings[],void *bot,void *cHandles[],char *activenxt,char *secret,cJSON *json,struct prices777_order *trades,int32_t numtrades,int32_t dotrade,char *extra) { struct destbuf exchangestr,gui,name,base,rel; struct InstantDEX_quote iQ; cJSON *retjson,*retarray; int32_t i; bidask_parse(1,&exchangestr,&name,&base,&rel,&gui,&iQ,json); retjson = cJSON_CreateObject(), retarray = cJSON_CreateArray(); for (i=0; i maxtrades ) return(clonestr("{\"error\":\"exceeded max trades possible in a tradesequence\"}")); if ( n == 1 && is_cJSON_Array(jitem(array,0)) != 0 ) { //printf("NESTED ARRAY DETECTED\n"); array = jitem(array,0); n = cJSON_GetArraySize(array); } *nump = n; timestamp = (uint32_t)time(NULL); for (i=0; iid = orderid, order->s.quoteid = quoteid; assetid = j64bits(item,"asset"), currency = j64bits(item,"currency"); baseid = j64bits(item,"baseid"), relid = j64bits(item,"relid"); sendbase = j64bits(item,"sendbase"), recvbase = j64bits(item,"recvbase"); sendrel = j64bits(item,"sendrel"), recvrel = j64bits(item,"recvrel"); order->s.baseamount = (recvbase - sendbase); order->s.relamount = (recvrel - sendrel); orderprice = jdouble(item,"orderprice"), ordervolume = jdouble(item,"ordervolume"); order->s.timestamp = juint(item,"timestamp"); order->s.duration = juint(item,"duration"); order->s.minperc = juint(item,"minperc"); order->s.baseid = baseid; order->s.relid = relid; //printf("ITEM.(%s)\n",jprint(item,0)); if ( tradestr != 0 ) { if ( strcmp(tradestr,"buy") == 0 ) dir = 1; else if ( strcmp(tradestr,"sell") == 0 ) dir = -1; else if ( strcmp(tradestr,"swap") == 0 ) dir = 0; else return(clonestr("{\"error\":\"invalid trade direction\"}")); if ( (prices= prices777_initpair(1,exchangestr,base.buf,rel.buf,0.,name.buf,baseid,relid,0)) != 0 ) { order->source = prices; order->s.offerNXT = j64bits(item,"offerNXT"); order->wt = dir, order->s.price = orderprice, order->s.vol = ordervolume; printf("item[%d] dir.%d (price %.8f vol %.4f) %s/%s baseid.%llu relid.%llu sendbase.%llu recvbase.%llu sendrel.%llu recvrel.%llu | baseqty.%lld relqty.%lld\n",i,dir,order->s.price,order->s.vol,prices->base,prices->rel,(long long)order->s.baseid,(long long)order->s.relid,(long long)sendbase,(long long)recvbase,(long long)sendrel,(long long)recvrel,(long long)order->s.baseamount,(long long)order->s.relamount); } else return(clonestr("{\"error\":\"invalid exchange or contract pair\"}")); } else { printf("item.(%s)\n",jprint(item,0)); return(clonestr("{\"error\":\"no trade specified\"}")); } } return(InstantDEX_dotrades(curlings,bot,cHandles,activenxt,secret,json,trades,n,dotrade,jstr(json,"extra"))); } printf("error parsing.(%s)\n",jprint(json,0)); return(clonestr("{\"error\":\"couldnt process trades\"}")); } #endif