You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1583 lines
84 KiB
1583 lines
84 KiB
/******************************************************************************
|
|
* 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<n; i++)
|
|
{
|
|
item = cJSON_GetArrayItem(array,i);
|
|
src64bits = get_API_nxt64bits(cJSON_GetObjectItem(item,"NXT"));
|
|
srcamount = get_API_nxt64bits(cJSON_GetObjectItem(item,"amountA"));
|
|
srcasset = get_API_nxt64bits(cJSON_GetObjectItem(item,"assetA"));
|
|
dest64bits = get_API_nxt64bits(cJSON_GetObjectItem(item,"other"));
|
|
destamount = get_API_nxt64bits(cJSON_GetObjectItem(item,"amountB"));
|
|
destasset = get_API_nxt64bits(cJSON_GetObjectItem(item,"assetB"));
|
|
jump64bits = get_API_nxt64bits(cJSON_GetObjectItem(item,"jumper"));
|
|
jumpamount = get_API_nxt64bits(cJSON_GetObjectItem(item,"jumpasset"));
|
|
jumpasset = get_API_nxt64bits(cJSON_GetObjectItem(item,"jumpamount"));
|
|
balancing = (long)get_API_nxt64bits(cJSON_GetObjectItem(item,"balancing"));
|
|
if ( src64bits != 0 && srcamount != 0 && srcasset != 0 && dest64bits != 0 && destamount != 0 && destasset != 0 )
|
|
{
|
|
if ( src64bits == mynxt64bits )
|
|
hist = update_tradehistory(hist,srcasset,srcamount,destasset,destamount);
|
|
else if ( dest64bits == mynxt64bits )
|
|
hist = update_tradehistory(hist,destasset,destamount,srcasset,srcamount);
|
|
else if ( jump64bits == mynxt64bits )
|
|
continue;
|
|
else printf("illegal tabulate_trade_entry %llu: (%llu -> %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<n; i++)
|
|
{
|
|
txobj = cJSON_GetArrayItem(array,i);
|
|
copy_cJSON(&receiverstr,cJSON_GetObjectItem(txobj,"recipient"));
|
|
if ( (senderbits = get_API_nxt64bits(cJSON_GetObjectItem(txobj,"sender"))) != 0 )
|
|
{
|
|
expand_nxt64bits(NXTaddr,senderbits);
|
|
if ( refNXTaddr != 0 && strcmp(NXTaddr,refNXTaddr) == 0 )
|
|
{
|
|
if ( (attachment= cJSON_GetObjectItem(txobj,"attachment")) != 0 && (msgobj= cJSON_GetObjectItem(attachment,"message")) != 0 )
|
|
{
|
|
copy_cJSON(&message,msgobj);
|
|
//printf("(%s) -> ",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; j<m; j++)
|
|
{
|
|
copy_cJSON(&triggerhash,cJSON_GetObjectItem(cJSON_GetArrayItem(histarray,j),"triggerhash"));
|
|
if ( strcmp(triggerhash.buf,newtriggerhash.buf) == 0 )
|
|
{
|
|
duplicates++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( j == m )
|
|
cJSON_AddItemToArray(histarray,msgobj);
|
|
} else printf("parse error on.(%s)\n",message.buf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(jsonstr);
|
|
}
|
|
if ( histarray != 0 )
|
|
retjson = tabulate_trade_history(calc_nxt64bits(refNXTaddr),histarray);
|
|
printf("duplicates.%d\n",duplicates);
|
|
return(retjson);
|
|
}
|
|
|
|
void free_pending(struct pending_trade *pend)
|
|
{
|
|
struct InstantDEX_quote *iQ;
|
|
if ( (iQ= find_iQ(pend->quoteid)) != 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; i<endi; i++)
|
|
{
|
|
if ( (pend= InstantDEX_historyi(&action,&str,i,txbuf,sizeof(txbuf))) != 0 )
|
|
{
|
|
printf("type.%d (%c) action.%d orderid.%llu quoteid.%llu (%s)\n",pend->type,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<numtrades; i++)
|
|
{
|
|
//printf("GOT%d.(%s)\n",i,jprint(json,0));
|
|
if ( trades[i].retitem != 0 )
|
|
free_json(trades[i].retitem );
|
|
trades[i].retitem = InstantDEX_tradejson(curlings!=0?&curlings[i]:0,bot,&trades[i].pend,cHandles!=0?cHandles[i]:0,jobj(json,"trades"),activenxt,secret,&trades[i],dotrade,iQ.s.quoteid,extra);
|
|
jaddi(retarray,trades[i].retitem);
|
|
}
|
|
jadd(retjson,"traderesults",retarray);
|
|
return(jprint(retjson,0));
|
|
}
|
|
|
|
char *InstantDEX_tradesequence(int32_t curlings[],void *bot,void *cHandles[],int32_t *nump,struct prices777_order *trades,int32_t maxtrades,int32_t dotrade,char *activenxt,char *secret,cJSON *json)
|
|
{
|
|
//"trades":[[{"basket":"bid","rootwt":-1,"groupwt":1,"wt":-1,"price":40000,"volume":0.00015000,"group":0,"trade":"buy","exchange":"nxtae","asset":"17554243582654188572","base":"BTC","rel":"NXT","orderid":"3545444239044461477","orderprice":40000,"ordervolume":0.00015000}], [{"basket":"bid","rootwt":-1,"groupwt":1,"wt":1,"price":0.00376903,"volume":1297.41480000,"group":10,"trade":"sell","exchange":"coinbase","name":"BTC/USD","base":"BTC","rel":"USD","orderid":"1","orderprice":265.32000000,"ordervolume":4.89000000}]]}
|
|
cJSON *array,*item; int32_t i,n,dir; char *tradestr,*exchangestr; struct prices777_order *order;
|
|
uint64_t orderid,assetid,currency,baseid,relid,quoteid; int64_t sendbase,recvbase,sendrel,recvrel; struct destbuf base,rel,name;
|
|
double orderprice,ordervolume; struct prices777 *prices; uint32_t timestamp;
|
|
if ( (array= jarray(&n,json,"trades")) != 0 )
|
|
{
|
|
if ( n > 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; i<n; i++)
|
|
{
|
|
order = &trades[i];
|
|
memset(order,0,sizeof(*order));
|
|
item = jitem(array,i);
|
|
tradestr = jstr(item,"trade"), exchangestr = jstr(item,"exchange");
|
|
copy_cJSON(&base,jobj(item,"base")), copy_cJSON(&rel,jobj(item,"rel")), copy_cJSON(&name,jobj(item,"name"));
|
|
orderid = j64bits(item,"orderid"), quoteid = j64bits(item,"quoteid");
|
|
if ( orderid == 0 )
|
|
orderid = quoteid;
|
|
if ( quoteid == 0 )
|
|
quoteid = orderid;
|
|
order->id = 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
|
|
|