|
|
|
/******************************************************************************
|
|
|
|
* Copyright © 2014-2016 The SuperNET Developers. *
|
|
|
|
* *
|
|
|
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
|
|
|
* the top-level directory of this distribution for the individual copyright *
|
|
|
|
* holder information and the developer policies on copyright and licensing. *
|
|
|
|
* *
|
|
|
|
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
|
|
|
* SuperNET software, including this file may be copied, modified, propagated *
|
|
|
|
* or distributed except according to the terms contained in the LICENSE file *
|
|
|
|
* *
|
|
|
|
* Removal or modification of this copyright notice is prohibited. *
|
|
|
|
* *
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include "exchanges777.h"
|
|
|
|
//#include "peggy.h"
|
|
|
|
|
|
|
|
#define EXCHANGE777_DONE 1
|
|
|
|
#define EXCHANGE777_ISPENDING 2
|
|
|
|
#define EXCHANGE777_REQUEUE 3
|
|
|
|
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
//char *Exchange_names[] = { "poloniex", "bittrex", "btc38", "huobi", "bitstamp", "bitfinex", "btce", "coinbase", "okcoin", "lakebtc", "quadriga", "truefx", "ecb", "instaforex", "fxcm", "yahoo" };
|
|
|
|
|
|
|
|
int32_t instantdex_updatesources(struct exchange_info *exchange,struct exchange_quote *sortbuf,int32_t n,int32_t max,int32_t ind,int32_t dir,struct exchange_quote *quotes,int32_t numquotes)
|
|
|
|
{
|
|
|
|
int32_t i; struct exchange_quote *quote;
|
|
|
|
//printf("instantdex_updatesources.%s update dir.%d numquotes.%d\n",exchange->name,dir,numquotes);
|
|
|
|
for (i=0; i<numquotes; i++)
|
|
|
|
{
|
|
|
|
quote = "es[i << 1];
|
|
|
|
//printf("n.%d ind.%d i.%d dir.%d price %.8f vol %.8f\n",n,ind,i,dir,quote->price,quote->volume);
|
|
|
|
if ( quote->price > SMALLVAL )
|
|
|
|
{
|
|
|
|
sortbuf[n] = *quote;
|
|
|
|
sortbuf[n].val = ind;
|
|
|
|
sortbuf[n].exchangebits = exchange->exchangebits;
|
|
|
|
//printf("sortbuf[%d] <-\n",n*2);
|
|
|
|
if ( ++n >= max )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
double instantdex_aveprice(struct supernet_info *myinfo,struct exchange_quote *sortbuf,int32_t max,double *totalvolp,char *base,char *rel,double basevolume,cJSON *argjson)
|
|
|
|
{
|
|
|
|
char *str; double totalvol,pricesum; uint32_t timestamp;
|
|
|
|
struct exchange_quote quote; int32_t i,n,dir,num,depth = 100;
|
|
|
|
struct exchange_info *exchange; struct exchange_request *req,*active[64];
|
|
|
|
if ( myinfo == 0 )
|
|
|
|
myinfo = SuperNET_MYINFO(0);
|
|
|
|
timestamp = (uint32_t)time(NULL);
|
|
|
|
if ( basevolume < 0. )
|
|
|
|
basevolume = -basevolume, dir = -1;
|
|
|
|
else dir = 1;
|
|
|
|
#ifdef INCLUDE_PAX
|
|
|
|
if ( rel == 0 || rel[0] == 0 )
|
|
|
|
{
|
|
|
|
*totalvolp = 1.;
|
|
|
|
return(PAX_aveprice(myinfo,base));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
memset(sortbuf,0,sizeof(*sortbuf) * max);
|
|
|
|
if ( base != 0 && rel != 0 && basevolume > SMALLVAL )
|
|
|
|
{
|
|
|
|
for (i=num=0; i<myinfo->numexchanges && num < sizeof(active)/sizeof(*active); i++)
|
|
|
|
{
|
|
|
|
if ( (exchange= myinfo->tradingexchanges[i]) != 0 )
|
|
|
|
{
|
|
|
|
if ( (req= exchanges777_baserelfind(exchange,base,rel,'M')) == 0 )
|
|
|
|
{
|
|
|
|
if ( (str= exchanges777_Qprices(exchange,base,rel,30,1,depth,argjson,1,exchange->commission)) != 0 )
|
|
|
|
free(str);
|
|
|
|
req = exchanges777_baserelfind(exchange,base,rel,'M');
|
|
|
|
}
|
|
|
|
if ( req == 0 )
|
|
|
|
{
|
|
|
|
if ( (*exchange->issue.supports)(exchange,base,rel,argjson) != 0 )
|
|
|
|
printf("unexpected null req.(%s %s) %s\n",base,rel,exchange->name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//printf("active.%s\n",exchange->name);
|
|
|
|
active[num++] = req;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i=n=0; i<num; i++)
|
|
|
|
{
|
|
|
|
if ( dir < 0 && active[i]->numbids > 0 )
|
|
|
|
n = instantdex_updatesources(active[i]->exchange,sortbuf,n,max,i,1,active[i]->bidasks,active[i]->numbids);
|
|
|
|
else if ( dir > 0 && active[i]->numasks > 0 )
|
|
|
|
n = instantdex_updatesources(active[i]->exchange,sortbuf,n,max,i,-1,&active[i]->bidasks[1],active[i]->numasks);
|
|
|
|
}
|
|
|
|
//printf("numexchanges.%d dir.%d %s/%s numX.%d n.%d\n",myinfo->numexchanges,dir,base,rel,num,n);
|
|
|
|
if ( dir < 0 )
|
|
|
|
revsort64s(&sortbuf[0].satoshis,n,sizeof(*sortbuf));
|
|
|
|
else sort64s(&sortbuf[0].satoshis,n,sizeof(*sortbuf));
|
|
|
|
for (totalvol=pricesum=i=0; i<n && totalvol < basevolume; i++)
|
|
|
|
{
|
|
|
|
quote = sortbuf[i];
|
|
|
|
//printf("n.%d i.%d price %.8f %.8f %.8f\n",n,i,dstr(sortbuf[i].satoshis),sortbuf[i].price,quote.volume);
|
|
|
|
if ( quote.satoshis != 0 )
|
|
|
|
{
|
|
|
|
pricesum += (quote.price * quote.volume);
|
|
|
|
totalvol += quote.volume;
|
|
|
|
//printf("i.%d of %d %12.8f vol %.8f %s | aveprice %.8f total vol %.8f\n",i,n,sortbuf[i].price,quote.volume,active[quote.val]->exchange->name,pricesum/totalvol,totalvol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( totalvol > 0. )
|
|
|
|
{
|
|
|
|
*totalvolp = totalvol;
|
|
|
|
return(pricesum / totalvol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*totalvolp = 0;
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
double instantdex_avehbla(struct supernet_info *myinfo,double retvals[4],char *_base,char *_rel,double basevolume)
|
|
|
|
{
|
|
|
|
double avebid,aveask,bidvol,askvol; struct exchange_quote sortbuf[2560]; cJSON *argjson; char base[64],rel[64];
|
|
|
|
if ( retvals == 0 )
|
|
|
|
return(0);
|
|
|
|
strcpy(base,_base);
|
|
|
|
if ( _rel == 0 )
|
|
|
|
strcpy(rel,"");
|
|
|
|
else strcpy(rel,_rel);
|
|
|
|
if ( myinfo == 0 )
|
|
|
|
myinfo = SuperNET_MYINFO(0);
|
|
|
|
argjson = cJSON_CreateObject();
|
|
|
|
aveask = instantdex_aveprice(myinfo,sortbuf,sizeof(sortbuf)/(4*sizeof(*sortbuf)),&askvol,base,rel,basevolume,argjson);
|
|
|
|
avebid = instantdex_aveprice(myinfo,sortbuf,sizeof(sortbuf)/(4*sizeof(*sortbuf)),&bidvol,base,rel,-basevolume,argjson);
|
|
|
|
free_json(argjson);
|
|
|
|
retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol;
|
|
|
|
#ifdef INCLUDE_PAX
|
|
|
|
int32_t basenum,relnum; double baseval,relval;
|
|
|
|
if ( (basenum= PAX_basenum(base)) >= 0 && (relnum= PAX_basenum(rel)) >= 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->PEGS != 0 && (baseval= myinfo->PEGS->data.RTmatrix[basenum][basenum]) != 0. && (relval= myinfo->PEGS->data.RTmatrix[relnum][relnum]) != 0. )
|
|
|
|
return(baseval / relval);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if ( avebid > SMALLVAL && aveask > SMALLVAL )
|
|
|
|
return((avebid + aveask) * .5);
|
|
|
|
else return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void prices777_processprice(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cJSON *exchanges777_allpairs(char *baserels[][2],int32_t num)
|
|
|
|
{
|
|
|
|
int32_t i; char str[32]; cJSON *json,*item,*array = cJSON_CreateArray();
|
|
|
|
for (i=0; i<num; i++)
|
|
|
|
{
|
|
|
|
item = cJSON_CreateArray();
|
|
|
|
jaddistr(item,uppercase_str(str,baserels[i][0]));
|
|
|
|
jaddistr(item,uppercase_str(str,baserels[i][1]));
|
|
|
|
jaddi(array,item);
|
|
|
|
}
|
|
|
|
json = cJSON_CreateObject();
|
|
|
|
jadd(json,"result",array);
|
|
|
|
return(json);
|
|
|
|
}
|
|
|
|
|
|
|
|
cJSON *exchanges777_quotejson(struct exchange_quote *quote,int32_t allflag,double pricesum,double totalvol)
|
|
|
|
{
|
|
|
|
cJSON *json; char str[65];
|
|
|
|
if ( allflag != 0 )
|
|
|
|
{
|
|
|
|
json = cJSON_CreateObject();
|
|
|
|
if ( totalvol > SMALLVAL )
|
|
|
|
pricesum /= totalvol;
|
|
|
|
jaddnum(json,"price",quote->price);
|
|
|
|
jaddnum(json,"volume",quote->volume);
|
|
|
|
jaddnum(json,"aveprice",pricesum);
|
|
|
|
jaddnum(json,"cumulative",totalvol);
|
|
|
|
if ( quote->timestamp != 0 )
|
|
|
|
jaddstr(json,"time",utc_str(str,quote->timestamp));
|
|
|
|
if ( quote->orderid != 0 )
|
|
|
|
jadd64bits(json,"orderid",quote->orderid);
|
|
|
|
//if ( quote->offerNXT != 0 )
|
|
|
|
jadd64bits(json,"account",quote->offerNXT);
|
|
|
|
return(json);
|
|
|
|
} else return(cJSON_CreateNumber(quote->price));
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_orderbook_jsonstr(struct exchange_info *exchange,char *_base,char *_rel,struct exchange_quote *bidasks,int32_t maxdepth,int32_t invert,int32_t allflag)
|
|
|
|
{
|
|
|
|
struct exchange_quote *bid,*ask,A,B; cJSON *json,*bids,*asks;
|
|
|
|
double highbid,lowask,price,volume,bidsum,asksum,bidvol,askvol;
|
|
|
|
uint32_t timestamp;
|
|
|
|
int32_t slot,numbids,numasks,enda,endb; char baserel[64],base[64],rel[64],str[65];
|
|
|
|
if ( invert == 0 )
|
|
|
|
{
|
|
|
|
strcpy(base,_base), strcpy(rel,_rel);
|
|
|
|
sprintf(baserel,"%s/%s",base,rel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(base,_rel), strcpy(rel,_base);
|
|
|
|
sprintf(baserel,"%s/%s",rel,base);
|
|
|
|
}
|
|
|
|
json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray();
|
|
|
|
highbid = lowask = 0.;
|
|
|
|
bidsum = asksum = bidvol = askvol = 0.;
|
|
|
|
for (slot=numbids=numasks=enda=endb=0; slot<maxdepth && enda+endb!=2; slot++)
|
|
|
|
{
|
|
|
|
bid = &bidasks[slot << 1], ask = &bidasks[(slot << 1) + 1];
|
|
|
|
if ( endb == 0 && (price= bid->price) > SMALLVAL )
|
|
|
|
{
|
|
|
|
volume = bid->volume;
|
|
|
|
if ( invert == 0 )
|
|
|
|
{
|
|
|
|
bidsum += (price * volume), bidvol += volume;
|
|
|
|
//printf("bid %f %f vol %f, cumulative %f %f\n",bid->price,price,volume,bidsum/bidvol,bidvol);
|
|
|
|
jaddi(bids,exchanges777_quotejson(bid,allflag,bidsum,bidvol));
|
|
|
|
if ( numbids++ == 0 )
|
|
|
|
highbid = price;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
volume *= price;
|
|
|
|
price = 1. / price;
|
|
|
|
A = *bid;
|
|
|
|
A.price = price, A.volume = volume;
|
|
|
|
asksum += (price * volume), askvol += volume;
|
|
|
|
jaddi(asks,exchanges777_quotejson(&A,allflag,asksum,askvol));
|
|
|
|
if ( numasks++ == 0 )
|
|
|
|
lowask = price;
|
|
|
|
}
|
|
|
|
} else endb = 1;
|
|
|
|
if ( enda == 0 && (price= ask->price) > SMALLVAL )
|
|
|
|
{
|
|
|
|
volume = ask->volume;
|
|
|
|
if ( invert == 0 )
|
|
|
|
{
|
|
|
|
asksum += (price * volume), askvol += volume;
|
|
|
|
jaddi(asks,exchanges777_quotejson(ask,allflag,asksum,askvol));
|
|
|
|
if ( numasks++ == 0 )
|
|
|
|
lowask = price;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
volume *= price;
|
|
|
|
price = 1. / price;
|
|
|
|
B = *ask;
|
|
|
|
B.price = price, B.volume = volume;
|
|
|
|
bidsum += (price * volume), bidvol += volume;
|
|
|
|
jaddi(bids,exchanges777_quotejson(&B,allflag,bidsum,bidvol));
|
|
|
|
if ( numbids++ == 0 )
|
|
|
|
highbid = price;
|
|
|
|
}
|
|
|
|
} else enda = 1;
|
|
|
|
}
|
|
|
|
jaddstr(json,"exchange",exchange->name);
|
|
|
|
jaddnum(json,"inverted",invert);
|
|
|
|
jaddstr(json,"base",base);
|
|
|
|
if ( rel[0] != 0 )
|
|
|
|
jaddstr(json,"rel",rel);
|
|
|
|
jadd(json,"bids",bids);
|
|
|
|
jadd(json,"asks",asks);
|
|
|
|
if ( invert == 0 )
|
|
|
|
{
|
|
|
|
jaddnum(json,"numbids",numbids);
|
|
|
|
jaddnum(json,"numasks",numasks);
|
|
|
|
if ( highbid > SMALLVAL )
|
|
|
|
jaddnum(json,"highbid",highbid);
|
|
|
|
if ( lowask > SMALLVAL )
|
|
|
|
jaddnum(json,"lowask",lowask);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
jaddnum(json,"numbids",numasks);
|
|
|
|
jaddnum(json,"numasks",numbids);
|
|
|
|
if ( lowask > SMALLVAL )
|
|
|
|
jaddnum(json,"highbid",1. / lowask);
|
|
|
|
if ( highbid > SMALLVAL )
|
|
|
|
jaddnum(json,"lowask",1. / highbid);
|
|
|
|
}
|
|
|
|
timestamp = (uint32_t)time(NULL);
|
|
|
|
jaddnum(json,"timestamp",timestamp);
|
|
|
|
jaddstr(json,"time",utc_str(str,timestamp));
|
|
|
|
jaddnum(json,"maxdepth",maxdepth);
|
|
|
|
return(jprint(json,1));
|
|
|
|
}
|
|
|
|
|
|
|
|
double exchange_setquote(struct exchange_quote *bidasks,int32_t *numbidsp,int32_t *numasksp,int32_t bidask,int32_t invert,double price,double volume,double commission,uint64_t orderid,uint32_t timestamp,uint64_t offerNXT)
|
|
|
|
{
|
|
|
|
int32_t slot_ba; struct exchange_quote *quote;
|
|
|
|
if ( price > SMALLVAL && volume > SMALLVAL )
|
|
|
|
{
|
|
|
|
if ( invert != 0 )
|
|
|
|
{
|
|
|
|
bidask = (1 ^ bidask);
|
|
|
|
volume *= price;
|
|
|
|
price = 1. / price;
|
|
|
|
}
|
|
|
|
if ( commission != 0. )
|
|
|
|
{
|
|
|
|
//printf("price %f fee %f -> ",price,prices->commission * price);
|
|
|
|
if ( bidask == 0 )
|
|
|
|
price -= commission * price;
|
|
|
|
else price += commission * price;
|
|
|
|
//printf("%f\n",price);
|
|
|
|
}
|
|
|
|
quote = (bidask == 0) ? &bidasks[(*numbidsp)<<1] : &bidasks[((*numasksp)<<1) + 1];
|
|
|
|
quote->price = price, quote->volume = volume, quote->timestamp = timestamp, quote->orderid = orderid, quote->offerNXT = offerNXT;
|
|
|
|
if ( bidask == 0 )
|
|
|
|
slot_ba = ((*numbidsp)++ << 1);
|
|
|
|
else slot_ba = ((*numasksp)++ << 1) | 1;
|
|
|
|
quote->satoshis = (price * SATOSHIDEN);
|
|
|
|
}
|
|
|
|
return(price);
|
|
|
|
}
|
|
|
|
|
|
|
|
void exchanges777_json_quotes(struct exchange_info *exchange,double commission,char *base,char *rel,double *lastbidp,double *lastaskp,double *hblap,struct exchange_quote *bidasks,cJSON *bids,cJSON *asks,int32_t maxdepth,char *pricefield,char *volfield,uint32_t reftimestamp,int32_t invert)
|
|
|
|
{
|
|
|
|
int32_t i,slot,n=0,m=0,dir,bidask,numitems,numbids,numasks; uint64_t orderid,offerNXT;
|
|
|
|
cJSON *item; uint32_t timestamp; double price,volume,hbla = 0.;
|
|
|
|
*lastbidp = *lastaskp = 0.;
|
|
|
|
numbids = numasks = 0;
|
|
|
|
if ( reftimestamp == 0 )
|
|
|
|
reftimestamp = (uint32_t)time(NULL);
|
|
|
|
if ( bids != 0 )
|
|
|
|
{
|
|
|
|
n = cJSON_GetArraySize(bids);
|
|
|
|
if ( maxdepth != 0 && n > maxdepth )
|
|
|
|
n = maxdepth;
|
|
|
|
}
|
|
|
|
if ( asks != 0 )
|
|
|
|
{
|
|
|
|
m = cJSON_GetArraySize(asks);
|
|
|
|
if ( maxdepth != 0 && m > maxdepth )
|
|
|
|
m = maxdepth;
|
|
|
|
}
|
|
|
|
for (i=0; i<n || i<m; i++)
|
|
|
|
{
|
|
|
|
for (bidask=0; bidask<2; bidask++)
|
|
|
|
{
|
|
|
|
offerNXT = orderid = 0;
|
|
|
|
price = volume = 0.;
|
|
|
|
dir = (bidask == 0) ? 1 : -1;
|
|
|
|
if ( bidask == 0 && i >= n )
|
|
|
|
continue;
|
|
|
|
else if ( bidask == 1 && i >= m )
|
|
|
|
continue;
|
|
|
|
//if ( strcmp(prices->exchange,"bter") == 0 && dir < 0 )
|
|
|
|
// slot = ((bidask==0?n:m) - 1) - i;
|
|
|
|
//else
|
|
|
|
slot = i;
|
|
|
|
timestamp = 0;
|
|
|
|
item = jitem(bidask==0?bids:asks,slot);
|
|
|
|
if ( pricefield != 0 && volfield != 0 )
|
|
|
|
price = jdouble(item,pricefield), volume = jdouble(item,volfield);
|
|
|
|
else if ( is_cJSON_Array(item) != 0 && (numitems= cJSON_GetArraySize(item)) != 0 ) // big assumptions about order within nested array!
|
|
|
|
{
|
|
|
|
price = jdouble(jitem(item,0),0), volume = jdouble(jitem(item,1),0);
|
|
|
|
if ( strcmp(exchange->name,"kraken") == 0 )
|
|
|
|
timestamp = juint(jitem(item,2),0);
|
|
|
|
else orderid = j64bits(jitem(item,2),0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
price = jdouble(item,"price");
|
|
|
|
volume = jdouble(item,"volume");
|
|
|
|
timestamp = juint(item,"timestamp");
|
|
|
|
orderid = j64bits(item,"orderid");
|
|
|
|
offerNXT = j64bits(item,"account");
|
|
|
|
}
|
|
|
|
if ( price == 0. || volume == 0. )
|
|
|
|
continue;
|
|
|
|
if ( price > SMALLVAL && volume > SMALLVAL )
|
|
|
|
{
|
|
|
|
price = exchange_setquote(bidasks,&numbids,&numasks,bidask,invert,price,volume,commission,orderid,timestamp,offerNXT);
|
|
|
|
if ( i == 0 )
|
|
|
|
{
|
|
|
|
if ( (bidask ^ invert) == 0 )
|
|
|
|
*lastbidp = price;
|
|
|
|
else *lastaskp = price;
|
|
|
|
if ( hbla == 0. )
|
|
|
|
hbla = price;
|
|
|
|
else hbla = 0.5 * (hbla + price);
|
|
|
|
}
|
|
|
|
//printf("%d,%d: %-8s %s %5s/%-5s %13.8f vol %13.8f | i %13.8f vol %13.8f | t.%u\n",numbids,numasks,exchange->name,dir>0?"bid":"ask",base,rel,price,volume,1./price,volume*price,timestamp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( hbla != 0. )
|
|
|
|
*hblap = hbla;
|
|
|
|
}
|
|
|
|
|
|
|
|
double exchanges777_json_orderbook(struct exchange_info *exchange,double commission,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth,cJSON *json,char *resultfield,char *bidfield,char *askfield,char *pricefield,char *volfield,int32_t invert)
|
|
|
|
{
|
|
|
|
cJSON *obj = 0,*bidobj=0,*askobj=0; double lastbid,lastask,hbla = 0.; int32_t numasks=0,numbids=0;
|
|
|
|
if ( resultfield == 0 )
|
|
|
|
obj = json;
|
|
|
|
if ( maxdepth == 0 )
|
|
|
|
maxdepth = EXCHANGES777_MAXDEPTH;
|
|
|
|
if ( resultfield == 0 || (obj= jobj(json,resultfield)) != 0 )
|
|
|
|
{
|
|
|
|
bidobj = jarray(&numbids,obj,bidfield);
|
|
|
|
askobj = jarray(&numasks,obj,askfield);
|
|
|
|
if ( bidobj != 0 || askobj != 0 )
|
|
|
|
{
|
|
|
|
exchanges777_json_quotes(exchange,commission,base,rel,&lastbid,&lastask,&hbla,bidasks,bidobj,askobj,maxdepth,pricefield,volfield,0,invert);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(hbla);
|
|
|
|
}
|
|
|
|
|
|
|
|
double exchanges777_standardprices(struct exchange_info *exchange,double commission,char *base,char *rel,char *url,struct exchange_quote *quotes,char *price,char *volume,int32_t maxdepth,char *field,int32_t invert)
|
|
|
|
{
|
|
|
|
char *jsonstr; cJSON *json; double hbla = 0.;
|
|
|
|
if ( (jsonstr= issue_curl(url)) != 0 )
|
|
|
|
{
|
|
|
|
//if ( strcmp(exchangestr,"btc38") == 0 )
|
|
|
|
//printf("(%s) -> (%s)\n",url,jsonstr);
|
|
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
|
|
{
|
|
|
|
hbla = exchanges777_json_orderbook(exchange,commission,base,rel,quotes,maxdepth,json,field,"bids","asks",price,volume,invert);
|
|
|
|
free_json(json);
|
|
|
|
}
|
|
|
|
free(jsonstr);
|
|
|
|
}
|
|
|
|
return(hbla);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchange_would_submit(char *postreq,char *hdr1,char *hdr2,char *hdr3, char *hdr4)
|
|
|
|
{
|
|
|
|
char *data; cJSON *json;
|
|
|
|
json = cJSON_CreateObject();
|
|
|
|
jaddstr(json,"post",postreq);
|
|
|
|
if ( hdr1[0] != 0 )
|
|
|
|
jaddstr(json,"hdr1",hdr1);
|
|
|
|
if ( hdr2[0] != 0 )
|
|
|
|
jaddstr(json,"hdr2",hdr2);
|
|
|
|
if ( hdr3[0] != 0 )
|
|
|
|
jaddstr(json,"hdr3",hdr3);
|
|
|
|
if ( hdr4[0] != 0 )
|
|
|
|
jaddstr(json,"hdr4",hdr4);
|
|
|
|
data = jprint(json,1);
|
|
|
|
json = 0;
|
|
|
|
return(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t exchange_nonce(struct exchange_info *exchange)
|
|
|
|
{
|
|
|
|
uint64_t nonce;
|
|
|
|
nonce = time(NULL);
|
|
|
|
if ( nonce < exchange->lastnonce )
|
|
|
|
nonce = exchange->lastnonce + 1;
|
|
|
|
exchange->lastnonce = nonce;
|
|
|
|
return(nonce);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t flip_for_exchange(char *pairstr,char *fmt,char *refstr,int32_t dir,double *pricep,double *volumep,char *base,char *rel)
|
|
|
|
{
|
|
|
|
if ( strcmp(rel,refstr) == 0 )
|
|
|
|
sprintf(pairstr,fmt,rel,base);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( strcmp(base,refstr) == 0 )
|
|
|
|
{
|
|
|
|
sprintf(pairstr,fmt,base,rel);
|
|
|
|
dir = -dir;
|
|
|
|
*volumep *= *pricep;
|
|
|
|
*pricep = (1. / *pricep);
|
|
|
|
}
|
|
|
|
else sprintf(pairstr,fmt,rel,base);
|
|
|
|
}
|
|
|
|
return(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t flipstr_for_exchange(struct exchange_info *exchange,char *pairstr,char *fmt,int32_t dir,double *pricep,double *volumep,char *_base,char *_rel,cJSON *argjson)
|
|
|
|
{
|
|
|
|
int32_t polarity; char base[64],rel[64];
|
|
|
|
strcpy(base,_base), strcpy(rel,_rel);
|
|
|
|
tolowercase(base), tolowercase(rel);
|
|
|
|
polarity = (*exchange->issue.supports)(exchange,base,rel,argjson);
|
|
|
|
if ( dir > 0 )
|
|
|
|
sprintf(pairstr,fmt,base,rel);
|
|
|
|
else if ( dir < 0 )
|
|
|
|
{
|
|
|
|
*volumep *= *pricep;
|
|
|
|
*pricep = (1. / *pricep);
|
|
|
|
sprintf(pairstr,fmt,rel,base);
|
|
|
|
}
|
|
|
|
return(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t cny_flip(char *market,char *coinname,char *base,char *rel,int32_t dir,double *pricep,double *volumep)
|
|
|
|
{
|
|
|
|
char pairstr[512],lbase[32],lrel[32],*refstr=0;
|
|
|
|
strcpy(lbase,base), tolowercase(lbase), strcpy(lrel,rel), tolowercase(lrel);
|
|
|
|
if ( strcmp(lbase,"cny") == 0 || strcmp(lrel,"cny") == 0 )
|
|
|
|
{
|
|
|
|
dir = flip_for_exchange(pairstr,"%s_%s","cny",dir,pricep,volumep,lbase,lrel);
|
|
|
|
refstr = "cny";
|
|
|
|
}
|
|
|
|
else if ( strcmp(lbase,"btc") == 0 || strcmp(lrel,"btc") == 0 )
|
|
|
|
{
|
|
|
|
dir = flip_for_exchange(pairstr,"%s_%s","btc",dir,pricep,volumep,lbase,lrel);
|
|
|
|
refstr = "btc";
|
|
|
|
}
|
|
|
|
if ( market != 0 && coinname != 0 && refstr != 0 )
|
|
|
|
{
|
|
|
|
strcpy(market,refstr);
|
|
|
|
if ( strcmp(lbase,"refstr") != 0 )
|
|
|
|
strcpy(coinname,lbase);
|
|
|
|
else strcpy(coinname,lrel);
|
|
|
|
touppercase(coinname);
|
|
|
|
}
|
|
|
|
return(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchange_extractorderid(int32_t historyflag,char *status,uint64_t quoteid,char *quoteid_field)
|
|
|
|
{
|
|
|
|
cJSON *array,*item,*json; int32_t i,n; uint64_t txid;
|
|
|
|
if ( status != 0 )
|
|
|
|
{
|
|
|
|
if ( (array= cJSON_Parse(status)) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
|
|
|
|
{
|
|
|
|
for (i=0; i<n; i++)
|
|
|
|
{
|
|
|
|
item = jitem(array,i);
|
|
|
|
if ( (txid= juint(item,quoteid_field)) == quoteid )
|
|
|
|
{
|
|
|
|
json = cJSON_CreateObject();
|
|
|
|
jaddstr(json,"result",historyflag == 0 ? "order still pending" : "order completed");
|
|
|
|
jadd(json,"order",cJSON_Duplicate(item,1));
|
|
|
|
free_json(array);
|
|
|
|
return(jprint(json,1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( array != 0 )
|
|
|
|
free_json(array);
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t baserel_polarity(char *pairs[][2],int32_t n,char *_base,char *_rel)
|
|
|
|
{
|
|
|
|
int32_t i; char base[32],rel[32],cmpbase[32],cmprel[32];
|
|
|
|
strcpy(base,_base), tolowercase(base);
|
|
|
|
strcpy(rel,_rel), tolowercase(rel);
|
|
|
|
for (i=0; i<n; i++)
|
|
|
|
{
|
|
|
|
strcpy(cmpbase,pairs[i][0]), tolowercase(cmpbase);
|
|
|
|
strcpy(cmprel,pairs[i][1]), tolowercase(cmprel);
|
|
|
|
if ( strcmp(cmpbase,base) == 0 && strcmp(cmprel,rel) == 0 )
|
|
|
|
return(1);
|
|
|
|
else if ( strcmp(cmpbase,rel) == 0 && strcmp(cmprel,base) == 0 )
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
//printf("%s cant find.(%s/%s) [%s/%s].%d\n",exchange->name,base,rel,pairs[0][0],pairs[0][1],n);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// following includes C code directly
|
|
|
|
#include "exchanges/poloniex.c"
|
|
|
|
#include "exchanges/bittrex.c"
|
|
|
|
#include "exchanges/btce.c"
|
|
|
|
#include "exchanges/bitfinex.c"
|
|
|
|
#include "exchanges/btc38.c"
|
|
|
|
#include "exchanges/huobi.c"
|
|
|
|
#include "exchanges/lakebtc.c"
|
|
|
|
#include "exchanges/quadriga.c"
|
|
|
|
#include "exchanges/okcoin.c"
|
|
|
|
#include "exchanges/coinbase.c"
|
|
|
|
#include "exchanges/bitstamp.c"
|
|
|
|
|
|
|
|
#include "exchanges/truefx.c"
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
#include "exchanges/PAX.c"
|
|
|
|
#include "exchanges/fxcm.c"
|
|
|
|
#include "exchanges/instaforex.c"
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
|
|
|
|
#include "exchanges/jumblr.c"
|
|
|
|
#include "exchanges/bitcoin.c"
|
|
|
|
#include "exchanges/nxtae.c"
|
|
|
|
#include "exchanges/unconf.c"
|
|
|
|
|
|
|
|
struct exchange_funcs *Exchange_funcs[] =
|
|
|
|
{
|
|
|
|
&truefx_funcs, &instaforex_funcs, &fxcm_funcs, // prices only
|
|
|
|
&PAX_funcs, &nxtae_funcs, &bitcoin_funcs, &jumblr_funcs, // special
|
|
|
|
&bitfinex_funcs, &huobi_funcs, &lakebtc_funcs, &quadriga_funcs, &okcoin_funcs, // BTC exchanges
|
|
|
|
&poloniex_funcs, &bittrex_funcs, &btce_funcs, &btc38_funcs, // altcoin exchanges
|
|
|
|
&coinbase_funcs, &bitstamp_funcs // authentication not working yet
|
|
|
|
};
|
|
|
|
|
|
|
|
struct exchange_info *Exchanges[sizeof(Exchange_funcs)/sizeof(*Exchange_funcs)];
|
|
|
|
|
|
|
|
int32_t exchanges777_orient(struct exchange_info *exchange,char *base,char *rel,double *pricep,double *volumep,struct exchange_request *req)
|
|
|
|
{
|
|
|
|
int32_t polarity = 1;
|
|
|
|
if ( exchange->issue.supports != 0 )
|
|
|
|
polarity = (*exchange->issue.supports)(exchange,req->base,req->rel,req->argjson);
|
|
|
|
if ( polarity < 0 )
|
|
|
|
{
|
|
|
|
strcpy(base,req->rel);
|
|
|
|
strcpy(rel,req->base);
|
|
|
|
if ( volumep != 0 )
|
|
|
|
*volumep = (req->price * req->volume);
|
|
|
|
if ( pricep != 0 && req->price != 0 )
|
|
|
|
*pricep = 1. / req->price;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(rel,req->rel);
|
|
|
|
strcpy(base,req->base);
|
|
|
|
if ( pricep != 0 )
|
|
|
|
*pricep = req->price;
|
|
|
|
if ( volumep != 0 )
|
|
|
|
*volumep = req->volume;
|
|
|
|
}
|
|
|
|
touppercase(base), touppercase(rel);
|
|
|
|
return(polarity);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_process(struct exchange_info *exchange,int32_t *retvalp,struct exchange_request *req)
|
|
|
|
{
|
|
|
|
char base[32],rel[32],*retstr = 0; int32_t polarity; uint64_t orderid; double price,volume,balance; cJSON *balancejson,*retjson;
|
|
|
|
*retvalp = EXCHANGE777_DONE;
|
|
|
|
switch ( req->func )
|
|
|
|
{
|
|
|
|
case 'Q': case 'M':
|
|
|
|
if ( exchange->issue.price != 0 )
|
|
|
|
{
|
|
|
|
memset(req->bidasks,0,req->depth * sizeof(*req->bidasks) * 2);
|
|
|
|
if ( (polarity= exchanges777_orient(exchange,base,rel,0,0,req)) <= 0 )
|
|
|
|
retstr = clonestr("{\"error\":\"invalid polarity\"}");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//printf("polarity.%d %s %s req.(%s %s)\n",polarity,base,rel,req->base,req->rel);
|
|
|
|
(*exchange->issue.price)(exchange,req->base,req->rel,req->bidasks,req->depth,req->commission,req->argjson,req->invert);
|
|
|
|
retstr = exchanges777_orderbook_jsonstr(exchange,base,rel,req->bidasks,req->depth,0,req->allflag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
if ( exchange->issue.supports != 0 )
|
|
|
|
{
|
|
|
|
polarity = (*exchange->issue.supports)(exchange,req->base,req->rel,req->argjson);
|
|
|
|
retjson = cJSON_CreateObject();
|
|
|
|
jaddnum(retjson,"result",polarity);
|
|
|
|
retstr = jprint(retjson,1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
if ( exchange->issue.trade != 0 )
|
|
|
|
{
|
|
|
|
polarity = exchanges777_orient(exchange,base,rel,&price,&volume,req);
|
|
|
|
orderid = (*exchange->issue.trade)(req->dotrade,&retstr,exchange,base,rel,polarity * req->dir,price,volume,req->argjson);
|
|
|
|
if ( retstr == 0 )
|
|
|
|
{
|
|
|
|
req->orderid = orderid;
|
|
|
|
retstr = (*exchange->issue.orderstatus)(exchange,req->orderid,req->argjson);
|
|
|
|
/*retjson = cJSON_CreateObject();
|
|
|
|
if ( orderid != 0 )
|
|
|
|
jadd64bits(retjson,"result",orderid);
|
|
|
|
else jaddstr(retjson,"error","no return value from trade call");
|
|
|
|
retstr = jprint(retjson,1);*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
if ( exchange->issue.balances != 0 )
|
|
|
|
{
|
|
|
|
if ( (balancejson= (*exchange->issue.balances)(exchange,req->argjson)) != 0 )
|
|
|
|
{
|
|
|
|
//printf("BALANCE.(%s)\n",jprint(balancejson,0));
|
|
|
|
if ( req->base[0] != 0 && exchange->issue.parsebalance != 0 )
|
|
|
|
retstr = (*exchange->issue.parsebalance)(exchange,&balance,req->base,balancejson);
|
|
|
|
else retstr = jprint(balancejson,0);
|
|
|
|
free_json(balancejson);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
if ( exchange->issue.orderstatus != 0 )
|
|
|
|
retstr = (*exchange->issue.orderstatus)(exchange,req->orderid,req->argjson);
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
if ( exchange->issue.cancelorder != 0 )
|
|
|
|
retstr = (*exchange->issue.cancelorder)(exchange,req->orderid,req->argjson);
|
|
|
|
break;
|
|
|
|
case 'O':
|
|
|
|
if ( exchange->issue.openorders != 0 )
|
|
|
|
retstr = (*exchange->issue.openorders)(exchange,req->argjson);
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
if ( exchange->issue.tradehistory != 0 )
|
|
|
|
retstr = (*exchange->issue.tradehistory)(exchange,req->argjson);
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
if ( exchange->issue.withdraw != 0 )
|
|
|
|
retstr = (*exchange->issue.withdraw)(exchange,req->base,req->volume,req->destaddr,req->argjson);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( retstr == 0 )
|
|
|
|
retstr = clonestr("{\"error\":\"null return\"}");
|
|
|
|
return(retstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*void iguana_statemachineupdate(struct supernet_info *myinfo,struct exchange_info *exchange)
|
|
|
|
{
|
|
|
|
int32_t timemod,modwidth = 10; struct iguana_info *coin; struct bitcoin_swapinfo *swap,*tmp; struct iguana_bundlereq *req;
|
|
|
|
timemod = time(NULL) % modwidth;
|
|
|
|
coin = iguana_coinfind("BTCD");
|
|
|
|
portable_mutex_lock(&exchange->mutexS);
|
|
|
|
DL_FOREACH_SAFE(exchange->statemachines,swap,tmp)
|
|
|
|
{
|
|
|
|
if ( swap->dead != 0 || swap->mine.dead != 0 || swap->other.dead != 0 )
|
|
|
|
DL_DELETE(exchange->statemachines,swap);
|
|
|
|
else if ( (swap->mine.orderid % modwidth) == timemod )
|
|
|
|
instantdex_statemachine_iter(myinfo,exchange,swap);
|
|
|
|
}
|
|
|
|
portable_mutex_unlock(&exchange->mutexS);
|
|
|
|
while ( (req= queue_dequeue(&exchange->recvQ,0)) != 0 )
|
|
|
|
{
|
|
|
|
if ( instantdex_recvquotes(coin,req,req->hashes,req->n) != 0 )
|
|
|
|
myfree(req->hashes,(req->n+1) * sizeof(*req->hashes)), req->hashes = 0;
|
|
|
|
}
|
|
|
|
//iguana_inv2poll(myinfo,coin);
|
|
|
|
}*/
|
|
|
|
|
|
|
|
void exchanges777_loop(void *ptr)
|
|
|
|
{
|
|
|
|
struct supernet_info *myinfo; struct exchange_info *exchange = ptr;
|
|
|
|
int32_t flag,retval,i; struct exchange_request *req; char *retstr;
|
|
|
|
myinfo = SuperNET_MYINFO(0);
|
|
|
|
#ifdef INCLUDE_PAX
|
|
|
|
/*struct peggy_info *PEGS=0; int32_t peggyflag = 0;
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
if ( strcmp(exchange->name,"PAX") == 0 )
|
|
|
|
{
|
|
|
|
if ( (PEGS= myinfo->PEGS) != 0 )
|
|
|
|
{
|
|
|
|
exchange->privatedata = PEGS;
|
|
|
|
peggyflag = 1;
|
|
|
|
_crypto_update(PEGS,PEGS->cryptovols,&PEGS->data,1,peggyflag);
|
|
|
|
PEGS->lastupdate = (uint32_t)time(NULL);
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
#endif
|
|
|
|
printf("exchanges loop.(%s)\n",exchange->name);
|
|
|
|
while ( 1 )
|
|
|
|
{
|
|
|
|
PAX_idle(myinfo);
|
|
|
|
flag = retval = 0;
|
|
|
|
retstr = 0;
|
|
|
|
if ( (req= queue_dequeue(&exchange->requestQ)) != 0 )
|
|
|
|
{
|
|
|
|
//printf("dequeued %s.%c\n",exchange->name,req->func);
|
|
|
|
if ( req->dead == 0 )
|
|
|
|
{
|
|
|
|
retstr = exchanges777_process(exchange,&retval,req);
|
|
|
|
//printf("retval.%d (%p) retstrp.%p timedout.%u\n",retval,retstr,req->retstrp,req->timedout);
|
|
|
|
if ( retval == EXCHANGE777_DONE )
|
|
|
|
{
|
|
|
|
if ( retstr != 0 )
|
|
|
|
{
|
|
|
|
if ( req->retstrp != 0 && req->timedout == 0 )
|
|
|
|
*req->retstrp = retstr;
|
|
|
|
else free(retstr);
|
|
|
|
if ( req->timedout != 0 )
|
|
|
|
printf("timedout.%u req finally finished at %u\n",req->timedout,(uint32_t)time(NULL));
|
|
|
|
}
|
|
|
|
free(req);
|
|
|
|
flag++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( retstr != 0 )
|
|
|
|
free(retstr);
|
|
|
|
//if ( retval == EXCHANGE777_ISPENDING )
|
|
|
|
// queue_enqueue("Xpending",&exchange->pendingQ,&req->DL,0), flag++;
|
|
|
|
//else
|
|
|
|
if ( retval == EXCHANGE777_REQUEUE )
|
|
|
|
queue_enqueue("requeue",&exchange->requestQ,&req->DL);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("exchanges777_process: illegal retval.%d\n",retval);
|
|
|
|
free(req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( req->retstrp != 0 )
|
|
|
|
*req->retstrp = clonestr("{\"result\":\"request killed\"}");
|
|
|
|
free(req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tradebot_timeslices(exchange);
|
|
|
|
if ( time(NULL) > exchange->lastpoll+exchange->pollgap )
|
|
|
|
{
|
|
|
|
/*if ( strcmp(exchange->name,"bitcoin") == 0 )
|
|
|
|
{
|
|
|
|
iguana_statemachineupdate(myinfo,exchange);
|
|
|
|
//printf("InstantDEX call update\n");
|
|
|
|
}*/
|
|
|
|
if ( (req= queue_dequeue(&exchange->pricesQ)) != 0 )
|
|
|
|
{
|
|
|
|
//printf("check %s pricesQ (%s %s)\n",exchange->name,req->base,req->rel);
|
|
|
|
if ( req->dead == 0 )
|
|
|
|
{
|
|
|
|
if ( req->base[0] != 0 )
|
|
|
|
{
|
|
|
|
req->timestamp = exchange->lastpoll = (uint32_t)time(NULL);
|
|
|
|
req->exchange = exchange;
|
|
|
|
req->hbla = (*exchange->issue.price)(exchange,req->base,req->rel,req->bidasks,req->depth,req->commission,req->argjson,req->invert);
|
|
|
|
for (i=req->numbids=0; i<req->depth; i++)
|
|
|
|
if ( req->bidasks[i << 1].price > SMALLVAL )
|
|
|
|
req->numbids++;
|
|
|
|
for (i=req->numasks=0; i<req->depth; i++)
|
|
|
|
if ( req->bidasks[(i << 1) + 1].price > SMALLVAL )
|
|
|
|
req->numasks++;
|
|
|
|
//printf("%-10s %s/%s numbids.%d numasks.%d\n",exchange->name,req->base,req->rel,req->numbids,req->numasks);
|
|
|
|
prices777_processprice(exchange,req->base,req->rel,req->bidasks,req->depth);
|
|
|
|
}
|
|
|
|
queue_enqueue("pricesQ",&exchange->pricesQ,&req->DL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( req->retstrp != 0 )
|
|
|
|
*req->retstrp = clonestr("{\"result\":\"request killed\"}");
|
|
|
|
free(req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( flag == 0 )
|
|
|
|
sleep(exchange->pollgap/2 + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct exchange_request *exchanges777_baserelfind(struct exchange_info *exchange,char *base,char *rel,int32_t func)
|
|
|
|
{
|
|
|
|
struct exchange_request PAD,*req,*retreq=0;
|
|
|
|
memset(&PAD,0,sizeof(PAD));
|
|
|
|
queue_enqueue("pricesQ",&exchange->pricesQ,&PAD.DL);
|
|
|
|
while ( (req= queue_dequeue(&exchange->pricesQ)) != 0 && req != &PAD )
|
|
|
|
{
|
|
|
|
if ( ((req->invert == 0 && strcmp(base,req->base) == 0 && strcmp(rel,req->rel) == 0) || (req->invert != 0 && strcmp(rel,req->base) == 0 && strcmp(base,req->rel) == 0)) && (func < 0 || req->func == func) )
|
|
|
|
retreq = req;
|
|
|
|
queue_enqueue("pricesQ",&exchange->pricesQ,&req->DL);
|
|
|
|
}
|
|
|
|
return(retreq);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_unmonitor(struct exchange_info *exchange,char *base,char *rel)
|
|
|
|
{
|
|
|
|
struct exchange_request *req; char *retstr = 0;
|
|
|
|
if ( (req= exchanges777_baserelfind(exchange,base,rel,'M')) != 0 )
|
|
|
|
{
|
|
|
|
printf("unmonitor.%s (%s %s)\n",exchange->name,base,rel);
|
|
|
|
req->dead = (uint32_t)time(NULL);
|
|
|
|
retstr = clonestr("{\"result\":\"mark priceQ entry as dead\"}");
|
|
|
|
}
|
|
|
|
if ( retstr == 0 )
|
|
|
|
retstr = clonestr("{\"error\":\"cant find base/rel pair to unmonitor\"}");
|
|
|
|
return(retstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_submit(struct exchange_info *exchange,struct exchange_request *req,int32_t func,int32_t maxseconds)
|
|
|
|
{
|
|
|
|
int32_t i; char **retstrp,*retstr;
|
|
|
|
req->func = func;
|
|
|
|
if ( maxseconds == 0 )
|
|
|
|
maxseconds = EXCHANGES777_DEFAULT_TIMEOUT;
|
|
|
|
retstrp = req->retstrp;
|
|
|
|
//printf("submit to %p\n",&exchange->requestQ);
|
|
|
|
queue_enqueue("exchangeQ",&exchange->requestQ,&req->DL);
|
|
|
|
for (i=0; i<maxseconds; i++)
|
|
|
|
{
|
|
|
|
if ( retstrp != 0 && (retstr= *retstrp) != 0 )
|
|
|
|
{
|
|
|
|
//printf("exchanges777_submit GOT.(%s)\n",retstr);
|
|
|
|
free(retstrp);
|
|
|
|
return(retstr);
|
|
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
req->timedout = (uint32_t)time(NULL);
|
|
|
|
printf("exchanges777_submit timed out.(%c)\n",func);
|
|
|
|
return(clonestr("{\"error\":\"request timed out\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_Qtrade(struct exchange_info *exchange,char *base,char *rel,int32_t maxseconds,int32_t dotrade,int32_t dir,double price,double volume,cJSON *argjson)
|
|
|
|
{
|
|
|
|
struct exchange_request *req; int32_t polarity;
|
|
|
|
if ( exchange->issue.supports == 0 )
|
|
|
|
return(clonestr("{\"error\":\"no supports function\"}"));
|
|
|
|
if ( base[0] == 0 || rel[0] == 0 || (polarity= (*exchange->issue.supports)(exchange,base,rel,argjson)) <= 0 || price < SMALLVAL || volume < SMALLVAL )
|
|
|
|
return(clonestr("{\"error\":\"invalid base or rel\"}"));
|
|
|
|
req = calloc(1,sizeof(*req));
|
|
|
|
req->argjson = argjson; req->retstrp = calloc(1,sizeof(void *));
|
|
|
|
safecopy(req->base,base,sizeof(req->base));
|
|
|
|
safecopy(req->rel,rel,sizeof(req->rel));
|
|
|
|
req->price = price, req->volume = volume, req->dir = dir;
|
|
|
|
req->dotrade = dotrade;
|
|
|
|
return(exchanges777_submit(exchange,req,'T',maxseconds));
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_Qprices(struct exchange_info *exchange,char *base,char *rel,int32_t maxseconds,int32_t allfields,int32_t depth,cJSON *argjson,int32_t monitor,double commission)
|
|
|
|
{
|
|
|
|
struct exchange_request *req; int32_t polarity;
|
|
|
|
if ( exchange->issue.supports == 0 )
|
|
|
|
{
|
|
|
|
printf("%s doesnt have supports func\n",exchange->name);
|
|
|
|
return(clonestr("{\"error\":\"no supports function\"}"));
|
|
|
|
}
|
|
|
|
if ( base[0] == 0 || rel[0] == 0 || (polarity= (*exchange->issue.supports)(exchange,base,rel,argjson)) == 0 )
|
|
|
|
{
|
|
|
|
//printf("%s invalid (%s) or (%s)\n",exchange->name,base,rel);
|
|
|
|
return(clonestr("{\"error\":\"invalid base or rel\"}"));
|
|
|
|
}
|
|
|
|
if ( depth <= 0 )
|
|
|
|
depth = 1;
|
|
|
|
req = calloc(1,sizeof(*req) + sizeof(*req->bidasks)*depth*2);
|
|
|
|
req->argjson = argjson; req->retstrp = calloc(1,sizeof(void *));
|
|
|
|
if ( polarity < 0 )
|
|
|
|
{
|
|
|
|
req->invert = 1;
|
|
|
|
safecopy(req->base,rel,sizeof(req->base));
|
|
|
|
safecopy(req->rel,base,sizeof(req->rel));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
safecopy(req->base,base,sizeof(req->base));
|
|
|
|
safecopy(req->rel,rel,sizeof(req->rel));
|
|
|
|
}
|
|
|
|
req->depth = depth, req->allflag = allfields;
|
|
|
|
if ( (req->commission= commission) == 0. )
|
|
|
|
req->commission = exchange->commission;
|
|
|
|
if ( monitor == 0 )
|
|
|
|
{
|
|
|
|
printf("%s submit (%s) (%s)\n",exchange->name,base,rel);
|
|
|
|
return(exchanges777_submit(exchange,req,'Q',maxseconds));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
req->func = 'M';
|
|
|
|
//printf("Monitor.%s (%s %s) invert.%d\n",exchange->name,base,rel,req->invert);
|
|
|
|
queue_enqueue("pricesQ",&exchange->pricesQ,&req->DL);
|
|
|
|
return(clonestr("{\"result\":\"start monitoring\"}"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exchanges777_Qrequest(struct exchange_info *exchange,int32_t func,char *base,char *rel,int32_t maxseconds,uint64_t orderid,char *destaddr,double amount,cJSON *argjson)
|
|
|
|
{
|
|
|
|
struct exchange_request *req;
|
|
|
|
req = calloc(1,sizeof(*req));
|
|
|
|
req->volume = amount;
|
|
|
|
safecopy(req->destaddr,destaddr,sizeof(req->destaddr));
|
|
|
|
safecopy(req->base,base,sizeof(req->base));
|
|
|
|
safecopy(req->rel,rel,sizeof(req->rel));
|
|
|
|
req->retstrp = calloc(1,sizeof(void *));
|
|
|
|
req->orderid = orderid;
|
|
|
|
//printf("Qrequest\n");
|
|
|
|
return(exchanges777_submit(exchange,req,func,maxseconds));
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t exchanges777_id(char *exchangestr)
|
|
|
|
{
|
|
|
|
int32_t i;
|
|
|
|
if ( exchangestr != 0 )
|
|
|
|
{
|
|
|
|
for (i=0; i<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs); i++)
|
|
|
|
{
|
|
|
|
//printf("%s ",Exchange_funcs[i]->name);
|
|
|
|
if ( strcmp(exchangestr,Exchange_funcs[i]->name) == 0 )
|
|
|
|
return(i);
|
|
|
|
}
|
|
|
|
//printf("cant find (%s)\n",exchangestr);
|
|
|
|
}
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
struct exchange_info *exchanges777_findbits(uint64_t exchangebits)
|
|
|
|
{
|
|
|
|
int32_t i;
|
|
|
|
for (i=0; i<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs); i++)
|
|
|
|
{
|
|
|
|
//printf("%s ",Exchange_funcs[i]->name);
|
|
|
|
if ( Exchanges[i] != 0 && exchangebits == Exchanges[i]->exchangebits )
|
|
|
|
return(Exchanges[i]);
|
|
|
|
}
|
|
|
|
//printf("cant find (%s)\n",exchangestr);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct exchange_info *exchanges777_find(char *exchangestr)
|
|
|
|
{
|
|
|
|
int32_t exchangeid;
|
|
|
|
if ( (exchangeid= exchanges777_id(exchangestr)) >= 0 )
|
|
|
|
return(Exchanges[exchangeid]);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void iguana_gotquotesM(struct iguana_info *coin,struct iguana_peer *addr,bits256 *quotes,int32_t n)
|
|
|
|
{
|
|
|
|
struct iguana_bundlereq *req; struct exchange_info *exchange = exchanges777_find("bitcoin");
|
|
|
|
//printf("got %d quotes from %s\n",n,addr->ipaddr);
|
|
|
|
req = iguana_bundlereq(coin,addr,'Q',0,0);
|
|
|
|
req->hashes = quotes, req->n = n;
|
|
|
|
queue_enqueue("recvQ",&exchange->recvQ,&req->DL);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct exchange_info *exchange_create(char *exchangestr,cJSON *argjson)
|
|
|
|
{
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
static int didinit;
|
|
|
|
if ( didinit == 0 )
|
|
|
|
{
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
int32_t i,j;
|
|
|
|
for (i=0; i<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs)-1; i++)
|
|
|
|
{
|
|
|
|
for (j=i+1; j<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs); j++)
|
|
|
|
if ( stringbits((char *)Exchange_funcs[i]->name) == stringbits((char *)Exchange_funcs[j]->name) )
|
|
|
|
{
|
|
|
|
printf("FIRST 8 chars of Exchange_func[].name must be unique: %d.(%s) vs %d.(%s)\n",i,Exchange_funcs[i]->name,j,Exchange_funcs[j]->name);
|
|
|
|
iguana_exit(0,0);
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
}
|
|
|
|
}
|
|
|
|
didinit = 1;
|
|
|
|
}
|
|
|
|
char *key,*secret,*userid,*tradepassword; struct exchange_info *exchange; int32_t i,exchangeid;
|
|
|
|
if ( exchangestr == 0 || exchangestr[0] == 0 )
|
|
|
|
return(0);
|
|
|
|
if ( (exchangeid= exchanges777_id(exchangestr)) < 0 )
|
|
|
|
{
|
|
|
|
printf("exchange_create: cant find.(%s)\n",exchangestr);
|
|
|
|
return(0);
|
|
|
|
}
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
for (i=0; i<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs); i++)
|
|
|
|
{
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
if ( strcmp(exchangestr,Exchange_funcs[i]->name) == 0 )
|
|
|
|
break;
|
|
|
|
}
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
if ( i == sizeof(Exchange_funcs)/sizeof(*Exchange_funcs) )
|
|
|
|
{
|
|
|
|
printf("cant find exchange.(%s)\n",exchangestr);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
exchange = calloc(1,sizeof(*exchange));
|
|
|
|
portable_mutex_init(&exchange->mutex);
|
|
|
|
portable_mutex_init(&exchange->mutexS);
|
|
|
|
portable_mutex_init(&exchange->mutexH);
|
|
|
|
portable_mutex_init(&exchange->mutexP);
|
|
|
|
portable_mutex_init(&exchange->mutexR);
|
|
|
|
portable_mutex_init(&exchange->mutexT);
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
exchange->issue = *Exchange_funcs[i];
|
|
|
|
iguana_initQ(&exchange->recvQ,"recvQ");
|
|
|
|
iguana_initQ(&exchange->pricesQ,"pricesQ");
|
|
|
|
iguana_initQ(&exchange->requestQ,"requestQ");
|
|
|
|
exchange->exchangeid = exchangeid;
|
|
|
|
safecopy(exchange->name,exchangestr,sizeof(exchange->name));
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
exchange->exchangebits = stringbits(exchange->name);
|
|
|
|
if ( argjson != 0 )
|
|
|
|
{
|
|
|
|
if ( (exchange->pollgap= juint(argjson,"pollgap")) < EXCHANGES777_MINPOLLGAP )
|
|
|
|
exchange->pollgap = EXCHANGES777_MINPOLLGAP;
|
|
|
|
if ( (key= jstr(argjson,"apikey")) != 0 || (key= jstr(argjson,"key")) != 0 )
|
|
|
|
safecopy(exchange->apikey,key,sizeof(exchange->apikey));
|
|
|
|
if ( (secret= jstr(argjson,"apisecret")) != 0 || (secret= jstr(argjson,"secret")) != 0 )
|
|
|
|
safecopy(exchange->apisecret,secret,sizeof(exchange->apisecret));
|
|
|
|
if ( (userid= jstr(argjson,"userid")) != 0 )
|
|
|
|
safecopy(exchange->userid,userid,sizeof(exchange->userid));
|
|
|
|
if ( (tradepassword= jstr(argjson,"tradepassword")) != 0 )
|
|
|
|
safecopy(exchange->tradepassword,tradepassword,sizeof(exchange->tradepassword));
|
|
|
|
if ( (exchange->commission= jdouble(argjson,"commission")) > 0. )
|
|
|
|
exchange->commission *= .01;
|
|
|
|
}
|
|
|
|
printf("ADDEXCHANGE.(%s) [%s, %s, %s] commission %.3f%% -> exchangeid.%d\n",exchangestr,exchange->apikey,exchange->userid,exchange->apisecret,exchange->commission * 100.,exchangeid);
|
|
|
|
Exchanges[exchangeid] = exchange;
|
|
|
|
//instantdex_FSMinit();
|
|
|
|
iguana_launch(0,"exchangeloop",(void *)exchanges777_loop,exchange,IGUANA_EXCHANGETHREAD);
|
|
|
|
return(exchange);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct exchange_info *exchanges777_info(char *exchangestr,int32_t sleepflag,cJSON *json,char *remoteaddr)
|
|
|
|
{
|
|
|
|
struct exchange_info *exchange;
|
|
|
|
if ( remoteaddr != 0 || exchangestr == 0 )
|
|
|
|
return(0);
|
|
|
|
if ( (exchange= exchanges777_find(exchangestr)) == 0 )
|
|
|
|
{
|
|
|
|
if ( (exchange= exchange_create(exchangestr,json)) != 0 )
|
|
|
|
{
|
|
|
|
if ( sleepflag > 0 )
|
|
|
|
sleep(sleepflag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( 0 && exchange != 0 )
|
|
|
|
printf("found exchange.(%s) %p %p %p\n",exchange->name,exchange->issue.supports,exchange->issue.price,exchange->issue.allpairs);
|
|
|
|
return(exchange);
|
|
|
|
}
|
|
|
|
|
|
|
|
void exchanges777_init(struct supernet_info *myinfo,cJSON *exchanges,int32_t sleepflag)
|
|
|
|
{
|
|
|
|
int32_t i,n; cJSON *argjson,*item; struct exchange_info *exchange;
|
|
|
|
if ( (exchange= exchanges777_find("bitcoin")) == 0 && (exchange= exchange_create("bitcoin",0)) != 0 )
|
|
|
|
myinfo->tradingexchanges[myinfo->numexchanges++] = exchange;
|
|
|
|
if ( exchanges != 0 )
|
|
|
|
{
|
|
|
|
n = cJSON_GetArraySize(exchanges);
|
|
|
|
for (i=0; i<n; i++)
|
|
|
|
{
|
|
|
|
item = jitem(exchanges,i);
|
|
|
|
if ( (exchange= exchanges777_find(jstr(item,"name"))) == 0 && (exchange= exchange_create(jstr(item,"name"),item)) != 0 )
|
|
|
|
myinfo->tradingexchanges[myinfo->numexchanges++] = exchange;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( 1 )
|
|
|
|
{
|
|
|
|
argjson = cJSON_CreateObject();
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
for (i=0; i<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs); i++)
|
|
|
|
if ( (exchange= exchanges777_find(Exchange_funcs[i]->name)) == 0 )
|
|
|
|
{
|
|
|
|
if ( strcmp(Exchange_funcs[i]->name,"PAX") == 0 || strcmp(Exchange_funcs[i]->name,"truefx") == 0 || strcmp(Exchange_funcs[i]->name,"fxcm") == 0 || strcmp(Exchange_funcs[i]->name,"instaforex") == 0 )
|
|
|
|
{
|
|
|
|
exchange->pollgap = 60;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( ((exchange= exchanges777_find(Exchange_funcs[i]->name)) == 0 && (exchange= exchange_create(Exchange_funcs[i]->name,0)) != 0) || (exchange= exchanges777_info(Exchange_funcs[i]->name,sleepflag,argjson,0)) != 0 )
|
|
|
|
myinfo->tradingexchanges[myinfo->numexchanges++] = exchange;
|
|
|
|
}
|
|
|
|
free_json(argjson);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cJSON *iguana_pricesarray(struct supernet_info *myinfo,char *exchange,char *base,char *rel,int32_t period,uint32_t start,uint32_t end)
|
|
|
|
{
|
|
|
|
cJSON *array = cJSON_CreateArray();
|
|
|
|
return(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "../includes/iguana_apidefs.h"
|
|
|
|
|
|
|
|
THREE_STRINGS_AND_THREE_INTS(InstantDEX,orderbook,exchange,base,rel,depth,allfields,ignore)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( exchange != 0 && exchange[0] != 0 )
|
|
|
|
{
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qprices(ptr,base,rel,juint(json,"maxseconds"),allfields,depth,json,0,ptr->commission));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no exchange specified\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,buy,exchange,base,rel,price,volume,dotrade)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qtrade(ptr,base,rel,juint(json,"maxseconds"),dotrade,1,price,volume,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,sell,exchange,base,rel,price,volume,dotrade)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qtrade(ptr,base,rel,juint(json,"maxseconds"),dotrade,-1,price,volume,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS_AND_DOUBLE(InstantDEX,withdraw,exchange,base,destaddr,amount)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'W',base,0,juint(json,"maxseconds"),0,destaddr,amount,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TWO_STRINGS(InstantDEX,balance,exchange,base)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'B',base,0,juint(json,"maxseconds"),0,0,0,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TWO_STRINGS(InstantDEX,orderstatus,exchange,orderid)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'P',0,0,juint(json,"maxseconds"),calc_nxt64bits(orderid),0,0,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TWO_STRINGS(InstantDEX,cancelorder,exchange,orderid)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'C',0,0,juint(json,"maxseconds"),calc_nxt64bits(orderid),0,0,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
STRING_ARG(InstantDEX,openorders,exchange)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'O',0,0,juint(json,"maxseconds"),0,0,0,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
STRING_ARG(InstantDEX,tradehistory,exchange)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'H',0,0,juint(json,"maxseconds"),0,0,0,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS(InstantDEX,apikeypair,exchange,apikey,apisecret)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
{
|
|
|
|
if ( apikey != 0 && apikey[0] != 0 && apisecret != 0 && apisecret[0] != 0 )
|
|
|
|
{
|
|
|
|
safecopy(ptr->apikey,apikey,sizeof(ptr->apikey));
|
|
|
|
safecopy(ptr->apisecret,apisecret,sizeof(ptr->apisecret));
|
|
|
|
return(clonestr("{\"result\":\"set apikey and apisecret\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"need both userid and password\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS(InstantDEX,setuserid,exchange,userid,tradepassword)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
{
|
|
|
|
safecopy(ptr->userid,userid,sizeof(ptr->userid));
|
|
|
|
safecopy(ptr->tradepassword,tradepassword,sizeof(ptr->tradepassword));
|
|
|
|
return(clonestr("{\"result\":\"set userid and/or tradepassword\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
STRING_AND_INT(InstantDEX,pollgap,exchange,pollgap)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( remoteaddr == 0 )
|
|
|
|
{
|
|
|
|
if ( myinfo->expiration == 0 )
|
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
{
|
|
|
|
ptr->pollgap = pollgap;
|
|
|
|
return(clonestr("{\"result\":\"set pollgap\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"no remote for this API\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
ZERO_ARGS(InstantDEX,allexchanges)
|
|
|
|
{
|
|
|
|
int32_t i; cJSON *retjson,*array;
|
|
|
|
retjson = cJSON_CreateObject(); array = cJSON_CreateArray();
|
many changes
blockexplorer tab: needs to allow to input height, blockhash or txid.
also please display images/BTC_blocks.jpg below the text as a w800 x
h400 bitmap, which is active using the mouse api
for coin management, below the active coins have a form that arbitrary
json can be input with an add button to the right that will call
"addcoin" API. this way I can test adding new coins dynamically. dont
worry if it doesnt work, just as long as it submits the json to the C
code. I am pretty sure I need to do some debugging of this
peers management is not working for me at all. maybe it is due to bad
internet. On initialization you need to read in the
confs/BTCD_peers.txt from the native filesystem and save it into the
chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is
only to be done if there isnt already such a file inside chrome. if
there is, only do it upon a button invoked by the user. the reason is
that the pexe is updating this file with the latest. Maybe it is nice
to have an "extract" button that will copy out from the chrome storage
into the native filesystem. There is also the manifest issue about
localstorage vs chrome.localstorage. not sure what is needed to be
done, but certainly a priority to get it so everything works as a
chrome app. I know before it was making ramchain files inside the
chrome filesystem, so it is probably things the GUI is doing. maybe in
the settings tab, which has obsolete stuff that can be removed.
anyway, the issue about files existing in the native filesystem ->
chrome and optionally extracting them is an issue for the confs files
and .html template files used to autogenerate the port7778, maybe other
files are affected. i think we need a way to have a list of hardcoded
files that are just copied into chrome on startup if they dont exist
already (or if possible copy over if the native version is bigger?) and
buttons to extract them
for debug tab:
THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything);
TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile);
at the top of page a way to put in passphrase and optional
permanentfile along with arbitrary json. The standard form template has
no easy way to describe to pass in everything as it is oriented to
specific fields. but the encryptjson API saves all the fields, so the
arbitrary json from the form needs to be combined at the same level as
the "agent", "method", etc. I know, not the best, but internally it
makes it easier. so
{"agent":"SuperNET","method":"encryptjson","passphrase":"<passphrase>","
permanentfile":"<filename>","fromform":"valuefromform","fromform2":"valu
efromform2",...rest of form at top level}
then this will save it into a file with crazy number (it is a hash like
txid) but given the same passphrase and filename, it will regenerate
this hash so you dont actually have to store it, but it helps during
debugging.
for the filename, we must warn quite strongly to the user that if the
file is ever lost or even changed in any way that the data will not be
recoverable. also best to not allow the user to specify a file that
does not exist. I think at this point chrome app version gets a bit
tricky. we could simply push the native file into the chrome storage,
but then an attacker who gets access to the computer could just get a
list of these files and it really wont be much protection. So that
means if a filename is specified, it needs to be copied into the chrome
space, then immediately deleted... ok, this seems like not a good
approach. let us make it so that the permanentfile option is not
available from the chrome app, but only if the native version is
running. that way we sidestep the issue of the pexe not having access
to the specified file.
Speaking of native vs pexe, on the startup page we should have a radio
button that allows the user to select which the GUI will talk to. It
should default based on a self test to the more likely value, but it is
possible that the user wants to use the native version, even if the
pexe is running.
another thing to have on the startup page is a simple login:
THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle);
ZERO_ARGS(SuperNET,logout);
ZERO_ARGS(SuperNET,activehandle);
the handle is a human readable name that is associated with the
passphrase/permanentfile. There can only be one active account (though
it will be possible to associate different accounts with tradebots).
use the activehandle API to find out who is logged in and the
associated addresses and pubkeys
The above is not yet tested so if it doesnt work, dont fret, just let
me know. Once set the handle can be displayed in various places to let
the user know which account is logged in. The standard 12 dictionary
word passphrases should be used, but any string can be sent in as the
password
for Pangea:
INT_AND_ARRAY(pangea,host,minplayers,params);
ZERO_ARGS(pangea,lobby);
HASH_AND_STRING(pangea,join,tablehash,handle);
HASH_AND_INT(pangea,buyin,tablehash,numchips);
HASH_ARG(pangea,start,tablehash); // by host only
HASH_ARG(pangea,status,tablehash);
HASH_ARG(pangea,call,tablehash);
HASH_ARG(pangea,check,tablehash);
HASH_AND_INT(pangea,raise,tablehash,numchips);
HASH_AND_INT(pangea,bet,tablehash,numchips);
HASH_ARG(pangea,fold,tablehash);
HASH_AND_STRING(pangea,mode,tablehash,modestr);
HASH_ARG(pangea,history,tablehash);
HASH_AND_INT(pangea,handhistory,tablehash,hand);
The first thing that is done is a "host" by any node. the "params"
should be an arbitrary json (like encryptjson) as it needs to be at the
top level and it has quite a few different parameters still subject to
change. The lobby API will just display all the hosted tables.
once a table exists, players can join and then buyin. the buyin is
denominated in chips, each chip's value is determined by the host's
initial parameters.
once there are enough players joined with adequate buyin's verified,
the host will be able to do a start. if done before it will
(eventually) give an error. for now it will just proceed.
The host and players that have joined a tablehash, need to do regular
status calls to see if the game has started. Probably just once per 5
or even 10 seconds is fine before the start. Once the game starts (the
status will have this info) then once per second polling is needed.
Then when it is your turn (as indicated by status) you need to do one
of the 5 actions (fold, call, check, raise, bet). do not worry if you
dont understand what all these do, just allow the user to do any of
these. I guess it is possible to submit it ahead of time. I will
support internally remembering the most recent action done prior to it
being your turn. once it is your turn and an action is sent to the
table, it is too late to change.
The last API calls are for getting handhistory where hand is 0 to N-1,
being the numbering of the hands played at that table. if just history,
all the history for all hands at the table is coming back, so it could
be quite big. probably I will make it a summary, but for the GUI just
display the returned values.
the mode is to change some poker specific modes, so just allow there to
be a string entered.
do not worry about understanding the pokerness of the API, just the
overall flow:
host -> creates, join/buyin -> fills up player slots, start -> starts
the game
status -> to determine when the game starts (or if it is cancelled) and
once started
actions -> game specific but basically just (button + arg) that is the
user input
results are via status for current game and history for past ones
please try to do the above logic in a generic way so it can be reused
for other games. The basic flow should be the same for almost all
multiplayer turn based games and even for multiplayer realtime games
For InstantDEX:
on the apikeypair/userid there needs to be two modes. one for when
there is no stored apikey and the current form is fine, just need to
make it wider as most apikeys are quite long. Now once there is an
apikey saved all that is needed is the passphrase to unlock it. So here
is where the encrptjson/decryptjson is used. When saving the apikey for
the first time, it can be:
a) not saved -> nothing extra to do
b) saved without password -> you can just save to a file and use it to
load it back in. use confs dir confs/instantdex.exchange.api or
something like that
c) saved with password (optional filename for native) -> probably best
to save in the confs dir to indicate that there is an encrypted file
for this, so just that and not the actual passphrase in the file
with the above, when the exchange is selected, you can see if the confs
file exists and if it has the plaintext, just populate the field, if
not, then indicate that a passphrase is needed. if the user provides
the passphrase, then decryptjson and populate the fields and autosubmit.
A special case is to encrypt the apikeys with the passphrase used when
logging in. This is only available if the checkbox to "remember
passphrase during session" is set on the main iguana login screen. (i
forgot to mention that checkbox!) So the login passphrase is stored in
memory, then the GUI simply uses that + encryptjson for
storing/decrypting. I would imagine that storing in the confs file that
it is encrypted using "handle"'s account login might be a good way to
differentiate between this mode of password usage.
OK, so we now have the insecure plaintext, the decent using handle's
passphrase and paranoid different passphrase for each exchange (with
additional permanentfile for native versions)
"SUPPORT" -> "SUPPORTS" just a typo
and "allpairs" API is missing from the selection
Might as well add a "tradebots" tab:
THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission);
STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission);
THREE_STRINGS(tradebot,unmonitor,exchange,base,rel);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr
ice,volume,duration);
THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,
volume,duration);
STRING_ARG(tradebot,activebots,exchange);
TWO_STRINGS(tradebot,status,exchange,botid);
TWO_STRINGS(tradebot,pause,exchange,botid);
TWO_STRINGS(tradebot,stop,exchange,botid);
TWO_STRINGS(tradebot,resume,exchange,botid);
the above are API for exchange specific bots, most should be
self-explanatory. bots are created via "accumulate" or "divest" API
call. it returns botid. once created, you can do status, pause, stop,
resume to a botid. and an activebots API call lists all the active bots
for an exchange.
duration is in seconds
the "monitor" API starts background monitoring of a specific base/rel,
"unmonitor" stops this. "monitorall" just does a monitor to the entire
list of "allpairs" for that exchange. Keep in mind that doing a
monitorall will not add load to an exchange as the request to each
exchange is governed by pollgap, but if you have 3 things monitored, it
will take 3*pollgap + time each one takes to execute. and if N are
monitored it is N*pollgap + time of each, with the "time of each"
possibly taking a very long time.
And one final request for today: Bitmap tab.
It should be an active bitmap using mouse api. either a dropdown to
select the bitmap or a form entry. then the rest of the page (resize
the bitmap to the page size) being the active bitmap. So on a small
screen the bitmap is smaller x/y dimensions and larger on larger
screens. plz make sure the proper dimensions are communicated to the
pexe via API if it ever is changed.
@vineet.bhargav86: I changed the "passphrase" fieldname to "password"
for the encryptjson/decryptjson related API. The reason is that the
password is like a wallet password and is only local, so it doesnt need
to be as high entropy as passphrase. I also added a field to the login
API as I realized that the 12 word "passphrase" is the payload and
usually wont be sent in:
FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase);
using "abiglongpassword" for the passphrase ->
{"pubkey":"6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906
209","RS":"NXT-KGV9-DXX8-TM86-DXR96","NXT":"12834974574569896807","btcpu
bkey":"024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c
8","rmd160":"33453c24914db7b77069b7ea24df44f6be145938","BTC":"15g6QK2dSd
iW9ZTQEnnJxKrSph6uP7uU23","BTCD":"RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC","r
esult":"success","handle":"test","tag":"14805226009240621255"}
and if you use that to log into NXT, it gives the same address. The BTC
and BTCD addresses are all derived from the same privkey so they are
all interchangeable with the NXT address. The user can therefore select
which coin's addressing they are most comfortable with
I also added an "allin" action API for pangea. all the action API will
autocalculate the number of chips if passed in 0 for numchips
***************** security issue ********
please dont use the GET URL method when dealing with passphrase!!!
Those URL's tend to get logged and available in browser histories. so
anything dealing with the actual passphrase needs to use the postCall
form or POST
9 years ago
|
|
|
for (i=0; i<sizeof(Exchange_funcs)/sizeof(*Exchange_funcs); i++)
|
|
|
|
jaddistr(array,Exchange_funcs[i]->name);
|
|
|
|
jadd(retjson,"result",array);
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS(InstantDEX,supports,exchange,base,rel)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 )
|
|
|
|
return(exchanges777_Qrequest(ptr,'S',base,rel,juint(json,"maxseconds"),0,0,0,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
STRING_ARG(InstantDEX,allpairs,exchange)
|
|
|
|
{
|
|
|
|
struct exchange_info *ptr;
|
|
|
|
if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 && ptr->issue.allpairs != 0 )
|
|
|
|
return((*ptr->issue.allpairs)(ptr,json));
|
|
|
|
else return(clonestr("{\"error\":\"cant find or create exchange\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TWO_STRINGS(iguana,rate,base,rel)
|
|
|
|
{
|
|
|
|
cJSON *retjson,*tmpjson; char *retstr,baserel[128],_base[64],_rel[64]; double aveprice = 0.;
|
|
|
|
safecopy(_base,base,sizeof(_base));
|
|
|
|
safecopy(_rel,rel,sizeof(_rel));
|
|
|
|
if ( (retstr= tradebot_aveprice(myinfo,coin,json,remoteaddr,"",_base,_rel,1)) != 0 )
|
|
|
|
{
|
|
|
|
if ( (tmpjson= cJSON_Parse(retstr)) != 0 )
|
|
|
|
{
|
|
|
|
aveprice = jdouble(tmpjson,"aveprice");
|
|
|
|
retjson = cJSON_CreateObject();
|
|
|
|
sprintf(baserel,"%s/%s",_base,_rel);
|
|
|
|
jaddnum(retjson,baserel,aveprice);
|
|
|
|
jaddstr(retjson,"result","success");
|
|
|
|
free_json(tmpjson);
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
} else return(clonestr("{\"error\":\"error parsing return from aveprice\"}"));
|
|
|
|
} else return(clonestr("{\"error\":\"null return from aveprice\"}"));
|
|
|
|
}
|
|
|
|
|
|
|
|
THREE_STRINGS_AND_THREE_INTS(iguana,prices,exchange,base,rel,period,start,end)
|
|
|
|
{
|
|
|
|
cJSON *retjson = cJSON_CreateObject();
|
|
|
|
if ( period <= 0 )
|
|
|
|
period = 60;
|
|
|
|
if ( end <= 0 )
|
|
|
|
end = (uint32_t)time(NULL);
|
|
|
|
if ( start <= 0 || start >= end )
|
|
|
|
start = end - 1024*period;
|
|
|
|
jaddstr(retjson,"base",base);
|
|
|
|
jaddstr(retjson,"rel",rel);
|
|
|
|
jaddstr(retjson,"exchange",exchange[0] != 0 ? exchange : "all");
|
|
|
|
jaddstr(retjson,"result","success");
|
|
|
|
jaddnum(retjson,"start",start);
|
|
|
|
jaddnum(retjson,"end",end);
|
|
|
|
jaddnum(retjson,"period",period);
|
|
|
|
jadd(retjson,"prices",iguana_pricesarray(myinfo,exchange,base,rel,period,start,end));
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
|
|
|
|
INT_AND_ARRAY(iguana,rates,unused,quotes)
|
|
|
|
{
|
|
|
|
int32_t i,n,len,j,haveslash; char *retstr,*quote,base[64][64],rel[64][64],field[64]; double aveprice; cJSON *tmpjson,*item,*array=0,*retjson = cJSON_CreateObject();
|
|
|
|
#ifdef INCLUDE_PAX
|
|
|
|
char *str; int32_t nonz;
|
|
|
|
if ( myinfo->PEGS != 0 && (str= peggy_emitprices(&nonz,myinfo->PEGS,(uint32_t)time(NULL),PEGGY_MAXLOCKDAYS)) != 0 )
|
|
|
|
free(str);
|
|
|
|
#endif
|
|
|
|
if ( is_cJSON_Array(quotes) != 0 && (n= cJSON_GetArraySize(quotes)) > 0 )
|
|
|
|
{
|
|
|
|
if ( n > 64 )
|
|
|
|
{
|
|
|
|
jaddstr(retjson,"error","only 16 quotes at a time");
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
memset(base,0,sizeof(base));
|
|
|
|
memset(rel,0,sizeof(rel));
|
|
|
|
for (i=0; i<n; i++)
|
|
|
|
{
|
|
|
|
if ( (quote= jstri(quotes,i)) != 0 )
|
|
|
|
{
|
|
|
|
len = (int32_t)strlen(quote);
|
|
|
|
if ( len >= 64 )
|
|
|
|
{
|
|
|
|
if ( array != 0 )
|
|
|
|
free_json(array);
|
|
|
|
jaddstr(retjson,"error","quote too long");
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
for (j=haveslash=0; j<len; j++)
|
|
|
|
{
|
|
|
|
if ( quote[j] == '/' )
|
|
|
|
{
|
|
|
|
haveslash = 1;
|
|
|
|
if ( j > 0 && j < len-1 )
|
|
|
|
{
|
|
|
|
memcpy(base[i],quote,j);
|
|
|
|
base[i][j] = 0;
|
|
|
|
j++;
|
|
|
|
strcpy(rel[i],"e[j]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( array != 0 )
|
|
|
|
free_json(array);
|
|
|
|
jaddstr(retjson,"error","no base error in quote item");
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( j < len || haveslash == 0 )
|
|
|
|
{
|
|
|
|
if ( haveslash == 0 )
|
|
|
|
strcpy(base[i],quote);
|
|
|
|
aveprice = 0.;
|
|
|
|
if ( (retstr= tradebot_aveprice(myinfo,coin,json,remoteaddr,"",base[i],rel[i],1)) != 0 )
|
|
|
|
{
|
|
|
|
if ( (tmpjson= cJSON_Parse(retstr)) != 0 )
|
|
|
|
{
|
|
|
|
aveprice = jdouble(tmpjson,"aveprice");
|
|
|
|
//printf("(%s) ",jprint(tmpjson,0));
|
|
|
|
free_json(tmpjson);
|
|
|
|
} else printf("error parsing.(%s)\n",retstr);
|
|
|
|
if ( haveslash == 0 )
|
|
|
|
strcpy(field,base[i]);
|
|
|
|
else sprintf(field,"%s/%s",base[i],rel[i]);
|
|
|
|
item = cJSON_CreateObject();
|
|
|
|
jaddnum(item,field,aveprice);
|
|
|
|
if ( array == 0 )
|
|
|
|
array = cJSON_CreateArray();
|
|
|
|
jaddi(array,item);
|
|
|
|
free(retstr);
|
|
|
|
//printf(" <- aveprice %f\n",aveprice);
|
|
|
|
} else printf("no return from aveprice\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( array != 0 )
|
|
|
|
free_json(array);
|
|
|
|
jaddstr(retjson,"error","syntax error in quote item");
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
} else printf("i.%d of %d null quote\n",i,n);
|
|
|
|
}
|
|
|
|
jaddstr(retjson,"result","success");
|
|
|
|
jadd(retjson,"rates",array);
|
|
|
|
} else jaddstr(retjson,"error","no quotes array");
|
|
|
|
return(jprint(retjson,1));
|
|
|
|
}
|
|
|
|
#include "../includes/iguana_apiundefs.h"
|