diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index 11ea1d80a..7bbb0621d 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -43,6 +43,9 @@ #include #define closesocket close #endif +#ifndef MIN +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#endif #include "../includes/libgfshare.h" #include "../includes/utlist.h" @@ -74,6 +77,10 @@ int32_t ramcoder_decompress(uint8_t *data,int32_t maxlen,uint8_t *bits,uint32_t int32_t ramcoder_compress(uint8_t *bits,int32_t maxlen,uint8_t *data,int32_t datalen,bits256 seed); uint64_t hconv_bitlen(uint64_t bitlen); void _init_HUFF(HUFF *hp,int32_t allocsize,void *buf); +int32_t hgetbit(HUFF *hp); +int32_t hputbit(HUFF *hp,int32_t bit); +uint64_t hconv_bitlen(uint64_t bitlen); +int32_t hseek(HUFF *hp,int32_t offset,int32_t mode); #define SCRIPT_OPRETURN 0x6a #define GENESIS_ACCT "1739068987193023818" // NXT-MRCC-2YLS-8M54-3CMAJ @@ -179,7 +186,7 @@ int32_t expand_datenum(char *date,int32_t datenum); int32_t calc_datenum(int32_t year,int32_t month,int32_t day); int32_t ecb_decrdate(int32_t *yearp,int32_t *monthp,int32_t *dayp,char *date,int32_t datenum); int32_t conv_date(int32_t *secondsp,char *buf); -uint64_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second); +uint32_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second); int32_t OS_conv_unixtime(struct tai *t,int32_t *secondsp,time_t timestamp); double OS_milliseconds(); @@ -253,6 +260,9 @@ int32_t strsearch(char *strs[],int32_t num,char *name); int32_t OS_getline(int32_t waitflag,char *line,int32_t max,char *dispstr); int32_t sort64s(uint64_t *buf,uint32_t num,int32_t size); int32_t revsort64s(uint64_t *buf,uint32_t num,int32_t size); +int decode_base32(uint8_t *token,uint8_t *tokenstr,int32_t len); +int init_base32(char *tokenstr,uint8_t *token,int32_t len); +char *OS_mvstr(); long _stripwhite(char *buf,int accept); int32_t is_DST(int32_t datenum); @@ -261,9 +271,10 @@ int32_t expand_datenum(char *date,int32_t datenum); int32_t calc_datenum(int32_t year,int32_t month,int32_t day); int32_t ecb_decrdate(int32_t *yearp,int32_t *monthp,int32_t *dayp,char *date,int32_t datenum); int32_t conv_date(int32_t *secondsp,char *buf); -uint64_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second); +uint32_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second); int32_t OS_conv_unixtime(struct tai *t,int32_t *secondsp,time_t timestamp); int32_t btc_coinaddr(char *coinaddr,uint8_t addrtype,char *pubkeystr); +int32_t btc_convaddr(char *hexaddr,char *addr58); uint64_t RS_decode(char *rs); int32_t RS_encode(char *rsaddr,uint64_t id); @@ -348,6 +359,7 @@ int32_t btc_priv2pub(uint8_t pubkey[33],uint8_t privkey[32]); extern char *Iguana_validcommands[]; extern bits256 GENESIS_PUBKEY,GENESIS_PRIVKEY; extern char NXTAPIURL[]; +extern int32_t smallprimes[168],Debuglevel; #endif diff --git a/crypto777/OS_time.c b/crypto777/OS_time.c index 8962fcbb1..927f640b2 100755 --- a/crypto777/OS_time.c +++ b/crypto777/OS_time.c @@ -520,7 +520,7 @@ int32_t extract_datenum(int32_t *yearp,int32_t *monthp,int32_t *dayp,int32_t dat else return(-1); } -uint64_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second) // datenum+H:M:S -> unix time +uint32_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t second) // datenum+H:M:S -> unix time { int32_t year,month,day; struct tai t; struct taitime ct; if ( 1 ) @@ -530,7 +530,7 @@ uint64_t OS_conv_datenum(int32_t datenum,int32_t hour,int32_t minute,int32_t sec ct = taitime_set(taidate_set(year,month,day),hour,minute,second); t = taitime2tai(ct); //char str[65]; printf("conv.(y%d m%d d%d %d:%d:%d) %s\n",year,month,day,hour,minute,second,tai_str(str,t)); - return(tai2utc(t));//tai2utime(t)+788250398LL - 4294967296LL); + return((uint32_t)tai2utc(t));//tai2utime(t)+788250398LL - 4294967296LL); } return(0); } diff --git a/crypto777/iguana_OS.c b/crypto777/iguana_OS.c index 74fef127e..8a10e49b2 100755 --- a/crypto777/iguana_OS.c +++ b/crypto777/iguana_OS.c @@ -24,6 +24,15 @@ #define MAP_FILE 0 #endif +char *OS_mvstr() +{ +#ifdef __WIN32 + return("rename"); +#else + return("mv"); +#endif +} + void OS_randombytes(unsigned char *x,long xlen) { OS_portable_randombytes(x,xlen); diff --git a/crypto777/iguana_utils.c b/crypto777/iguana_utils.c index 263c9137d..4729b4781 100755 --- a/crypto777/iguana_utils.c +++ b/crypto777/iguana_utils.c @@ -15,6 +15,27 @@ #include "../iguana/iguana777.h" +int32_t smallprimes[168] = +{ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997 +}; + bits256 bits256_doublesha256(char *hashstr,uint8_t *data,int32_t datalen) { bits256 hash,hash2; int32_t i; @@ -880,6 +901,78 @@ int32_t RS_encode(char *rsaddr,uint64_t id) return(0); } +uint64_t conv_acctstr(char *acctstr) +{ + uint64_t nxt64bits = 0; + int32_t len; + if ( acctstr != 0 ) + { + if ( (len= is_decimalstr(acctstr)) > 0 && len < 24 ) + nxt64bits = calc_nxt64bits(acctstr); + else if ( strncmp("NXT-",acctstr,4) == 0 ) + { + nxt64bits = RS_decode(acctstr); + //nxt64bits = conv_rsacctstr(acctstr,0); + } + } + return(nxt64bits); +} + +int32_t base32byte(int32_t val) +{ + if ( val < 26 ) + return('A' + val); + else if ( val < 32 ) + return('2' + val - 26); + else return(-1); +} + +int32_t unbase32(char c) +{ + if ( c >= 'A' && c <= 'Z' ) + return(c - 'A'); + else if ( c >= '2' && c <= '7' ) + return(c - '2' + 26); + else return(-1); +} + +int init_base32(char *tokenstr,uint8_t *token,int32_t len) +{ + int32_t i,j,n,val5,offset = 0; + for (i=n=0; i= 0 ) + { + for (j=val5=0; j<5; j++,offset++) + { + if ( GETBIT(&val5,j) != 0 ) + SETBIT(token,offset); + else CLEARBIT(token,offset); + } + } else return(-1); + } + while ( (offset & 7) != 0 ) + { + CLEARBIT(token,offset); + offset++; + } + return(offset); +} + void calc_hexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len) { init_hexbytes_noT(hexstr,(void *)msg,len+1); diff --git a/iguana/SuperNET.c b/iguana/SuperNET.c index 4bfca3683..7e7130ebb 100644 --- a/iguana/SuperNET.c +++ b/iguana/SuperNET.c @@ -878,11 +878,53 @@ void SuperNET_parsepeers(struct supernet_info *myinfo,cJSON *array,int32_t n,int } } +cJSON *SuperNET_rosettajson(bits256 privkey,int32_t showprivs) +{ + uint8_t rmd160[20],pub[33],flag = 0; uint64_t nxt64bits; bits256 pubkey; + char str2[41],wifbuf[64],addr[64],str[128]; cJSON *retjson; + pubkey = acct777_pubkey(privkey); + nxt64bits = acct777_nxt64bits(pubkey); + retjson = cJSON_CreateObject(); + jaddbits256(retjson,"pubkey",pubkey); + RS_encode(str,nxt64bits); + jaddstr(retjson,"RS",str); + jadd64bits(retjson,"NXT",nxt64bits); + btc_priv2pub(pub,privkey.bytes); + init_hexbytes_noT(str,pub,33); + jaddstr(retjson,"btcpubkey",str); + calc_OP_HASH160(str2,rmd160,str); + jaddstr(retjson,"rmd160",str2); + if ( btc_coinaddr(addr,0,str) == 0 ) + { + jaddstr(retjson,"BTC",addr); + if ( flag != 0 ) + { + btc_priv2wif(wifbuf,privkey.bytes,0x80); + jaddstr(retjson,"BTCwif",wifbuf); + } + } + if ( btc_coinaddr(addr,60,str) == 0 ) + { + jaddstr(retjson,"BTCD",addr); + if ( flag != 0 ) + { + btc_priv2wif(wifbuf,privkey.bytes,0xbc); + jaddstr(retjson,"BTCDwif",wifbuf); + } + } + if ( flag != 0 ) + jaddbits256(retjson,"privkey",privkey); + return(retjson); +} + #include "../includes/iguana_apidefs.h" HASH_ARG(SuperNET,priv2pub,privkey) { - cJSON *retjson = cJSON_CreateObject(); bits256 pubkey; + cJSON *retjson; bits256 pubkey; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + retjson = cJSON_CreateObject(); crypto_box_priv2pub(pubkey.bytes,privkey.bytes); jaddbits256(retjson,"result",pubkey); return(jprint(retjson,1)); @@ -890,7 +932,10 @@ HASH_ARG(SuperNET,priv2pub,privkey) ZERO_ARGS(SuperNET,keypair) { - cJSON *retjson = cJSON_CreateObject(); bits256 pubkey,privkey; + cJSON *retjson; bits256 pubkey,privkey; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + retjson = cJSON_CreateObject(); crypto_box_keypair(pubkey.bytes,privkey.bytes); jaddstr(retjson,"result","generated keypair"); jaddbits256(retjson,"privkey",privkey); @@ -901,6 +946,8 @@ ZERO_ARGS(SuperNET,keypair) TWOHASHES_AND_STRING(SuperNET,decipher,privkey,srcpubkey,cipherstr) { int32_t cipherlen=0,msglen; char *retstr; cJSON *retjson; void *ptr = 0; uint8_t *cipher,*message,space[8192]; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); if ( cipherstr != 0 ) cipherlen = (int32_t)strlen(cipherstr) >> 1; if ( cipherlen < crypto_box_NONCEBYTES ) @@ -924,6 +971,8 @@ TWOHASHES_AND_STRING(SuperNET,cipher,privkey,destpubkey,message) { cJSON *retjson; char *retstr,*hexstr,space[8129]; uint8_t space2[8129]; uint8_t *cipher; int32_t cipherlen,onetimeflag; bits256 origprivkey; void *ptr = 0; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); if ( (cipher= SuperNET_ciphercalc(&ptr,&cipherlen,&privkey,&destpubkey,(uint8_t *)message,(int32_t)strlen(message)+1,space2,sizeof(space2))) != 0 ) { if ( cipherlen > sizeof(space)/2 ) @@ -973,8 +1022,10 @@ bits256 SuperNET_pindecipher(IGUANA_ARGS,char *pin,char *privcipher) THREE_STRINGS(SuperNET,rosetta,passphrase,pin,showprivkey) { - uint8_t rmd160[20],pub[33],flag = 0; uint64_t nxt64bits; bits256 check,privkey,pubkey,pinpriv,pinpub; - char str2[41],wifbuf[64],addr[64],str[128],privcipher[512],*privcipherstr,*cstr; cJSON *retjson; + uint8_t flag = 0; uint64_t nxt64bits; bits256 check,privkey,pubkey,pinpriv,pinpub; + char str[128],privcipher[512],*privcipherstr,*cstr; cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); nxt64bits = conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); if ( showprivkey != 0 && strcmp(showprivkey,"yes") == 0 ) flag = 1; @@ -990,40 +1041,8 @@ THREE_STRINGS(SuperNET,rosetta,passphrase,pin,showprivkey) } else printf("error parsing cipher retstr.(%s)\n",cstr); free(cstr); } else printf("error SuperNET_cipher null return\n"); - retjson = cJSON_CreateObject(); + retjson = SuperNET_rosettajson(privkey,flag); jaddstr(retjson,"privcipher",privcipher); - jaddbits256(retjson,"pubkey",pubkey); - RS_encode(str,nxt64bits); - jaddstr(retjson,"RS",str); - jadd64bits(retjson,"NXT",nxt64bits); - btc_priv2pub(pub,privkey.bytes); - init_hexbytes_noT(str,pub,33); - jaddstr(retjson,"btcpubkey",str); - calc_OP_HASH160(str2,rmd160,str); - jaddstr(retjson,"rmd160",str2); - if ( btc_coinaddr(addr,0,str) == 0 ) - { - jaddstr(retjson,"BTC",addr); - btc_priv2wif(wifbuf,privkey.bytes,0x80); - if ( flag != 0 ) - jaddstr(retjson,"BTCwif",wifbuf); - } - if ( btc_coinaddr(addr,60,str) == 0 ) - { - jaddstr(retjson,"BTCD",addr); - btc_priv2wif(wifbuf,privkey.bytes,0xbc); - if ( flag != 0 ) - jaddstr(retjson,"BTCDwif",wifbuf); - } - if ( btc_coinaddr(addr,5,str) == 0 ) - { - jaddstr(retjson,"VPN",addr); - btc_priv2wif(wifbuf,privkey.bytes,0xbc); - if ( flag != 0 ) - jaddstr(retjson,"VPNwif",wifbuf); - } - if ( flag != 0 ) - jaddbits256(retjson,"privkey",privkey); check = SuperNET_pindecipher(IGUANA_CALLARGS,pin,privcipher); if ( memcmp(check.bytes,privkey.bytes,sizeof(check)) != 0 ) { @@ -1040,6 +1059,8 @@ THREE_STRINGS(SuperNET,rosetta,passphrase,pin,showprivkey) STRING_ARG(SuperNET,broadcastcipher,message) { bits256 zero; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); memset(zero.bytes,0,sizeof(zero)); return(SuperNET_cipher(IGUANA_CALLARGS,zero,zero,message)); } @@ -1047,6 +1068,8 @@ STRING_ARG(SuperNET,broadcastcipher,message) STRING_ARG(SuperNET,broadcastdecipher,message) { bits256 zero; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); memset(zero.bytes,0,sizeof(zero)); return(SuperNET_decipher(IGUANA_CALLARGS,zero,zero,message)); } @@ -1054,6 +1077,8 @@ STRING_ARG(SuperNET,broadcastdecipher,message) HASH_AND_STRING(SuperNET,multicastcipher,pubkey,message) { bits256 zero; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); memset(zero.bytes,0,sizeof(zero)); return(SuperNET_cipher(IGUANA_CALLARGS,zero,pubkey,message)); } @@ -1061,6 +1086,8 @@ HASH_AND_STRING(SuperNET,multicastcipher,pubkey,message) HASH_AND_STRING(SuperNET,multicastdecipher,privkey,cipherstr) { bits256 zero; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); memset(zero.bytes,0,sizeof(zero)); return(SuperNET_decipher(IGUANA_CALLARGS,privkey,zero,cipherstr)); } @@ -1122,17 +1149,23 @@ TWOSTRINGS_AND_TWOHASHES_AND_TWOINTS(SuperNET,DHT,hexmsg,destip,categoryhash,sub HASH_AND_STRING(SuperNET,saveconf,wallethash,confjsonstr) { + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); return(clonestr("{\"result\":\"saveconf here\"}")); } HASH_ARRAY_STRING(SuperNET,layer,mypriv,otherpubs,str) { + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); return(clonestr("{\"result\":\"layer encrypt here\"}")); } TWO_STRINGS(SuperNET,categoryhashes,category,subcategory) { bits256 categoryhash,subhash; cJSON *retjson = cJSON_CreateObject(); + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); categoryhash = calc_categoryhashes(&subhash,category,subcategory); jaddstr(retjson,"result","category hashes calculated"); jaddbits256(retjson,"categoryhash",categoryhash); @@ -1143,6 +1176,8 @@ TWO_STRINGS(SuperNET,categoryhashes,category,subcategory) TWO_STRINGS(SuperNET,subscribe,category,subcategory) { bits256 categoryhash,subhash; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); categoryhash = calc_categoryhashes(&subhash,category,subcategory); if ( category_subscribe(myinfo,categoryhash,subhash) != 0 ) return(clonestr("{\"result\":\"subscribed\"}")); @@ -1152,6 +1187,8 @@ TWO_STRINGS(SuperNET,subscribe,category,subcategory) TWO_STRINGS(SuperNET,gethexmsg,category,subcategory) { bits256 categoryhash,subhash; struct category_msg *m; char *hexstr; cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); categoryhash = calc_categoryhashes(&subhash,category,subcategory); if ( (m= category_gethexmsg(myinfo,categoryhash,subhash)) != 0 ) { @@ -1167,6 +1204,8 @@ TWO_STRINGS(SuperNET,gethexmsg,category,subcategory) THREE_STRINGS(SuperNET,posthexmsg,category,subcategory,hexmsg) { bits256 categoryhash,subhash; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); categoryhash = calc_categoryhashes(&subhash,category,subcategory); category_posthexmsg(myinfo,categoryhash,subhash,hexmsg,tai_now(),remoteaddr); return(clonestr("{\"result\":\"posted message\"}")); @@ -1175,6 +1214,8 @@ THREE_STRINGS(SuperNET,posthexmsg,category,subcategory,hexmsg) THREE_STRINGS(SuperNET,announce,category,subcategory,message) { bits256 categoryhash,subhash; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); categoryhash = calc_categoryhashes(&subhash,category,subcategory); return(SuperNET_categorymulticast(myinfo,0,categoryhash,subhash,message,juint(json,"maxdelay"),juint(json,"broadcast"),juint(json,"plaintext"))); } @@ -1182,6 +1223,8 @@ THREE_STRINGS(SuperNET,announce,category,subcategory,message) THREE_STRINGS(SuperNET,survey,category,subcategory,message) { bits256 categoryhash,subhash; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); categoryhash = calc_categoryhashes(&subhash,category,subcategory); return(SuperNET_categorymulticast(myinfo,1,categoryhash,subhash,message,juint(json,"maxdelay"),juint(json,"broadcast"),juint(json,"plaintext"))); } @@ -1214,4 +1257,72 @@ INT_ARG(SuperNET,utc2utime,utc) return(jprint(retjson,1)); } +ZERO_ARGS(SuperNET,logout) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + memset(myinfo->persistent_priv.bytes,0,sizeof(myinfo->persistent_priv)); + memset(myinfo->myaddr.persistent.bytes,0,sizeof(myinfo->myaddr.persistent)); + memset(myinfo->handle,0,sizeof(myinfo->handle)); + memset(myinfo->myaddr.NXTADDR,0,sizeof(myinfo->myaddr.NXTADDR)); + myinfo->myaddr.nxt64bits = 0; + return(clonestr("{\"result\":\"logged out\"}")); +} + +ZERO_ARGS(SuperNET,activehandle) +{ + cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + retjson = SuperNET_rosettajson(myinfo->persistent_priv,0); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"handle",myinfo->handle); + return(jprint(retjson,1)); +} + +FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase) +{ + char *str,*decryptstr = 0; cJSON *argjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( bits256_nonz(myinfo->persistent_priv) != 0 && (str= SuperNET_logout(IGUANA_CALLARGS)) != 0 ) + free(str); + if ( handle != 0 ) + safecopy(myinfo->handle,handle,sizeof(myinfo->handle)); + if ( (passphrase == 0 || passphrase[0] == 0) && (decryptstr= SuperNET_decryptjson(IGUANA_CALLARGS,password,permanentfile)) != 0 ) + { + if ( (argjson= cJSON_Parse(decryptstr)) != 0 ) + { + printf("decrypted.(%s)\n",decryptstr); + free(decryptstr); + if ( (passphrase= jstr(argjson,"passphrase")) != 0 ) + { + SuperNET_setkeys(myinfo,passphrase,(int32_t)strlen(passphrase),1); + free_json(argjson); + return(SuperNET_activehandle(IGUANA_CALLARGS)); + } + else + { + free_json(argjson); + return(clonestr("{\"error\":\"cant find passphrase in decrypted json\"}")); + } + } + else + { + free(decryptstr); + return(clonestr("{\"error\":\"cant parse decrypted json\"}")); + } + } + if ( passphrase != 0 && passphrase[0] != 0 ) + { + SuperNET_setkeys(myinfo,passphrase,(int32_t)strlen(passphrase),1); + if ( (str= SuperNET_encryptjson(IGUANA_CALLARGS,password,permanentfile,passphrase)) != 0 ) + free(str); + return(SuperNET_activehandle(IGUANA_CALLARGS)); + } + else return(clonestr("{\"error\":\"need passphrase\"}")); + printf("logged into (%s) %s %s\n",myinfo->myaddr.NXTADDR,myinfo->myaddr.BTC,myinfo->myaddr.BTCD); + return(SuperNET_activehandle(IGUANA_CALLARGS)); +} + #include "../includes/iguana_apiundefs.h" diff --git a/iguana/SuperNET.h b/iguana/SuperNET.h index c55e1bf2c..e074df9fa 100644 --- a/iguana/SuperNET.h +++ b/iguana/SuperNET.h @@ -70,7 +70,7 @@ struct supernet_address { bits256 pubkey,iphash,persistent; uint32_t selfipbits,myipbits; int32_t confirmed,totalconfirmed; uint64_t nxt64bits; - char NXTADDR[32]; + char NXTADDR[32],BTC[64],BTCD[64]; }; struct supernet_info @@ -86,6 +86,7 @@ struct supernet_info struct nn_pollfd pfd[SUPERNET_MAXAGENTS]; //struct relay_info active; struct supernet_agent agents[SUPERNET_MAXAGENTS]; queue_t acceptQ; int32_t numagents,numexchanges; struct exchange_info *tradingexchanges[SUPERNET_MAXEXCHANGES]; + char handle[1024]; }; /*struct supernet_endpoint @@ -118,7 +119,7 @@ struct category_info extern struct category_info *Categories; struct category_msg { struct queueitem DL; struct tai t; uint64_t remoteipbits; int32_t len; uint8_t msg[]; }; -struct exchange_quote { uint64_t satoshis,orderid,offerNXT; double price,volume; uint32_t timestamp,val; }; +struct exchange_quote { uint64_t satoshis,orderid,offerNXT,exchangebits; double price,volume; uint32_t timestamp,val; }; void expand_epbits(char *endpoint,struct endpoint epbits); struct endpoint calc_epbits(char *transport,uint32_t ipbits,uint16_t port,int32_t type); @@ -162,6 +163,7 @@ struct category_chain *category_chain_functions(struct supernet_info *myinfo,bit void category_init(struct supernet_info *myinfo); char *SuperNET_keysinit(struct supernet_info *myinfo,char *jsonstr); double instantdex_aveprice(struct supernet_info *myinfo,struct exchange_quote *sortbuf,int32_t max,double *totalvolp,char *base,char *rel,double volume,cJSON *argjson); +void SuperNET_setkeys(struct supernet_info *myinfo,void *pass,int32_t passlen,int32_t dosha256); #endif diff --git a/iguana/SuperNET_keys.c b/iguana/SuperNET_keys.c index 97ebe9a99..a106b66ea 100644 --- a/iguana/SuperNET_keys.c +++ b/iguana/SuperNET_keys.c @@ -28,7 +28,7 @@ bits256 SuperNET_wallet2priv(char *wallet2fname,bits256 wallethash) { char *wallet2str; uint32_t r,i,crc; long allocsize; bits256 wallet2priv; wallet2priv = GENESIS_PRIVKEY; - if ( (wallet2str= OS_filestr(&allocsize,wallet2fname)) != 0 ) + if ( wallet2fname[0] != 0 && (wallet2str= OS_filestr(&allocsize,wallet2fname)) != 0 ) { r = crc = calc_crc32(0,wallet2str,(int32_t)allocsize); r %= 32; @@ -37,7 +37,8 @@ bits256 SuperNET_wallet2priv(char *wallet2fname,bits256 wallethash) vcalc_sha256(0,wallet2priv.bytes,(void *)wallet2str,(int32_t)allocsize); free(wallet2str); //char str[65]; printf("wallet2priv.(%s) from.(%s) crc.%u and passphrase r.%d len.%ld\n",bits256_str(str,wallet2priv),wallet2fname,crc,r,allocsize); - } else printf("SuperNET_wallet2priv cant open (%s)\n",wallet2fname); + } else if ( wallet2fname[0] != 0 ) + printf("SuperNET_wallet2priv cant open (%s)\n",wallet2fname); return(wallet2priv); } @@ -58,7 +59,7 @@ char *SuperNET_parsemainargs(struct supernet_info *myinfo,bits256 *wallethashp,b printf("ARGSTR.(%s)\n",argjsonstr); if ( jobj(json,"numhelpers") != 0 ) IGUANA_NUMHELPERS = juint(json,"numhelpers"); - if ( (secret= jstr(json,"wallet")) != 0 ) + if ( (secret= jstr(json,"passphrase")) != 0 ) { len = (int32_t)strlen(secret); if ( is_hexstr(secret,0) != 0 && len == 128 ) @@ -68,7 +69,7 @@ char *SuperNET_parsemainargs(struct supernet_info *myinfo,bits256 *wallethashp,b } else vcalc_sha256(0,secretbuf,(void *)secret,len), len = sizeof(bits256); memcpy(wallethash.bytes,secretbuf,sizeof(wallethash)); //printf("wallethash.(%s)\n",bits256_str(str,wallethash)); - if ( (wallet2fname= jstr(json,"2fafile")) != 0 ) + if ( (wallet2fname= jstr(json,"permanentfile")) != 0 ) wallet2priv = SuperNET_wallet2priv(wallet2fname,wallethash); } exchanges = jarray(&n,json,"exchanges"); @@ -77,7 +78,8 @@ char *SuperNET_parsemainargs(struct supernet_info *myinfo,bits256 *wallethashp,b free_json(json); } } - exchanges777_init(myinfo,exchanges,0); + if ( exchanges != 0 ) + exchanges777_init(myinfo,exchanges,0); *wallethashp = wallethash, *wallet2privp = wallet2priv; return(coinargs); } @@ -122,7 +124,7 @@ int32_t SuperNET_savejsonfile(char *fname,bits256 privkey,bits256 destpubkey,cJS //sprintf(fname,"confs/iguana.%llu",(long long)wallet2shared.txid); if ( (ciphered= SuperNET_cipher(0,0,json,0,privkey,destpubkey,confstr)) != 0 ) { - //printf("save (%s) <- (%s)\n",fname,ciphered); + printf("save (%s) <- (%s)\n",fname,confstr); if ( (fp= fopen(fname,"wb")) != 0 ) { fwrite(ciphered,1,strlen(ciphered)+1,fp); @@ -188,7 +190,7 @@ cJSON *SuperNET_decryptedjson(char *passphrase,int32_t passsize,bits256 walletha wallet2shared = SuperNET_wallet2shared(wallethash,wallet2priv); wallet2pub = curve25519(wallet2shared,curve25519_basepoint9()); sprintf(fname,"confs/%s",bits256_str(str,wallet2pub)); - //printf("fname.(%s) wallet2shared.%s\n",fname,bits256_str(str,wallet2pub)); + printf("fname.(%s) wallet2shared.%s\n",fname,bits256_str(str,wallet2pub)); if ( (confstr= OS_filestr(&allocsize,fname)) != 0 ) { if ( (filejson= cJSON_Parse(confstr)) != 0 ) @@ -224,7 +226,7 @@ cJSON *SuperNET_decryptedjson(char *passphrase,int32_t passsize,bits256 walletha return(msgjson); } -int32_t SuperNET_encryptjson(char *destfname,char *passphrase,int32_t passsize,char *fname2fa,int32_t fnamesize,cJSON *argjson) +int32_t _SuperNET_encryptjson(char *destfname,char *passphrase,int32_t passsize,char *fname2fa,int32_t fnamesize,cJSON *argjson) { bits256 wallethash,wallet2priv,wallet2shared,wallet2pub; char str[65]; wallethash = wallet2priv = GENESIS_PRIVKEY; @@ -233,7 +235,7 @@ int32_t SuperNET_encryptjson(char *destfname,char *passphrase,int32_t passsize,c wallethash = SuperNET_linehash(passphrase); SuperNET_linehash(fname2fa); // maps special chars wallet2priv = SuperNET_wallet2priv(fname2fa,wallethash); - //char str2[65]; printf("ENCRYPT.[%s %s] (%s) 2.%s\n",passphrase,fname2fa,bits256_str(str,wallethash),bits256_str(str2,wallet2priv)); + char str2[65]; printf("ENCRYPT.[%s %s] (%s) 2.%s\n",passphrase,fname2fa,bits256_str(str,wallethash),bits256_str(str2,wallet2priv)); wallet2shared = SuperNET_wallet2shared(wallethash,wallet2priv); wallet2pub = curve25519(wallet2shared,curve25519_basepoint9()); sprintf(destfname,"confs/%s",bits256_str(str,wallet2pub)); @@ -242,20 +244,37 @@ int32_t SuperNET_encryptjson(char *destfname,char *passphrase,int32_t passsize,c return(0); } +void SuperNET_setkeys(struct supernet_info *myinfo,void *pass,int32_t passlen,int32_t dosha256) +{ + char pubkeystr[128]; uint8_t pubkey33[33]; bits256 hash; + if ( dosha256 != 0 ) + myinfo->myaddr.nxt64bits = conv_NXTpassword(myinfo->persistent_priv.bytes,myinfo->myaddr.persistent.bytes,pass,passlen); + else + { + myinfo->myaddr.persistent = curve25519(myinfo->persistent_priv,curve25519_basepoint9()); + vcalc_sha256(0,hash.bytes,myinfo->myaddr.persistent.bytes,32); + myinfo->myaddr.nxt64bits = hash.txid; + } + RS_encode(myinfo->myaddr.NXTADDR,myinfo->myaddr.nxt64bits); + btc_priv2pub(pubkey33,myinfo->persistent_priv.bytes); + init_hexbytes_noT(pubkeystr,pubkey33,33); + btc_coinaddr(myinfo->myaddr.BTC,0,pubkeystr); + btc_coinaddr(myinfo->myaddr.BTCD,60,pubkeystr); +} + void SuperNET_parsemyinfo(struct supernet_info *myinfo,cJSON *msgjson) { - char *ipaddr,*secret,str[65]; bits256 checkhash,acct; + char *ipaddr,*secret,str[65]; bits256 checkhash; if ( msgjson != 0 ) { if ( (ipaddr= jstr(msgjson,"ipaddr")) != 0 && is_ipaddr(ipaddr) != 0 ) strcpy(myinfo->ipaddr,ipaddr); - if ( (secret= jstr(msgjson,"secret")) != 0 ) - { - myinfo->myaddr.nxt64bits = conv_NXTpassword(myinfo->persistent_priv.bytes,myinfo->myaddr.persistent.bytes,(uint8_t *)secret,(int32_t)strlen(secret)); - } + if ( (secret= jstr(msgjson,"passphrase")) != 0 ) + SuperNET_setkeys(myinfo,secret,(int32_t)strlen(secret),1); else { myinfo->persistent_priv = jbits256(msgjson,"persistent_priv"); + SuperNET_setkeys(myinfo,myinfo->persistent_priv.bytes,sizeof(myinfo->persistent_priv),0); if ( bits256_nonz(myinfo->persistent_priv) == 0 ) { printf("null persistent_priv? generate new one\n"); @@ -271,13 +290,8 @@ void SuperNET_parsemyinfo(struct supernet_info *myinfo,cJSON *msgjson) } else printf("persistent VALIDATED persistentpub.(%s)\n",bits256_str(str,checkhash)); } if ( bits256_nonz(myinfo->persistent_priv) == 0 ) - { OS_randombytes(myinfo->persistent_priv.bytes,sizeof(myinfo->persistent_priv)); - myinfo->myaddr.persistent = curve25519(myinfo->persistent_priv,curve25519_basepoint9()); - } - vcalc_sha256(0,acct.bytes,(void *)myinfo->myaddr.persistent.bytes,sizeof(bits256)); - myinfo->myaddr.nxt64bits = acct.txid; - RS_encode(myinfo->myaddr.NXTADDR,myinfo->myaddr.nxt64bits); + SuperNET_setkeys(myinfo,myinfo->persistent_priv.bytes,sizeof(myinfo->persistent_priv),0); } char *SuperNET_keysinit(struct supernet_info *myinfo,char *argjsonstr) @@ -307,7 +321,7 @@ char *SuperNET_keysinit(struct supernet_info *myinfo,char *argjsonstr) OS_randombytes((void *)&r,sizeof(r)); jadd64bits(json,"rand",r); //printf("call SuperNET_encryptjson\n"); - SuperNET_encryptjson(destfname,passphrase,sizeof(passphrase),fname2fa,sizeof(fname2fa),json); + _SuperNET_encryptjson(destfname,passphrase,sizeof(passphrase),fname2fa,sizeof(fname2fa),json); //printf("save.(%s)\n",jprint(json,0)); free_json(json); } @@ -342,20 +356,20 @@ char *SuperNET_keysinit(struct supernet_info *myinfo,char *argjsonstr) #include "../includes/iguana_apidefs.h" #include "../includes/iguana_apideclares.h" -THREE_STRINGS(InstantDEX,encryptjson,passphrase,permanentfile,anything) +THREE_STRINGS(SuperNET,encryptjson,password,permanentfile,anything) { char destfname[4096],pass[8192],fname2[1023]; cJSON *argjson,*retjson = cJSON_CreateObject(); - safecopy(pass,passphrase,sizeof(pass)); + safecopy(pass,password,sizeof(pass)); safecopy(fname2,permanentfile,sizeof(fname2)); argjson = jduplicate(json); //printf("argjson.(%s)\n",jprint(argjson,0)); jdelete(argjson,"agent"); jdelete(argjson,"method"); - jdelete(argjson,"passphrase"); + jdelete(argjson,"password"); jdelete(argjson,"permanentfile"); jdelete(argjson,"timestamp"); jdelete(argjson,"tag"); - if ( SuperNET_encryptjson(destfname,pass,sizeof(pass),fname2,sizeof(fname2),argjson) == 0 ) + if ( _SuperNET_encryptjson(destfname,pass,sizeof(pass),fname2,sizeof(fname2),argjson) == 0 ) { jaddstr(retjson,"result","success"); jaddstr(retjson,"filename",destfname); @@ -364,10 +378,10 @@ THREE_STRINGS(InstantDEX,encryptjson,passphrase,permanentfile,anything) return(jprint(retjson,1)); } -TWO_STRINGS(InstantDEX,decryptjson,passphrase,permanentfile) +TWO_STRINGS(SuperNET,decryptjson,password,permanentfile) { char pass[8192],fname2[1023]; cJSON *retjson,*obj; bits256 wallethash,wallet2priv; - safecopy(pass,passphrase,sizeof(pass)); + safecopy(pass,password,sizeof(pass)); safecopy(fname2,permanentfile,sizeof(fname2)); wallethash = wallet2priv = GENESIS_PRIVKEY; if ( strlen(pass) == sizeof(wallethash)*2 && is_hexstr(pass,(int32_t)sizeof(bits256)*2) > 0 ) diff --git a/iguana/exchanges/PAX.c b/iguana/exchanges/PAX.c new file mode 100755 index 000000000..fa2536654 --- /dev/null +++ b/iguana/exchanges/PAX.c @@ -0,0 +1,110 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "PAX" +#define UPDATE PAX ## _price +#define SUPPORTS PAX ## _supports +#define SIGNPOST PAX ## _signpost +#define TRADE PAX ## _trade +#define ORDERSTATUS PAX ## _orderstatus +#define CANCELORDER PAX ## _cancelorder +#define OPENORDERS PAX ## _openorders +#define TRADEHISTORY PAX ## _tradehistory +#define BALANCES PAX ## _balances +#define PARSEBALANCE PAX ## _parsebalance +#define WITHDRAW PAX ## _withdraw +#define CHECKBALANCE PAX ## _checkbalance +#define ALLPAIRS PAX ## _allpairs +#define FUNCS PAX ## _funcs +#define BASERELS PAX ## _baserels + +#include "../peggy.h" + +char *peggy_bases[64] = +{ + "BTCD", "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies + "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", + "BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced + "XAUUSD", "XAGUSD", "XPTUSD", "XPDUSD", "COPPER", "NGAS", "UKOIL", "USOIL", // USD priced + "BUND", "NAS100", "SPX500", "US30", "EUSTX50", "UK100", "JPN225", "GER30", "SUI30", "AUS200", "HKG33", "XAUUSD", "BTCRUB", "BTCCNY", "BTCUSD" // abstract +}; + +char *ALLPAIRS(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX is not yet\"}")); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + return(0); +} + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert) +{ + return(0); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) +{ + if ( retstrp != 0 ) + *retstrp = clonestr("{\"error\":\"PAX signing is not yet\"}"); + return(cJSON_Parse("{}")); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX parsebalance is not yet\"}")); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(cJSON_Parse("{\"error\":\"PAX balances is not yet\"}")); +} + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + return(0); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX orderstatus is not yet\"}")); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX cancel order is not yet\"}")); +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX open orders is not yet\"}")); +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX tradehistory is not yet\"}")); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"PAX redeem is not yet\"}")); +} + +struct exchange_funcs PAX_funcs = EXCHANGE_FUNCS(PAX,EXCHANGE_NAME); + +#include "exchange_undefs.h" + + diff --git a/iguana/exchanges/ecb.c b/iguana/exchanges/bitcoin.c similarity index 69% rename from iguana/exchanges/ecb.c rename to iguana/exchanges/bitcoin.c index 0b02184bb..614f75598 100755 --- a/iguana/exchanges/ecb.c +++ b/iguana/exchanges/bitcoin.c @@ -13,22 +13,22 @@ * * ******************************************************************************/ -#define EXCHANGE_NAME "ecb" -#define UPDATE ecb ## _price -#define SUPPORTS ecb ## _supports -#define SIGNPOST ecb ## _signpost -#define TRADE ecb ## _trade -#define ORDERSTATUS ecb ## _orderstatus -#define CANCELORDER ecb ## _cancelorder -#define OPENORDERS ecb ## _openorders -#define TRADEHISTORY ecb ## _tradehistory -#define BALANCES ecb ## _balances -#define PARSEBALANCE ecb ## _parsebalance -#define WITHDRAW ecb ## _withdraw -#define CHECKBALANCE ecb ## _checkbalance -#define ALLPAIRS ecb ## _allpairs -#define FUNCS ecb ## _funcs -#define BASERELS ecb ## _baserels +#define EXCHANGE_NAME "bitcoin" +#define UPDATE bitcoin ## _price +#define SUPPORTS bitcoin ## _supports +#define SIGNPOST bitcoin ## _signpost +#define TRADE bitcoin ## _trade +#define ORDERSTATUS bitcoin ## _orderstatus +#define CANCELORDER bitcoin ## _cancelorder +#define OPENORDERS bitcoin ## _openorders +#define TRADEHISTORY bitcoin ## _tradehistory +#define BALANCES bitcoin ## _balances +#define PARSEBALANCE bitcoin ## _parsebalance +#define WITHDRAW bitcoin ## _withdraw +#define CHECKBALANCE bitcoin ## _checkbalance +#define ALLPAIRS bitcoin ## _allpairs +#define FUNCS bitcoin ## _funcs +#define BASERELS bitcoin ## _baserels static char *BASERELS[][2] = { {"btc","nxt"}, {"btc","btcd"}, {"btc","ltc"}, {"btc","vrc"}, {"btc","doge"} }; #include "exchange_supports.h" @@ -45,18 +45,18 @@ double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchang cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) { if ( retstrp != 0 ) - *retstrp = clonestr("{\"error\":\"ecb is readonly data source\"}"); + *retstrp = clonestr("{\"error\":\"bitcoin is not yet\"}"); return(cJSON_Parse("{}")); } char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) { - return(clonestr("{\"error\":\"ecb is readonly data source\"}")); + return(clonestr("{\"error\":\"bitcoin is not yet\"}")); } cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) { - return(cJSON_Parse("{\"error\":\"ecb is readonly data source\"}")); + return(cJSON_Parse("{\"error\":\"bitcoin is not yet\"}")); } uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) @@ -66,29 +66,29 @@ uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,cha char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) { - return(clonestr("{\"error\":\"ecb is readonly data source\"}")); + return(clonestr("{\"error\":\"bitcoin is not yet\"}")); } char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) { - return(clonestr("{\"error\":\"ecb is readonly data source\"}")); + return(clonestr("{\"error\":\"bitcoin is not yet\"}")); } char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) { - return(clonestr("{\"error\":\"ecb is readonly data source\"}")); + return(clonestr("{\"error\":\"bitcoin is not yet\"}")); } char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) { - return(clonestr("{\"error\":\"ecb is readonly data source\"}")); + return(clonestr("{\"error\":\"bitcoin is not yet\"}")); } char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) { - return(clonestr("{\"error\":\"ecb is readonly data source\"}")); + return(clonestr("{\"error\":\"bitcoin is not yet\"}")); } -struct exchange_funcs ecb_funcs = EXCHANGE_FUNCS(ecb,EXCHANGE_NAME); +struct exchange_funcs bitcoin_funcs = EXCHANGE_FUNCS(bitcoin,EXCHANGE_NAME); #include "exchange_undefs.h" diff --git a/iguana/exchanges/yahoo.c b/iguana/exchanges/jumblr.c similarity index 61% rename from iguana/exchanges/yahoo.c rename to iguana/exchanges/jumblr.c index 0d1f5afa1..ba3cb4209 100755 --- a/iguana/exchanges/yahoo.c +++ b/iguana/exchanges/jumblr.c @@ -13,24 +13,24 @@ * * ******************************************************************************/ -#define EXCHANGE_NAME "yahoo" -#define UPDATE yahoo ## _price -#define SUPPORTS yahoo ## _supports -#define SIGNPOST yahoo ## _signpost -#define TRADE yahoo ## _trade -#define ORDERSTATUS yahoo ## _orderstatus -#define CANCELORDER yahoo ## _cancelorder -#define OPENORDERS yahoo ## _openorders -#define TRADEHISTORY yahoo ## _tradehistory -#define BALANCES yahoo ## _balances -#define PARSEBALANCE yahoo ## _parsebalance -#define WITHDRAW yahoo ## _withdraw -#define CHECKBALANCE yahoo ## _checkbalance -#define ALLPAIRS yahoo ## _allpairs -#define FUNCS yahoo ## _funcs -#define BASERELS yahoo ## _baserels +#define EXCHANGE_NAME "jumblr" +#define UPDATE jumblr ## _price +#define SUPPORTS jumblr ## _supports +#define SIGNPOST jumblr ## _signpost +#define TRADE jumblr ## _trade +#define ORDERSTATUS jumblr ## _orderstatus +#define CANCELORDER jumblr ## _cancelorder +#define OPENORDERS jumblr ## _openorders +#define TRADEHISTORY jumblr ## _tradehistory +#define BALANCES jumblr ## _balances +#define PARSEBALANCE jumblr ## _parsebalance +#define WITHDRAW jumblr ## _withdraw +#define CHECKBALANCE jumblr ## _checkbalance +#define ALLPAIRS jumblr ## _allpairs +#define FUNCS jumblr ## _funcs +#define BASERELS jumblr ## _baserels -static char *BASERELS[][2] = { {"EUR","USD"},{"USD","JPY"},{"GBP","USD"},{"EUR","GBP"},{"USD","CHF"},{"AUD","NZD"},{"CAD","CHF"},{"CHF","JPY"},{"EUR","AUD"},{"EUR","CAD"},{"EUR","JPY"},{"EUR","CHF"},{"USD","CAD"},{"AUD","USD"},{"GBP","JPY"},{"AUD","CAD"},{"AUD","CHF"},{"AUD","JPY"},{"EUR","NOK"},{"EUR","NZD"},{"GBP","CAD"},{"GBP","CHF"},{"NZD","JPY"},{"NZD","USD"},{"USD","NOK"},{"USD","SEK"} }; +static char *BASERELS[][2] = { {"btc","nxt"}, {"btc","btcd"}, {"btc","ltc"}, {"btc","vrc"}, {"btc","doge"} }; #include "exchange_supports.h" double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert) @@ -45,18 +45,18 @@ double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchang cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) { if ( retstrp != 0 ) - *retstrp = clonestr("{\"error\":\"yahoo is readonly data source\"}"); + *retstrp = clonestr("{\"error\":\"jumblr is not yet\"}"); return(cJSON_Parse("{}")); } char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) { - return(clonestr("{\"error\":\"yahoo is readonly data source\"}")); + return(clonestr("{\"error\":\"jumblr is not yet\"}")); } cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) { - return(cJSON_Parse("{\"error\":\"yahoo is readonly data source\"}")); + return(cJSON_Parse("{\"error\":\"jumblr is not yet\"}")); } uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) @@ -66,29 +66,29 @@ uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,cha char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) { - return(clonestr("{\"error\":\"yahoo is readonly data source\"}")); + return(clonestr("{\"error\":\"jumblr is not yet\"}")); } char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) { - return(clonestr("{\"error\":\"yahoo is readonly data source\"}")); + return(clonestr("{\"error\":\"jumblr is not yet\"}")); } char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) { - return(clonestr("{\"error\":\"yahoo is readonly data source\"}")); + return(clonestr("{\"error\":\"jumblr is not yet\"}")); } char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) { - return(clonestr("{\"error\":\"yahoo is readonly data source\"}")); + return(clonestr("{\"error\":\"jumblr is not yet\"}")); } char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) { - return(clonestr("{\"error\":\"yahoo is readonly data source\"}")); + return(clonestr("{\"error\":\"jumblr is not yet\"}")); } -struct exchange_funcs yahoo_funcs = EXCHANGE_FUNCS(yahoo,EXCHANGE_NAME); +struct exchange_funcs jumblr_funcs = EXCHANGE_FUNCS(jumblr,EXCHANGE_NAME); #include "exchange_undefs.h" diff --git a/iguana/exchanges/nxtae.c b/iguana/exchanges/nxtae.c index 0cdb065f3..10d17e05c 100755 --- a/iguana/exchanges/nxtae.c +++ b/iguana/exchanges/nxtae.c @@ -33,141 +33,70 @@ static char *BASERELS[][2] = { {"btc","nxt"}, {"btc","btcd"}, {"btc","ltc"}, {"btc","vrc"}, {"btc","doge"} }; #include "exchange_supports.h" -double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert) +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert) { - char url[1024],lrel[16],lbase[16]; - strcpy(lrel,rel), strcpy(lbase,base); - tolowercase(lrel), tolowercase(lbase); - sprintf(url,"http://api.quadrigacx.com/v2/order_book?book=%s_%s",lbase,lrel); - return(exchanges777_standardprices(exchange,commission,base,rel,url,quotes,0,0,maxdepth,0,invert)); + double bid,ask,bids[64],asks[64],highs[64],lows[64]; int32_t numbids,numasks,c; char name[32]; + if ( fxcm_ensure() == 0 ) + { + strcpy(name,base), strcat(name,rel), touppercase(name); + if ( (c= strsearch(FXCM_contracts,num_FXCM,name)) >= 0 ) + { + prices777_fxcm(bids,asks,highs,lows); + numbids = numasks = 0; + bid = exchange_setquote(bidasks,&numbids,&numasks,0,invert,bids[c],1,commission,0,(uint32_t)time(NULL),0); + ask = exchange_setquote(bidasks,&numbids,&numasks,1,invert,asks[c],1,commission,0,(uint32_t)time(NULL),0); + if ( bid > SMALLVAL && ask > SMALLVAL ) + return((bid + ask) * .5); + } + } + return(0); } cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) { - char url[1024],req[1024],md5secret[128],tmp[1024],dest[1025],hdr1[512],hdr2[512],hdr3[512],hdr4[512],*sig,*data = 0; - cJSON *json; uint64_t nonce; - hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; - json = 0; - nonce = exchange_nonce(exchange) * 1000 + ((uint64_t)OS_milliseconds() % 1000); - sprintf(tmp,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey); - calc_md5(md5secret,exchange->apisecret,(int32_t)strlen(exchange->apisecret)); - if ( (sig= hmac_sha256_str(dest,md5secret,(int32_t)strlen(md5secret),tmp)) != 0 ) - { - sprintf(req,"{\"key\":\"%s\",%s\"nonce\":%llu,\"signature\":\"%s\"}",exchange->apikey,payload,(long long)nonce,sig); - sprintf(hdr1,"Content-Type:application/json"); - sprintf(hdr2,"charset=utf-8"); - sprintf(hdr3,"Content-Length:%ld",(long)strlen(req)); - sprintf(url,"https://api.quadrigacx.com/v2/%s",path); - if ( dotrade == 0 ) - data = exchange_would_submit(req,hdr1,hdr2,hdr3,hdr4); - else if ( (data= curl_post(&exchange->cHandle,url,0,req,hdr1,hdr2,hdr3,hdr4)) != 0 ) - json = cJSON_Parse(data); - } if ( retstrp != 0 ) - *retstrp = data; - else if ( data != 0 ) - free(data); - return(json); + *retstrp = clonestr("{\"error\":\"nxtae is readonly data source\"}"); + return(cJSON_Parse("{}")); } char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) { - //[{"btc_available":"0.00000000","btc_reserved":"0.00000000","btc_balance":"0.00000000","cad_available":"0.00","cad_reserved":"0.00","cad_balance":"0.00","usd_available":"0.00","usd_reserved":"0.00","usd_balance":"0.00","xau_available":"0.000000","xau_reserved":"0.000000","xau_balance":"0.000000","fee":"0.5000"}] - char field[128],*str,*itemstr = 0; cJSON *obj; double reserv,total; - *balancep = 0.; - strcpy(field,coinstr); - tolowercase(field); - strcat(field,"_available"); - if ( argjson != 0 && (str= jstr(argjson,field)) != 0 ) - { - *balancep = jdouble(argjson,field); - strcpy(field,coinstr), tolowercase(field), strcat(field,"_reserved"); - reserv = jdouble(argjson,field); - strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance"); - total = jdouble(argjson,field); - obj = cJSON_CreateObject(); - jaddnum(obj,"balance",*balancep); - jaddnum(obj,"locked_balance",reserv); - jaddnum(obj,"total",total); - itemstr = jprint(obj,1); - } - if ( itemstr == 0 ) - return(clonestr("{\"error\":\"cant find coin balance\"}")); - return(itemstr); + return(clonestr("{\"error\":\"nxtae is readonly data source\"}")); } cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) { - return(SIGNPOST(&exchange->cHandle,1,0,exchange,"","balance")); + return(cJSON_Parse("{\"error\":\"nxtae is readonly data source\"}")); } -#include "checkbalance.c" - uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) { - char payload[1024],pairstr[64],*extra,*path; cJSON *json; uint64_t txid = 0; - if ( (extra= *retstrp) != 0 ) - *retstrp = 0; - if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel,argjson)) == 0 ) - { - printf("cant find baserel (%s/%s)\n",base,rel); - return(0); - } - path = (dir > 0) ? "buy" : "sell"; - //key - API key - //signature - signature - //nonce - nonce - //amount - amount of major currency - //price - price to buy at - //book - optional, if not specified, will default to btc_cad - sprintf(payload,"\"amount\":%.6f,\"price\":%.3f,\"book\":\"%s_%s\",",volume,price,base,rel); - if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,path)) != 0 ) - { - // parse json and set txid - free_json(json); - } - return(txid); + return(0); } char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) { - char buf[64]; - sprintf(buf,"\"id\":%llu,",(long long)quoteid); - return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,buf,"lookup_order"),1)); + return(clonestr("{\"error\":\"nxtae is readonly data source\"}")); } char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) { - char buf[64]; - sprintf(buf,"\"id\":%llu,",(long long)quoteid); - return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,buf,"cancel_order"),1)); + return(clonestr("{\"error\":\"nxtae is readonly data source\"}")); } char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) { - return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"","open_orders"),1)); + return(clonestr("{\"error\":\"nxtae is readonly data source\"}")); } char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) { - return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"","user_transactions"),1)); + return(clonestr("{\"error\":\"nxtae is readonly data source\"}")); } char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) { - uint64_t txid,assetid,assetoshis; cJSON *retjson = cJSON_CreateObject(); - if ( is_validNXT(destaddr) < 0 ) - jaddstr(retjson,"error","invalid NXT address"); - else if ( (assetid= is_MGW_asset(base)) == 0 ) - jaddstr(retjson,"error","invalid MGW asset"); - else if ( is_validNXT_amount(base) < 0 ) - jaddstr(retjson,"error","invalid NXT asset"); - else if ( (txid= MGW_redeem(passphrase,assetid,assetoshis,destaddr)) != 0 ) - { - jaddstr(retjson,"result","success"); - jadd64bits(retjson,"redeemtxid",txid); - } else jaddstr(retjson,"error","couldnt submit MGW redeem"); - return(jprint(retjson,1)); + return(clonestr("{\"error\":\"nxtae is readonly data source\"}")); } struct exchange_funcs nxtae_funcs = EXCHANGE_FUNCS(nxtae,EXCHANGE_NAME); diff --git a/iguana/exchanges/truefx.c b/iguana/exchanges/truefx.c index aaae4cb28..03af6de98 100755 --- a/iguana/exchanges/truefx.c +++ b/iguana/exchanges/truefx.c @@ -77,7 +77,19 @@ uint64_t prices777_truefx(char *reqbase,char *reqrel,uint64_t *millistampp,doubl } if ( str != 0 ) { - //printf("(%s) -> (%s)\n",url,str); + printf("(%s) -> (%s)\n",url,str); + /*EUR/USD,1454354222037,1.08,997,1.09,000,1.08142,1.09130,1.08333 + USD/JPY,1454354221120,121.,049,121.,053,120.676,121.496,121.289 + GBP/USD,1454354221048,1.44,242,1.44,254,1.42280,1.44305,1.42483 + EUR/GBP,1454354220966,0.75,561,0.75,567,0.75517,0.76238,0.76031 + USD/CHF,1454354221288,1.01,866,1.01,876,1.01553,1.02514,1.02209 + EUR/JPY,1454354221693,131.,937,131.,944,131.224,132.003,131.381 + EUR/CHF,1454354221028,1.11,027,1.11,032,1.10542,1.11173,1.10705 + USD/CAD,1454354221764,1.39,473,1.39,479,1.39437,1.40627,1.39729 + AUD/USD,1454354221515,0.70,955,0.70,961,0.70421,0.70970,0.70817 + GBP/JPY,1454354221581,174.,602,174.,621,172.408,174.730,172.805 + +*/ while ( str[n + 0] != 0 && str[n] != '\n' && str[n] != '\r' ) { for (i=jpyflag=0; str[n + i]!=' '&&str[n + i]!='\n'&&str[n + i]!='\r'&&str[n + i]!=0; i++) @@ -94,7 +106,7 @@ uint64_t prices777_truefx(char *reqbase,char *reqrel,uint64_t *millistampp,doubl memcpy(base,str+n,3), base[3] = 0; memcpy(rel,str+n+4,3), rel[3] = 0; str[n + i] = 0; - //printf("str.(%s) (%s/%s) %d n.%d i.%d\n",str+n,base,rel,str[n],n,i); + printf("str.(%s) (%s/%s) %d n.%d i.%d\n",str+n,base,rel,str[n],n,i); sprintf(buf,"[%s]",str+n+7+1); n += i + 1; if ( (array= cJSON_Parse(buf)) != 0 ) diff --git a/iguana/exchanges/unconf.c b/iguana/exchanges/unconf.c new file mode 100755 index 000000000..d0cea56ab --- /dev/null +++ b/iguana/exchanges/unconf.c @@ -0,0 +1,94 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "unconf" +#define UPDATE unconf ## _price +#define SUPPORTS unconf ## _supports +#define SIGNPOST unconf ## _signpost +#define TRADE unconf ## _trade +#define ORDERSTATUS unconf ## _orderstatus +#define CANCELORDER unconf ## _cancelorder +#define OPENORDERS unconf ## _openorders +#define TRADEHISTORY unconf ## _tradehistory +#define BALANCES unconf ## _balances +#define PARSEBALANCE unconf ## _parsebalance +#define WITHDRAW unconf ## _withdraw +#define CHECKBALANCE unconf ## _checkbalance +#define ALLPAIRS unconf ## _allpairs +#define FUNCS unconf ## _funcs +#define BASERELS unconf ## _baserels + +static char *BASERELS[][2] = { {"btc","nxt"}, {"btc","btcd"}, {"btc","ltc"}, {"btc","vrc"}, {"btc","doge"} }; +#include "exchange_supports.h" + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert) +{ + char url[1024],lrel[16],lbase[16]; + strcpy(lrel,rel), strcpy(lbase,base); + tolowercase(lrel), tolowercase(lbase); + sprintf(url,"http://api.quadrigacx.com/v2/order_book?book=%s_%s",lbase,lrel); + return(exchanges777_standardprices(exchange,commission,base,rel,url,quotes,0,0,maxdepth,0,invert)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) +{ + if ( retstrp != 0 ) + *retstrp = clonestr("{\"error\":\"unconf is read only\"}"); + return(cJSON_Parse("{}")); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"unconf is read only\"}")); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(cJSON_Parse("{\"error\":\"unconf is read only\"}")); +} + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + return(0); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + return(clonestr("{\"error\":\"unconf is read only\"}")); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + return(clonestr("{\"error\":\"unconf is read only\"}")); +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"unconf is read only\"}")); +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"unconf is read only\"}")); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"unconf is read only\"}")); +} + +struct exchange_funcs unconf_funcs = EXCHANGE_FUNCS(unconf,EXCHANGE_NAME); + +#include "exchange_undefs.h" diff --git a/iguana/exchanges777.h b/iguana/exchanges777.h index fd8b7c18c..76748f042 100755 --- a/iguana/exchanges777.h +++ b/iguana/exchanges777.h @@ -48,7 +48,8 @@ struct exchange_info struct exchange_funcs issue; char name[16],apikey[MAX_JSON_FIELD],apisecret[MAX_JSON_FIELD],tradepassword[MAX_JSON_FIELD],userid[MAX_JSON_FIELD]; uint32_t exchangeid,pollgap,lastpoll; - uint64_t lastnonce; double commission; + uint64_t lastnonce,exchangebits; double commission; + void *privatedata; CURL *cHandle; queue_t requestQ,pricesQ,pendingQ[2],tradebotsQ; }; @@ -79,7 +80,12 @@ char *exchanges777_unmonitor(struct exchange_info *exchange,char *base,char *rel void tradebot_timeslice(struct exchange_info *exchange,void *bot); 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 *exchanges777_baserelfind(struct exchange_info *exchange,char *base,char *rel,int32_t func); +struct exchange_info *exchanges777_find(char *exchangestr); void prices777_processprice(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth); +double truefx_price(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert); +double fxcm_price(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert); +double instaforex_price(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth,double commission,cJSON *argjson,int32_t invert); + #endif diff --git a/iguana/iguana.sources b/iguana/iguana.sources index efb83c985..b2fd43338 100755 --- a/iguana/iguana.sources +++ b/iguana/iguana.sources @@ -1,3 +1,3 @@ #iguana_html.c -SOURCES := SuperNET.c SuperNET_keys.c SuperNET_category.c SuperNET_hexmsg.c iguana_exchanges.c iguana_tradebots.c iguana_instantdex.c pangea_api.c pangea_bets.c cards777.c pangea_summary.c pangea_json.c pangea_hand.c poker.c ramchain_api.c iguana_tx.c iguana_wallet.c iguana_pubkeys.c iguana_recv.c iguana_bundles.c iguana_msg.c iguana_rpc.c iguana777.c iguana_chains.c iguana_peers.c iguana_accept.c iguana_bitmap.c iguana_init.c iguana_ramchain.c iguana_blocks.c iguana_json.c main.c +SOURCES := SuperNET.c SuperNET_keys.c SuperNET_category.c SuperNET_hexmsg.c peggy.c peggy_consensus.c peggy_price.c peggy_update.c peggy_accts.c peggy_tx.c peggy_txind.c peggy_ramkv.c peggy_serdes.c iguana_exchanges.c iguana_tradebots.c iguana_instantdex.c pangea_api.c pangea_bets.c cards777.c pangea_summary.c pangea_json.c pangea_hand.c poker.c ramchain_api.c iguana_tx.c iguana_wallet.c iguana_pubkeys.c iguana_recv.c iguana_bundles.c iguana_msg.c iguana_rpc.c iguana777.c iguana_chains.c iguana_peers.c iguana_accept.c iguana_bitmap.c iguana_init.c iguana_ramchain.c iguana_blocks.c iguana_json.c main.c diff --git a/iguana/iguana777.c b/iguana/iguana777.c index f4febc48b..a06b1f67e 100755 --- a/iguana/iguana777.c +++ b/iguana/iguana777.c @@ -559,16 +559,6 @@ void iguana_coins(void *arg) } } -int32_t opreturns_init(uint32_t blocknum,uint32_t blocktimestamp,char *path) -{ - printf("opreturns_init not yet\n"); - return(-1); -} - -void peggy() -{ - printf("peggy not yet\n"); -} char *busdata_sync(uint32_t *noncep,char *jsonstr,char *broadcastmode,char *destNXTaddr) { printf("busdata_sync.(%s)\n",jsonstr); diff --git a/iguana/iguana_exchanges.c b/iguana/iguana_exchanges.c index dfb47cbc0..52bc8df9f 100755 --- a/iguana/iguana_exchanges.c +++ b/iguana/iguana_exchanges.c @@ -14,14 +14,13 @@ ******************************************************************************/ #include "exchanges777.h" +#include "peggy.h" #define EXCHANGE777_DONE 1 #define EXCHANGE777_ISPENDING 2 #define EXCHANGE777_REQUEUE 3 -char *Exchange_names[] = { "poloniex", "bittrex", "btc38", "huobi", "bitstamp", "bitfinex", "btce", "coinbase", "okcoin", "lakebtc", "quadriga", "truefx", "ecb", "instaforex", "fxcm", "yahoo" }; - -struct exchange_info *Exchanges[sizeof(Exchange_names)/sizeof(*Exchange_names)]; +//char *Exchange_names[] = { "poloniex", "bittrex", "btc38", "huobi", "bitstamp", "bitfinex", "btce", "coinbase", "okcoin", "lakebtc", "quadriga", "truefx", "ecb", "instaforex", "fxcm", "yahoo" }; void prices777_processprice(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth) { @@ -443,10 +442,25 @@ int32_t baserel_polarity(char *pairs[][2],int32_t n,char *_base,char *_rel) #include "exchanges/bitstamp.c" #include "exchanges/truefx.c" -#include "exchanges/yahoo.c" +#include "exchanges/PAX.c" #include "exchanges/fxcm.c" #include "exchanges/instaforex.c" -#include "exchanges/ecb.c" + +#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) { @@ -560,10 +574,28 @@ char *exchanges777_process(struct exchange_info *exchange,int32_t *retvalp,struc void exchanges777_loop(void *ptr) { - struct exchange_info *exchange = ptr; - int32_t flag,retval,i; struct exchange_request *req; char *retstr; void *bot; + struct peggy_info *PEGS; struct exchange_info *exchange = ptr; + int32_t flag,retval,i,peggyflag = 0; struct exchange_request *req; char *retstr; void *bot; + if ( strcmp(exchange->name,"PAX") == 0 ) + { + PEGS = calloc(1,sizeof(*PEGS)); + PAX_init(PEGS); + exchange->privatedata = PEGS; + peggyflag = 1; + _crypto_update(PEGS,PEGS->cryptovols,&PEGS->data,1,peggyflag); + PEGS->lastupdate = (uint32_t)time(NULL); + } while ( 1 ) { + if ( peggyflag != 0 ) + { + PAX_idle(PEGS,peggyflag,3); + if ( time(NULL) > PEGS->lastupdate+100 ) + { + _crypto_update(PEGS,PEGS->cryptovols,&PEGS->data,1,peggyflag); + PEGS->lastupdate = (uint32_t)time(NULL); + } + } flag = retval = 0; retstr = 0; if ( (req= queue_dequeue(&exchange->requestQ,0)) != 0 ) @@ -764,16 +796,29 @@ char *exchanges777_Qrequest(struct exchange_info *exchange,int32_t func,char *ba int32_t exchanges777_id(char *exchangestr) { int32_t i; - for (i=0; iname); + if ( strcmp(exchangestr,Exchange_funcs[i]->name) == 0 ) return(i); } //printf("cant find (%s)\n",exchangestr); return(-1); } +struct exchange_info *exchanges777_findbits(uint64_t exchangebits) +{ + int32_t i; + for (i=0; iname); + 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; @@ -784,12 +829,21 @@ struct exchange_info *exchanges777_find(char *exchangestr) struct exchange_info *exchange_create(char *exchangestr,cJSON *argjson) { - struct exchange_funcs funcs[] = + static int didinit; + if ( didinit == 0 ) { - truefx_funcs, ecb_funcs, instaforex_funcs, fxcm_funcs, yahoo_funcs, - poloniex_funcs, bittrex_funcs, btce_funcs, bitfinex_funcs, btc38_funcs, - huobi_funcs, lakebtc_funcs, quadriga_funcs, okcoin_funcs, coinbase_funcs, bitstamp_funcs - }; + int32_t i,j; + for (i=0; iname) == 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); + exit(-1); + } + } + didinit = 1; + } char *key,*secret,*userid,*tradepassword; struct exchange_info *exchange; int32_t i,exchangeid; if ( exchangestr == 0 || exchangestr[0] == 0 ) return(0); @@ -798,18 +852,18 @@ struct exchange_info *exchange_create(char *exchangestr,cJSON *argjson) printf("exchange_create: cant find.(%s)\n",exchangestr); return(0); } - for (i=0; iname) == 0 ) break; } - if ( i == sizeof(funcs)/sizeof(*funcs) ) + if ( i == sizeof(Exchange_funcs)/sizeof(*Exchange_funcs) ) { printf("cant find exchange.(%s)\n",exchangestr); return(0); } exchange = calloc(1,sizeof(*exchange)); - exchange->issue = funcs[i]; + exchange->issue = *Exchange_funcs[i]; iguana_initQ(&exchange->pricesQ,"prices"); iguana_initQ(&exchange->requestQ,"request"); iguana_initQ(&exchange->tradebotsQ,"tradebots"); @@ -817,6 +871,7 @@ struct exchange_info *exchange_create(char *exchangestr,cJSON *argjson) iguana_initQ(&exchange->pendingQ[1],"pending1"); exchange->exchangeid = exchangeid; safecopy(exchange->name,exchangestr,sizeof(exchange->name)); + exchange->exchangebits = stringbits(exchange->name); if ( (exchange->pollgap= juint(argjson,"pollgap")) < EXCHANGES777_MINPOLLGAP ) exchange->pollgap = EXCHANGES777_MINPOLLGAP; if ( (key= jstr(argjson,"apikey")) != 0 || (key= jstr(argjson,"key")) != 0 ) @@ -869,8 +924,8 @@ void exchanges777_init(struct supernet_info *myinfo,cJSON *exchanges,int32_t sle if ( 1 ) { argjson = cJSON_CreateObject(); - for (i=0; iname,sleepflag,argjson,0)) != 0 ) myinfo->tradingexchanges[myinfo->numexchanges++] = exchange; free_json(argjson); } @@ -1000,8 +1055,8 @@ ZERO_ARGS(InstantDEX,allexchanges) { int32_t i; cJSON *retjson,*array; retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); - for (i=0; iname); jadd(retjson,"result",array); return(jprint(retjson,1)); } diff --git a/iguana/iguana_instantdex.c b/iguana/iguana_instantdex.c index 4b6d751e1..6bb7339f3 100755 --- a/iguana/iguana_instantdex.c +++ b/iguana/iguana_instantdex.c @@ -78,7 +78,7 @@ char *instantdex_sendcmd(struct supernet_info *myinfo,cJSON *argjson,char *cmdst } } -int32_t instantdex_updatesources(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 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 update dir.%d numquotes.%d\n",dir,numquotes); @@ -90,6 +90,7 @@ int32_t instantdex_updatesources(struct exchange_quote *sortbuf,int32_t n,int32_ { sortbuf[n] = *quote; sortbuf[n].val = ind; + sortbuf[n].exchangebits = exchange->exchangebits; //printf("sortbuf[%d] <-\n",n*2); if ( ++n >= max ) break; @@ -135,9 +136,9 @@ double instantdex_aveprice(struct supernet_info *myinfo,struct exchange_quote *s for (i=n=0; inumbids > 0 ) - n = instantdex_updatesources(sortbuf,n,max,i,1,active[i]->bidasks,active[i]->numbids); + 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(sortbuf,n,max,i,-1,&active[i]->bidasks[1],active[i]->numasks); + n = instantdex_updatesources(active[i]->exchange,sortbuf,n,max,i,-1,&active[i]->bidasks[1],active[i]->numasks); } //printf("dir.%d %s/%s numX.%d n.%d\n",dir,base,rel,num,n); if ( dir < 0 ) @@ -156,7 +157,7 @@ double instantdex_aveprice(struct supernet_info *myinfo,struct exchange_quote *s } if ( totalvol > 0. ) { - *totalvolp = pricesum; + *totalvolp = totalvol; return(pricesum / totalvol); } } diff --git a/iguana/iguana_json.c b/iguana/iguana_json.c index f6183acfa..88814261d 100755 --- a/iguana/iguana_json.c +++ b/iguana/iguana_json.c @@ -82,6 +82,7 @@ cJSON *SuperNET_helpjson() #define IGUANA_HELP_S(agent,name,str) array = helpjson(IGUANA_ARGS,#agent,#name,helparray(cJSON_CreateArray(),helpitem(#str,"string"))) #define IGUANA_HELP_SS(agent,name,str,str2) array = helpjson(IGUANA_ARGS,#agent,#name,helparray2(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"))) #define IGUANA_HELP_SSS(agent,name,str,str2,str3) array = helpjson(IGUANA_ARGS,#agent,#name,helparray3(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"))) +#define IGUANA_HELP_SSSS(agent,name,str,str2,str3,str4) array = helpjson(IGUANA_ARGS,#agent,#name,helparray4(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#str4,"string"))) #define IGUANA_HELP_SSSD(agent,name,str,str2,str3,amount) array = helpjson(IGUANA_ARGS,#agent,#name,helparray4(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#amount,"float"))) #define IGUANA_HELP_SSSDDD(agent,name,str,str2,str3,amount,val2,val3) array = helpjson(IGUANA_ARGS,#agent,#name,helparray6(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#amount,"float"),helpitem(#val2,"float"),helpitem(#val3,"float"))) #define IGUANA_HELP_SSSIII(agent,name,str,str2,str3,val,val2,val3) array = helpjson(IGUANA_ARGS,#agent,#name,helparray6(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#val,"int"),helpitem(#val2,"int"),helpitem(#val3,"int"))) @@ -91,6 +92,7 @@ cJSON *SuperNET_helpjson() #define IGUANA_HELP_SSHII(agent,name,str,str2,hash,val,val2) array = helpjson(IGUANA_ARGS,#agent,#name,helparray5(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#hash,"hash"),helpitem(#val,"int"),helpitem(#val2,"int"))) #define IGUANA_HELP_SSHHII(agent,name,str,str2,hash,hash2,val,val2) array = helpjson(IGUANA_ARGS,#agent,#name,helparray6(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#hash,"hash"),helpitem(#hash2,"hash"),helpitem(#val,"int"),helpitem(#val2,"int"))) #define IGUANA_HELP_SI(agent,name,str,val) array = helpjson(IGUANA_ARGS,#agent,#name,helparray2(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#val,"int"))) +#define IGUANA_HELP_SD(agent,name,str,val) array = helpjson(IGUANA_ARGS,#agent,#name,helparray2(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#val,"float"))) #define IGUANA_HELP_SII(agent,name,str,val,val2) array = helpjson(IGUANA_ARGS,#agent,#name,helparray3(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#val,"int"),helpitem(#val2,"int"))) #define IGUANA_HELP_SSI(agent,name,str,str2,val) array = helpjson(IGUANA_ARGS,#agent,#name,helparray3(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#val,"int"))) #define IGUANA_HELP_SA(agent,name,str,obj) array = helpjson(IGUANA_ARGS,#agent,#name,helparray2(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#obj,"array"))) @@ -129,6 +131,7 @@ cJSON *SuperNET_helpjson() #define STRING_ARG IGUANA_HELP_S #define TWO_STRINGS IGUANA_HELP_SS #define THREE_STRINGS IGUANA_HELP_SSS +#define FOUR_STRINGS IGUANA_HELP_SSSS #define STRING_AND_INT IGUANA_HELP_SI #define STRING_AND_TWOINTS IGUANA_HELP_SII #define HASH_AND_STRING IGUANA_HELP_HS @@ -160,6 +163,7 @@ cJSON *SuperNET_helpjson() #define THREE_STRINGS_AND_THREE_INTS IGUANA_HELP_SSSIII #define THREE_STRINGS_AND_THREE_DOUBLES IGUANA_HELP_SSSDDD #define THREE_STRINGS_AND_DOUBLE IGUANA_HELP_SSSD +#define STRING_AND_DOUBLE IGUANA_HELP_SD #include "../includes/iguana_apideclares.h" @@ -749,7 +753,9 @@ char *SuperNET_parser(struct supernet_info *myinfo,char *agentstr,char *method,c #define IGUANA_DISPATCH0(agent,name) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS)) #define IGUANA_DISPATCH_S(agent,name,str) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str))) #define IGUANA_DISPATCH_SS(agent,name,str,str2) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jstr(json,#str2))) +#define IGUANA_DISPATCH_SD(agent,name,str,val) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jdouble(json,#val))) #define IGUANA_DISPATCH_SSS(agent,name,str,str2,str3) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jstr(json,#str2),jstr(json,#str3))) +#define IGUANA_DISPATCH_SSSS(agent,name,str,str2,str3,str4) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jstr(json,#str2),jstr(json,#str3),jstr(json,#str4))) #define IGUANA_DISPATCH_SSSD(agent,name,str,str2,str3,amount) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jstr(json,#str2),jstr(json,#str3),jdouble(json,#amount))) #define IGUANA_DISPATCH_SSSDDD(agent,name,str,str2,str3,val,val2,val3) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jstr(json,#str2),jstr(json,#str3),jdouble(json,#val),jdouble(json,#val2),jdouble(json,#val3))) #define IGUANA_DISPATCH_SSSIII(agent,name,str,str2,str3,val,val2,val3) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str),jstr(json,#str2),jstr(json,#str3),jint(json,#val),jint(json,#val2),jint(json,#val3))) @@ -798,6 +804,7 @@ char *SuperNET_parser(struct supernet_info *myinfo,char *agentstr,char *method,c #define STRING_ARG IGUANA_DISPATCH_S #define TWO_STRINGS IGUANA_DISPATCH_SS #define THREE_STRINGS IGUANA_DISPATCH_SSS +#define FOUR_STRINGS IGUANA_DISPATCH_SSSS #define STRING_AND_INT IGUANA_DISPATCH_SI #define STRING_AND_TWOINTS IGUANA_DISPATCH_SII #define HASH_AND_INT IGUANA_DISPATCH_HI @@ -829,6 +836,7 @@ char *SuperNET_parser(struct supernet_info *myinfo,char *agentstr,char *method,c #define THREE_STRINGS_AND_THREE_INTS IGUANA_DISPATCH_SSSIII #define THREE_STRINGS_AND_THREE_DOUBLES IGUANA_DISPATCH_SSSDDD #define THREE_STRINGS_AND_DOUBLE IGUANA_DISPATCH_SSSD +#define STRING_AND_DOUBLE IGUANA_DISPATCH_SD #include "../includes/iguana_apideclares.h" //#undef IGUANA_ARGS diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index 47a453dba..92849f605 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -959,21 +959,25 @@ void iguana_rpcloop(void *args) sprintf(hdrs,"Access-Control-Allow-Methods: GET, POST\r\n"); sprintf(hdrs,"Cache-Control: no-cache, no-store, must-revalidate\r\n"); sprintf(hdrs,"Content-type: application/javascript\r\n"); - sprintf(hdrs,"Content-Length: %8d\r\n",(int32_t)strlen(retstr)); - send(sock,hdrs,strlen(hdrs),MSG_NOSIGNAL);*/ - char * response ; - char hdrs[1024]; - response = malloc(strlen(retstr)+1024+1); - sprintf(hdrs,"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Allow-Methods: GET, POST\r\nCache-Control : no-cache, no-store, must-revalidate\r\nContent-Length : %8d\r\n\r\n",(int32_t)strlen(retstr)); - response[0] = '\0'; - strcat(response,hdrs); - strcat(response,retstr); - remains = (int32_t)strlen(response); - i = 0; - + sprintf(hdrs,"Content-Length: %8d\r\n",(int32_t)strlen(retstr)); + send(sock,hdrs,strlen(hdrs),MSG_NOSIGNAL);*/ + char *response,hdrs[1024]; + if ( jsonflag != 0 ) + { + response = malloc(strlen(retstr)+1024+1); + sprintf(hdrs,"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Allow-Methods: GET, POST\r\nCache-Control : no-cache, no-store, must-revalidate\r\nContent-Length : %8d\r\n\r\n",(int32_t)strlen(retstr)); + response[0] = '\0'; + strcat(response,hdrs); + strcat(response,retstr); + if ( retstr != space ) + free(retstr); + retstr = response; + } + remains = (int32_t)strlen(retstr); + i = 0; while ( remains > 0 ) { - if ( (numsent= (int32_t)send(sock,&response[i],remains,MSG_NOSIGNAL)) < 0 ) + if ( (numsent= (int32_t)send(sock,&retstr[i],remains,MSG_NOSIGNAL)) < 0 ) { if ( errno != EAGAIN && errno != EWOULDBLOCK ) { @@ -989,10 +993,8 @@ void iguana_rpcloop(void *args) printf("iguana sent.%d remains.%d of len.%d\n",numsent,remains,recvlen); } } - if ( response != space){ + if ( retstr != space) free(retstr); - free(response); - } } //if ( Currentjsonstr[0] != 0 ) // strcpy(Prevjsonstr,Currentjsonstr); diff --git a/iguana/iguana_tradebots.c b/iguana/iguana_tradebots.c index 8e3c5be38..36ce9df09 100755 --- a/iguana/iguana_tradebots.c +++ b/iguana/iguana_tradebots.c @@ -211,6 +211,44 @@ THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission) } else return(clonestr("{\"error\":\"tradebots only local usage!\"}")); } +STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission) +{ + int32_t i,n,allfields = 1,depth = 50; cJSON *arg,*array,*item; char *base,*rel,*str,*str2; struct exchange_info *ptr; + if ( remoteaddr == 0 ) + { + if ( (ptr= exchanges777_info(exchange,1,json,remoteaddr)) != 0 ) + { + if ( (str= InstantDEX_allpairs(myinfo,0,json,remoteaddr,exchange)) != 0 ) + { + if ( (arg= cJSON_Parse(str)) != 0 ) + { + if ( (array= jarray(&n,arg,"result")) != 0 ) + { + for (i=0; i 0 ) { tp = pangea_tablealloc(0,N); memset(tp,0,sizeof(*tp)); @@ -205,6 +205,19 @@ struct table_info *pangea_table(bits256 tablehash,int32_t N) return(tp); } +struct player_info *pangea_playerfind(struct supernet_info *myinfo,struct table_info *tp) +{ + struct player_info *player; + if ( tp->priv.myind >= 0 && tp->priv.myind < tp->G.numactive ) + { + player = tp->active[tp->priv.myind]; + if ( memcmp(player->playerpub.bytes,myinfo->myaddr.persistent.bytes,sizeof(player->playerpub)) == 0 ) + return(player); + char str[65],str2[65]; printf("unexpected playerpub mismatch %s vs %s\n",bits256_str(str,player->playerpub),bits256_str(str2,myinfo->myaddr.persistent)); + } + return(0); +} + char *pangea_jsondatacmd(struct supernet_info *myinfo,bits256 tablehash,struct pangea_msghdr *pm,cJSON *json,char *cmdstr,char *ipaddr) { cJSON *argjson; char *reqstr,hexstr[8192]; uint64_t nxt64bits; @@ -212,7 +225,7 @@ char *pangea_jsondatacmd(struct supernet_info *myinfo,bits256 tablehash,struct p pangeahash = calc_categoryhashes(0,"pangea",0); category_subscribe(myinfo,pangeahash,GENESIS_PUBKEY); category_subscribe(myinfo,pangeahash,tablehash); - argjson = cJSON_CreateObject();//SuperNET_argjson(json); + argjson = json != 0 ? jduplicate(json) : cJSON_CreateObject(); jaddstr(argjson,"cmd",cmdstr); if ( myinfo->ipaddr[0] == 0 || strncmp(myinfo->ipaddr,"127.0.0.1",strlen("127.0.0.1")) == 0 ) return(clonestr("{\"error\":\"need to send your ipaddr for now\"}")); @@ -297,21 +310,6 @@ void pangea_sendcmd(struct supernet_info *myinfo,struct table_info *tp,char *cmd free(pm); } -void pangea_ping(PANGEA_HANDARGS) -{ - -} - -void pangea_ready(PANGEA_HANDARGS) -{ - -} - -void pangea_addfunds(PANGEA_HANDARGS) -{ - -} - void pangea_tablejoin(struct supernet_info *myinfo,struct table_info *tp,uint8_t *data,int32_t datalen,uint64_t signer64bits,uint32_t sigtimestamp,bits256 sigtablehash) { char str[65],str2[65],space[4096]; int32_t i; cJSON *json; @@ -334,7 +332,7 @@ void pangea_tablejoin(struct supernet_info *myinfo,struct table_info *tp,uint8_t printf("add player.%d %p\n",i,tp); if ( tp->G.creatorbits == myinfo->myaddr.nxt64bits ) { - pangea_jsondatacmd(myinfo,sigtablehash,(struct pangea_msghdr *)space,json,"accept",myinfo->ipaddr); + pangea_jsondatacmd(myinfo,sigtablehash,(struct pangea_msghdr *)space,0,"accept",myinfo->ipaddr); printf("my table! "); } } else printf("duplicate player.%llu\n",(long long)signer64bits); @@ -436,15 +434,32 @@ void pangea_parse(struct supernet_info *myinfo,struct pangea_msghdr *pm,cJSON *a printf("ACCEPT.(%s)\n",jprint(argjson,0)); //pangea_tableaccept(myinfo,pm,tp,pm->serialized,(int32_t)(pm->sig.allocsize - sizeof(*pm))); } + else if ( strcmp(method,"addfunds") == 0 ) + { + printf("ADDFUNDS.(%s)\n",jprint(argjson,0)); + } + else if ( strcmp(method,"buyin") == 0 ) + { + printf("BUYIN.(%s)\n",jprint(argjson,0)); + } + else if ( strcmp(method,"status") == 0 ) + { + printf("STATUS.(%s)\n",jprint(argjson,0)); + } } } +void pangea_addfunds(PANGEA_HANDARGS) +{ + printf("got remote addfunds\n"); +} + char *pangea_hexmsg(struct supernet_info *myinfo,void *data,int32_t len,char *remoteaddr) { static struct { char *cmdstr; void (*func)(PANGEA_HANDARGS); uint64_t cmdbits; } tablecmds[] = { //{ "newtable", pangea_tablecreate }, { "join", pangea_tablejoin }, { "accept", pangea_tableaccept }, - { "addfunds", pangea_addfunds }, { "ping", pangea_ping }, { "ready", pangea_ready }, + { "addfunds", pangea_addfunds }, //{ "ping", pangea_ping }, { "ready", pangea_ready }, { "newhand", pangea_newhand }, { "gothand", pangea_gothand }, { "encoded", pangea_encoded }, { "sentencoded", pangea_sentencoded }, { "final", pangea_final }, { "gotfinal", pangea_gotfinal }, @@ -680,9 +695,123 @@ HASH_AND_ARRAY(pangea,history,tablehash,params) return(_pangea_history(myinfo,tablehash,json)); }*/ +char *pangea_submitaction(struct supernet_info *myinfo,struct table_info *tp,int64_t bet,int32_t action,char *name) +{ + char retbuf[1024]; struct player_info *player; + if ( (player= pangea_playerfind(myinfo,tp)) != 0 ) + { + pangea_action(myinfo,tp->G.numactive,action,action,-1,tp->priv.myind,tp,(uint8_t *)&bet,sizeof(bet)); + if ( player->actualaction != action ) + sprintf(retbuf,"{\"result\":\"submitted %s, but got mismatched\",\"action\":\"%d\",\"expected\":\"%d\",\"bet\":%.8f}",name,action,player->actualaction,dstr(player->actualbet)); + else sprintf(retbuf,"{\"result\":\"success\",\"broadcast\":\"%s\",\"bet\":%.8f}",name,dstr(player->actualbet)); + return(clonestr(retbuf)); + } else return(clonestr("{\"error\":\"not a player on the table\"}")); +} + +HASH_ARG(pangea,call,tablehash) +{ + struct table_info *tp; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else return(pangea_submitaction(myinfo,tp,0,CARDS777_CALL,"call")); +} + +HASH_AND_INT(pangea,raise,tablehash,numchips) +{ + struct table_info *tp; int64_t value; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else + { + value = pangea_chipsvalue(myinfo,tp,numchips); + return(pangea_submitaction(myinfo,tp,value,CARDS777_RAISE,"raise")); + } +} + +HASH_ARG(pangea,allin,tablehash) +{ + struct table_info *tp; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else return(pangea_submitaction(myinfo,tp,0,CARDS777_ALLIN,"allin")); +} + +HASH_AND_INT(pangea,bet,tablehash,numchips) +{ + struct table_info *tp; int64_t value; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else + { + value = pangea_chipsvalue(myinfo,tp,numchips); + return(pangea_submitaction(myinfo,tp,value,CARDS777_BET,"bet")); + } +} + +HASH_ARG(pangea,check,tablehash) +{ + struct table_info *tp; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else return(pangea_submitaction(myinfo,tp,0,CARDS777_CHECK,"check")); +} + +HASH_ARG(pangea,fold,tablehash) +{ + struct table_info *tp; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else return(pangea_submitaction(myinfo,tp,0,CARDS777_FOLD,"fold")); +} + +HASH_ARG(pangea,status,tablehash) +{ + struct table_info *tp; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else return(jprint(pangea_tablestatus(myinfo,tp),1)); +} + +HASH_AND_STRING(pangea,mode,tablehash,params) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + return(clonestr("{\"result\":\"mode not active yet\"}")); +} + +HASH_ARG(pangea,history,tablehash) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + return(clonestr("{\"result\":\"history not active yet\"}")); +} + +HASH_AND_INT(pangea,handhistory,tablehash,hand) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + return(clonestr("{\"result\":\"handhistory not active yet\"}")); +} + ZERO_ARGS(pangea,lobby) { //cJSON *retjson,*argjson; char *retstr,*result; uint8_t *buf; int32_t flag,len; struct pangea_msghdr *pm; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); bits256 pangeahash = calc_categoryhashes(0,"pangea",0); category_subscribe(myinfo,pangeahash,GENESIS_PUBKEY); pangea_update(myinfo); @@ -692,6 +821,8 @@ ZERO_ARGS(pangea,lobby) INT_AND_ARRAY(pangea,host,minplayers,params) { bits256 tablehash; struct table_info *tp; uint8_t space[sizeof(struct pangea_msghdr) + 4096]; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); OS_randombytes(tablehash.bytes,sizeof(tablehash)); tp = pangea_table(tablehash,9); if ( tp != 0 ) @@ -705,12 +836,32 @@ INT_AND_ARRAY(pangea,host,minplayers,params) HASH_AND_STRING(pangea,join,tablehash,handle) { uint8_t space[sizeof(struct pangea_msghdr) + 4096]; - return(pangea_jsondatacmd(myinfo,tablehash,(struct pangea_msghdr *)space,json,"join",myinfo->ipaddr)); + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + return(pangea_jsondatacmd(myinfo,tablehash,(struct pangea_msghdr *)space,0,"join",myinfo->ipaddr)); +} + +HASH_AND_INT(pangea,buyin,tablehash,numchips) +{ + uint8_t space[sizeof(struct pangea_msghdr) + 4096]; struct table_info *tp; int64_t value; cJSON *fundsjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( (tp= pangea_table(tablehash,0)) == 0 ) + return(clonestr("{\"result\":\"table doesnt exist\"}")); + else + { + value = pangea_chipsvalue(myinfo,tp,numchips); + fundsjson = cJSON_CreateObject(); + jaddnum(fundsjson,"amount",dstr(value)); + return(pangea_jsondatacmd(myinfo,tablehash,(struct pangea_msghdr *)space,fundsjson,"addfunds",myinfo->ipaddr)); + } } -HASH_AND_ARRAY(pangea,start,tablehash,params) +HASH_ARG(pangea,start,tablehash) { struct table_info *tp; int32_t allocsize; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); if ( (tp= pangea_table(tablehash,9)) != 0 ) { if ( tp->G.numactive >= tp->G.minplayers && pangea_tableismine(myinfo,tp) >= 0 ) diff --git a/iguana/pangea_bets.c b/iguana/pangea_bets.c index cfc40425a..879c40461 100755 --- a/iguana/pangea_bets.c +++ b/iguana/pangea_bets.c @@ -15,7 +15,12 @@ #include "pangea777.h" -void pangea_fold(struct supernet_info *myinfo,struct table_info *tp,struct player_info *player) +int64_t pangea_chipsvalue(struct supernet_info *myinfo,struct table_info *tp,int32_t numchips) +{ + return((tp->G.bigblind >> 1) * numchips); +} + +void pangea_playerfold(struct supernet_info *myinfo,struct table_info *tp,struct player_info *player) { uint8_t tmp; //printf("player.%d folded\n",player); //getchar(); @@ -26,15 +31,28 @@ void pangea_fold(struct supernet_info *myinfo,struct table_info *tp,struct playe pangea_summaryadd(myinfo,tp,CARDS777_FOLD,&tmp,sizeof(tmp),(void *)&player->bets,sizeof(player->bets)); } -int32_t pangea_bet(struct supernet_info *myinfo,struct table_info *tp,struct player_info *player,int64_t bet,int32_t action) +int32_t pangea_playerbet(struct supernet_info *myinfo,int64_t *actualbetp,struct table_info *tp,struct player_info *player,int64_t bet,int32_t action) { uint64_t sum; uint8_t tmp; struct hand_info *hand = &tp->hand; + if ( bet == 0 ) // autobet + { + if ( action == CARDS777_CALL ) + bet = hand->betsize; + else if ( action == CARDS777_BET ) + bet = hand->betsize + hand->lastraise; + else if ( action == CARDS777_RAISE ) + bet = hand->betsize + hand->lastraise * 2; + bet -= player->bets; + } + *actualbetp = 0; if ( Debuglevel > 2 ) printf("PANGEA_BET[%d] <- %.8f\n",player->ind,dstr(bet)); if ( player->betstatus == CARDS777_ALLIN ) return(CARDS777_ALLIN); else if ( player->betstatus == CARDS777_FOLD ) return(CARDS777_FOLD); + else if ( action == CARDS777_ALLIN ) + bet = player->balance; if ( bet > 0 && bet >= player->balance ) { bet = player->balance; @@ -52,7 +70,7 @@ int32_t pangea_bet(struct supernet_info *myinfo,struct table_info *tp,struct pla sum = player->bets; if ( sum+bet < hand->betsize && action != CARDS777_ALLIN ) { - pangea_fold(myinfo,tp,player); + pangea_playerfold(myinfo,tp,player); action = CARDS777_FOLD; if ( Debuglevel > 2 ) printf("player.%d betsize %.8f < hand.betsize %.8f FOLD\n",player->ind,dstr(bet),dstr(hand->betsize)); @@ -84,20 +102,21 @@ int32_t pangea_bet(struct supernet_info *myinfo,struct table_info *tp,struct pla tmp = player->ind; pangea_summaryadd(myinfo,tp,action,&tmp,sizeof(tmp),(void *)&bet,sizeof(bet)); player->balance -= bet, player->bets += bet; - if ( Debuglevel > 2 ) + //if ( Debuglevel > 2 ) printf("player.%d: player.%d BET %f -> balances %f bets %f\n",tp->priv.myind,player->ind,dstr(bet),dstr(player->balance),dstr(player->bets)); + *actualbetp = bet; return(action); } void pangea_antes(struct supernet_info *myinfo,struct table_info *tp) { - int32_t i,n,N; struct player_info *p; uint64_t threshold; int32_t handid; + int32_t i,n,N; struct player_info *p; uint64_t threshold; int32_t handid; int64_t actualbet; N = tp->G.numactive; for (i=0; iG.N; i++) { tp->G.P[i].ind = i; if ( (tp->snapshot[i]= tp->G.P[i].balance) <= 0 ) - pangea_fold(myinfo,tp,&tp->G.P[i]); + pangea_playerfold(myinfo,tp,&tp->G.P[i]); } handid = tp->numhands - 1; pangea_summaryadd(myinfo,tp,CARDS777_SNAPSHOT,(void *)&handid,sizeof(handid),(void *)tp->snapshot,sizeof(uint64_t)*CARDS777_MAXPLAYERS); @@ -108,8 +127,8 @@ void pangea_antes(struct supernet_info *myinfo,struct table_info *tp) if ( (p= tp->active[i]) != 0 ) { if ( p->balance < tp->G.ante ) - pangea_fold(myinfo,tp,p); - else pangea_bet(myinfo,tp,p,tp->G.ante,CARDS777_ANTE); + pangea_playerfold(myinfo,tp,p); + else pangea_playerbet(myinfo,&actualbet,tp,p,tp->G.ante,CARDS777_ANTE); } else printf("unexpected null player ptr\n"); } } @@ -121,16 +140,15 @@ void pangea_antes(struct supernet_info *myinfo,struct table_info *tp) threshold = tp->G.bigblind - 1; else threshold = 0; if ( (p= tp->active[i]) != 0 && p->balance < threshold ) - pangea_fold(myinfo,tp,p); + pangea_playerfold(myinfo,tp,p); else n++; } if ( n < 2 ) printf("pangea_antes not enough players n.%d\n",n); else { - pangea_bet(myinfo,tp,tp->active[0],(tp->G.bigblind>>1),CARDS777_SMALLBLIND); - pangea_bet(myinfo,tp,tp->active[1],tp->G.bigblind,CARDS777_BIGBLIND); - + pangea_playerbet(myinfo,&actualbet,tp,tp->active[0],(tp->G.bigblind>>1),CARDS777_SMALLBLIND); + pangea_playerbet(myinfo,&actualbet,tp,tp->active[1],tp->G.bigblind,CARDS777_BIGBLIND); } } diff --git a/iguana/pangea_hand.c b/iguana/pangea_hand.c index af7b40a0e..2cdd26d2d 100755 --- a/iguana/pangea_hand.c +++ b/iguana/pangea_hand.c @@ -824,7 +824,7 @@ int32_t pangea_lastman(struct supernet_info *myinfo,struct table_info *tp) void pangea_action(PANGEA_HANDARGS) { uint32_t now; struct player_info *p; int64_t x,snapshot[CARDS777_MAXPLAYERS + 1]; int32_t action,i,j; - bits256 audit[CARDS777_MAXPLAYERS]; struct hand_info *hand; uint8_t tmp; uint64_t amount = 0; + bits256 audit[CARDS777_MAXPLAYERS]; struct hand_info *hand; uint8_t tmp; int64_t amount = 0; hand = &tp->hand; p = tp->active[senderind]; memcpy(&amount,data,sizeof(amount)); @@ -840,8 +840,8 @@ void pangea_action(PANGEA_HANDARGS) return; } tmp = senderind; - pangea_bet(myinfo,tp,tp->active[senderind],amount,CARDS777_CHECK); p->action = action; + p->actualaction = pangea_playerbet(myinfo,&p->actualbet,tp,tp->active[senderind],amount,CARDS777_CHECK); hand->undergun = (hand->undergun + 1) % N; hand->numactions++; //if ( Debuglevel > 2 )//|| tp->priv.myind == 0 ) diff --git a/iguana/pangea_json.c b/iguana/pangea_json.c index 42aff73b7..cc2499128 100755 --- a/iguana/pangea_json.c +++ b/iguana/pangea_json.c @@ -25,7 +25,7 @@ cJSON *pangea_playerjson(struct supernet_info *myinfo,struct table_info *tp,stru return(json); } -cJSON *pangea_tablejson(struct supernet_info *myinfo,struct table_info *tp) +/*cJSON *pangea_tablejson(struct supernet_info *myinfo,struct table_info *tp) { char ipaddr[64],str[64]; int32_t i; cJSON *array,*json; struct game_info *gp; gp = &tp->G; @@ -64,9 +64,8 @@ cJSON *pangea_tablejson(struct supernet_info *myinfo,struct table_info *tp) jadd(json,"players",array); } jaddnum(json,"numactive",tp->G.numactive); - printf("tp.%p\n",tp); return(json); -} +}*/ void pangea_gamecreate(struct game_info *gp,uint32_t timestamp,bits256 tablehash,cJSON *json) { @@ -116,7 +115,7 @@ cJSON *pangea_lobbyjson(struct supernet_info *myinfo) HASH_ITER(hh,cat->sub,sub,tmp) { if ( (tp= sub->info) != 0 && pangea_opentable(&tp->G) > 0 ) - jaddi(array,pangea_tablejson(myinfo,tp)); + jaddi(array,pangea_tablestatus(myinfo,tp)); } } jadd(retjson,"tables",array); @@ -203,10 +202,29 @@ cJSON *pangea_tablestatus(struct supernet_info *myinfo,struct table_info *tp) jaddnum(json,"pangearake",dstr(gp->pangearake)); jaddnum(json,"bigblind",dstr(gp->bigblind)); jaddnum(json,"ante",dstr(gp->ante)); - array = cJSON_CreateArray(); + if ( gp->opentime != 0 ) + { + char utcbuf[65]; + jaddstr(json,"opentime",utc_str(utcbuf,gp->opentime)); + if ( gp->started != 0 ) + { + jaddstr(json,"started",utc_str(utcbuf,gp->started)); + if ( gp->finished != 0 ) + jaddstr(json,"finished",utc_str(utcbuf,gp->finished)); + } + } + if ( tp->G.numactive > 0 ) + { + array = cJSON_CreateArray(); + for (i=0; iG.numactive; i++) + jaddi(array,pangea_playerjson(myinfo,tp,&tp->G.P[i])); + jadd(json,"players",array); + } + jaddnum(json,"numactive",tp->G.numactive); + /*array = cJSON_CreateArray(); for (i=0; iG.numactive; i++) jaddi64bits(array,tp->active[i]!=0?tp->active[i]->nxt64bits:0); - jadd(json,"addrs",array); + jadd(json,"addrs",array);*/ total = 0; for (iter=0; iter<6; iter++) { diff --git a/iguana/peggy.c b/iguana/peggy.c new file mode 100755 index 000000000..2d5073a03 --- /dev/null +++ b/iguana/peggy.c @@ -0,0 +1,689 @@ +/****************************************************************************** + * 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 "peggy.h" +#include "exchanges777.h" + +int32_t Peggy_inds[539] = {289, 404, 50, 490, 59, 208, 87, 508, 366, 288, 13, 38, 159, 440, 120, 480, 361, 104, 534, 195, 300, 362, 489, 108, 143, 220, 131, 244, 133, 473, 315, 439, 210, 456, 219, 352, 153, 444, 397, 491, 286, 479, 519, 384, 126, 369, 155, 427, 373, 360, 135, 297, 256, 506, 322, 425, 501, 251, 75, 18, 420, 537, 443, 438, 407, 145, 173, 78, 340, 240, 422, 160, 329, 32, 127, 128, 415, 495, 372, 522, 60, 238, 129, 364, 471, 140, 171, 215, 378, 292, 432, 526, 252, 389, 459, 350, 233, 408, 433, 51, 423, 19, 62, 115, 211, 22, 247, 197, 530, 7, 492, 5, 53, 318, 313, 283, 169, 464, 224, 282, 514, 385, 228, 175, 494, 237, 446, 105, 150, 338, 346, 510, 6, 348, 89, 63, 536, 442, 414, 209, 216, 227, 380, 72, 319, 259, 305, 334, 236, 103, 400, 176, 267, 355, 429, 134, 257, 527, 111, 287, 386, 15, 392, 535, 405, 23, 447, 399, 291, 112, 74, 36, 435, 434, 330, 520, 335, 201, 478, 17, 162, 483, 33, 130, 436, 395, 93, 298, 498, 511, 66, 487, 218, 65, 309, 419, 48, 214, 377, 409, 462, 139, 349, 4, 513, 497, 394, 170, 307, 241, 185, 454, 29, 367, 465, 194, 398, 301, 229, 212, 477, 303, 39, 524, 451, 116, 532, 30, 344, 85, 186, 202, 517, 531, 515, 230, 331, 466, 147, 426, 234, 304, 64, 100, 416, 336, 199, 383, 200, 166, 258, 95, 188, 246, 136, 90, 68, 45, 312, 354, 184, 314, 518, 326, 401, 269, 217, 512, 81, 88, 272, 14, 413, 328, 393, 198, 226, 381, 161, 474, 353, 337, 294, 295, 302, 505, 137, 207, 249, 46, 98, 27, 458, 482, 262, 253, 71, 25, 0, 40, 525, 122, 341, 107, 80, 165, 243, 168, 250, 375, 151, 503, 124, 52, 343, 371, 206, 178, 528, 232, 424, 163, 273, 191, 149, 493, 177, 144, 193, 388, 1, 412, 265, 457, 255, 475, 223, 41, 430, 76, 102, 132, 96, 97, 316, 472, 213, 263, 3, 317, 324, 274, 396, 486, 254, 205, 285, 101, 21, 279, 58, 467, 271, 92, 538, 516, 235, 332, 117, 500, 529, 113, 445, 390, 358, 79, 34, 488, 245, 83, 509, 203, 476, 496, 347, 280, 12, 84, 485, 323, 452, 10, 146, 391, 293, 86, 94, 523, 299, 91, 164, 363, 402, 110, 321, 181, 138, 192, 469, 351, 276, 308, 277, 428, 182, 260, 55, 152, 157, 382, 121, 507, 225, 61, 431, 31, 106, 327, 154, 16, 49, 499, 73, 70, 449, 460, 187, 24, 248, 311, 275, 158, 387, 125, 67, 284, 35, 463, 190, 179, 266, 376, 221, 42, 26, 290, 357, 268, 43, 167, 99, 374, 242, 156, 239, 403, 339, 183, 320, 180, 306, 379, 441, 20, 481, 141, 77, 484, 69, 410, 502, 172, 417, 118, 461, 261, 47, 333, 450, 296, 453, 368, 359, 437, 421, 264, 504, 281, 270, 114, 278, 56, 406, 448, 411, 521, 418, 470, 123, 455, 148, 356, 468, 109, 204, 533, 365, 8, 345, 174, 370, 28, 57, 11, 2, 231, 310, 196, 119, 82, 325, 44, 342, 37, 189, 142, 222, 9, 54, }; + +char *peggy_mapname(char *basebuf,char *relbuf,int32_t i) // sorry it is messy thing +{ + char *base,*rel,buf[16]; + base = rel = 0; + strcpy(buf,peggy_bases[i]); + base = buf, rel = "BTCD"; + if ( strlen(buf) > 3 && strcmp(buf+strlen(buf)-3,"USD") == 0 ) + { + if ( strcmp(buf,"BTCUSD") == 0 ) + base = "BTC"; + buf[strlen(buf)-3] = 0; + } + else if ( strcmp(buf,"COPPER") == 0 || strcmp(buf,"NGAS") == 0 || strcmp(buf,"UKOIL") == 0 || strcmp(buf,"USOIL") == 0 || strcmp(buf,"US30") == 0 || strcmp(buf,"SPX500") == 0 || strcmp(buf,"NAS100") == 0 ) + rel = "USD"; + else if ( strcmp(buf,"BUND") == 0 ) + rel = "yield"; + else if ( strcmp(buf,"EUSTX50") == 0 ) + rel = "EUR"; + else if ( strcmp(buf,"JPN225") == 0 ) + rel = "JPY"; + else if ( strcmp(buf,"UK100") == 0 ) + rel = "GBP"; + else if ( strcmp(buf,"GER30") == 0 ) + rel = "EUR"; + else if ( strcmp(buf,"SUI30") == 0 ) + rel = "CHF"; + else if ( strcmp(buf,"AUS200") == 0 ) + rel = "AUD"; + else if ( strcmp(buf,"HKG33") == 0 ) + rel = "HKD"; + else if ( strlen(buf) > 3 && strcmp(buf+strlen(buf)-3,"BTC") == 0 ) + base = buf, buf[strlen(buf)-3] = 0; + if ( i == sizeof(peggy_bases)/sizeof(*peggy_bases)-1 && strcmp(peggy_bases[i],"BTCUSD") == 0 ) + base = "BTC", rel = "USD"; + else if ( i == sizeof(peggy_bases)/sizeof(*peggy_bases)-2 && strcmp(peggy_bases[i],"BTCCNY") == 0 ) + base = "BTC", rel = "CNY"; + else if ( i == sizeof(peggy_bases)/sizeof(*peggy_bases)-3 && strcmp(peggy_bases[i],"BTCRUB") == 0 ) + base = "BTC", rel = "RUB"; + else if ( i == sizeof(peggy_bases)/sizeof(*peggy_bases)-4 && strcmp(peggy_bases[i],"XAUUSD") == 0 ) + base = "XAU", rel = "USD"; + else if ( i == 0 ) + base = "BTCD", rel = "maincurrency peggy, realtime"; + basebuf[0] = relbuf[0] = 0; + if ( rel != 0 ) + strcpy(relbuf,rel);//, printf("rel.(%s) ",rel); + if ( base != 0 ) + strcpy(basebuf,base);//, printf("base.(%s) ",base); + return(basebuf); +} + +uint64_t peggy_basebits(char *name) +{ + int32_t i; char basebuf[64],relbuf[64]; + for (i=0; i<64; i++) + { + if ( strcmp(name,peggy_bases[i]) == 0 ) + { + peggy_mapname(basebuf,relbuf,i); + return(stringbits(basebuf)); + } + } + return(0); +} + +uint64_t peggy_relbits(char *name) +{ + int32_t i; char basebuf[64],relbuf[64]; + for (i=0; i<64; i++) + { + if ( strcmp(name,peggy_bases[i]) == 0 ) + { + peggy_mapname(basebuf,relbuf,i); + return(stringbits(relbuf)); + } + } + return(0); +} + +static uint64_t peggy_assetbits(char *name) { return((is_decimalstr(name) != 0) ? calc_nxt64bits(name) : stringbits(name)); } + +int32_t find_uint64(int32_t *emptyslotp,uint64_t *nums,long max,uint64_t val) +{ + int32_t i; + *emptyslotp = -1; + for (i=0; i 2 ) + printf("found in slot[%d] %llx\n",i,(long long)val); + return(i); + } + } + if ( Debuglevel > 2 ) + printf("emptyslot[%d] for %llx\n",i,(long long)val); + return(-1); +} + +int32_t add_uint64(uint64_t *nums,long max,uint64_t val) +{ + int32_t i,emptyslot; + if ( (i= find_uint64(&emptyslot,nums,max,val)) >= 0 ) + return(i); + else if ( emptyslot >= 0 ) + { + nums[emptyslot] = val; + return(emptyslot); + } else return(-1); +} + +// init time +void peggy_descriptions(struct peggy_info *PEGS,struct peggy_description *P,char *name,char *base,char *rel) +{ + int32_t emptyslot; + strcpy(P->name,name), strcpy(P->base,base); + if ( rel != 0 ) + strcpy(P->rel,rel); + P->assetbits = peggy_assetbits(name), P->basebits = stringbits(base), P->relbits = stringbits(P->rel); + P->baseid = add_uint64(PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->basebits); + P->relid = add_uint64(PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->relbits); + if ( find_uint64(&emptyslot,PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->basebits) != P->baseid ) + printf("(%s) (%s) (%s) error cant find baseid.%d for %llx\n",name,base,P->rel,P->baseid,(long long)P->basebits); + if ( P->relbits != 0 && find_uint64(&emptyslot,PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->relbits) != P->relid ) + printf("(%s) (%s) (%s) error cant find relid.%d for %llx\n",name,base,P->rel,P->relid,(long long)P->relbits); +} + +/*int32_t peggy_timeframes(struct peggy_limits *limits,int64_t *scales,uint32_t *timeframes,int32_t numtimeframes,uint64_t maxsupply,uint64_t maxnetbalance) + { + int32_t i; + memset(limits,0,sizeof(*limits)); + limits->maxsupply = maxsupply, limits->maxnetbalance = maxnetbalance; + if ( limits->maxsupply < 0 || limits->maxnetbalance < 0 ) + { + printf("peggy_check_limits: maxnetbalance %lld > %d\n",(long long)limits->maxnetbalance,(int32_t)PRICE_RESOLUTION); + return(-1); + } + limits->numtimeframes = (numtimeframes <= MAX_TIMEFRAMES) ? numtimeframes : MAX_TIMEFRAMES; + for (i=0; inumtimeframes; i++) + { + limits->scales[i] = scales[i]; + if ( (limits->timeframes[i]= PEGGY_DAYTICKS * timeframes[i]) > MAX_TIMEFRAME || (i > 0 && limits->timeframes[i] <= limits->timeframes[i-1]) ) + { + printf("createpeg: illegal timeframe.%d: %d %d vs %d\n",i,timeframes[i],limits->timeframes[i],MAX_TIMEFRAME); + getchar(); return(-1); + } + } + limits->timeframes[0] = 0; + return(0); + }*/ + +int32_t peggy_lockparms(struct peggy_lock *dest,int32_t peg,struct peggy_lock *lockparms) +{ + if ( lockparms->minlockdays > lockparms->maxlockdays ) + { + printf("peggy_check_lockparms: minlockdays %d > %d maxlockdays\n",lockparms->minlockdays,lockparms->maxlockdays); + return(-1); + } + if ( lockparms->mixrange == 0 ) + lockparms->mixrange = PEGGY_MIXRANGE; + if ( lockparms->extralockdays < PEGGY_MINEXTRADAYS * 2 ) + lockparms->extralockdays = PEGGY_MINEXTRADAYS * 2; + *dest = *lockparms, dest->peg = peg; + return(0); +} + +int32_t peggy_setvars(struct peggy_info *PEGS,struct peggy *PEG,int16_t baseid,int16_t relid,int32_t peg,uint64_t maxsupply,uint64_t maxnetbalance,struct peggy_lock *lockparms,uint32_t unitincr,int32_t dailyrate,struct price_resolution *initialprices,int32_t numprices,int32_t hasprice) +{ + int32_t i; + PEG->name.id = peg, PEG->name.hasprice = hasprice; + //if ( peggy_timeframes(&PEG->limits,limits->scales,limits->timeframes,limits->numtimeframes,limits->maxsupply,limits->maxnetbalance) < 0 ) + // return(-1); + if ( peggy_lockparms(&PEG->lockparms,peg,lockparms) < 0 ) + return(-1); + PEG->unitincr = unitincr; + PEG->maxdailyrate = dailyrate; + PEG->maxsupply = maxsupply, PEG->maxnetbalance = maxnetbalance; + if ( initialprices != 0 ) + { + if ( numprices > 0 ) + { + //if ( initialprices[0].Pval >= PRICE_RESOLUTION_MAXPVAL ) + // initialprices[0].Pval = PRICE_RESOLUTION_MAXPVAL; + PEG->genesisprice = PEG->dayprice = PEG->price = initialprices[0]; + for (i=0; imaincurrency, mainunitsize = PEGS->mainunitsize; + if ( lockparms == 0 ) + lockparms = &PEGS->default_lockparms; + //if ( limits == 0 ) + // limits = &PEGS->default_limits; + if ( (PEGS->numpegs == 0 && stringbits(base) != PEGS->mainbits) || maxmargin > PEGGY_MARGINMAX ) + { + printf("peggy_create: numpegs.%d mismatched maincurrency.(%s) || illegal maxmargin.%d vs %d\n",PEGS->numpegs,maincurrency,maxmargin,PEGGY_MARGINMAX); + return(0); + } + if ( firsttimestamp + (numprices-1)*PEGGY_DAYTICKS > time(NULL) ) + { + printf("peggy_createpair latest price must be in the past: 1st.%u + numprices.%d -> %u vs %u\n",firsttimestamp,numprices,firsttimestamp + (numprices-1)*PEGGY_DAYTICKS,(uint32_t)time(NULL)); + return(0); + } + if ( quorum == 0 ) + quorum = PEGS->quorum; + if ( decisionthreshold == 0 ) + decisionthreshold = PEGS->decisionthreshold; + assetbits = peggy_assetbits(name); + if ( PEGS->numpegs > 0 ) + { + for (i=0; inumpegs; i++) + if ( PEGS->contracts[i]->name.assetbits == assetbits ) + { + printf("peggy_create: cant create duplicate peggy.(%s) base.(%s) rel.(%s)\n",name,base,rel); + return(0); + } + } + if ( hasprice != 0 ) + PEG = &PEGS->pricedpegs[PEGS->numpricedpegs].PEG; + else PEG = &PEGS->pairedpegs[PEGS->numpairedpegs]; + memset(PEG,0,sizeof(*PEG)); + peggy_descriptions(PEGS,&PEG->name,name,base,rel); + PEG->pool.quorum = (quorum != 0) ? quorum : PEGS->quorum, PEG->pool.decisionthreshold = (decisionthreshold != 0) ? decisionthreshold : PEGS->decisionthreshold; + PEG->pool.mainunitsize = PEGS->mainunitsize, PEG->pool.mainbits = PEGS->mainbits; + PEG->genesistime = firsttimestamp, PEG->name.id = PEGS->numpegs; + PEG->spread = spread, PEG->lockparms.margin = maxmargin, PEG->mindenomination = mindenomination; + if ( hasprice == 0 ) + PEG->baseprices = PEGS->pricedpegs[PEG->name.baseid].prices, PEG->relprices = PEGS->pricedpegs[PEG->name.relid].prices; + else PEG->baseprices = PEGS->pricedpegs[PEG->name.id].prices, PEG->relprices = 0; + if ( peggy_setvars(PEGS,PEG,PEG->name.baseid,PEG->name.relid,PEGS->numpegs,maxsupply,maxnetbalance,lockparms,unitincr,maxdailyrate,initialprices,numprices,hasprice) < 0 ) + { + printf("peggy_create: error init peggy.(%s) base.(%s) rel.(%s)\n",name,base,rel); + return(0); + } + //printf("PEG.%p num.%d priced.%d paired.%d\n",PEG,PEGS->numpegs,PEGS->numpricedpegs,PEGS->numpairedpegs); + if ( hasprice != 0 ) + PEGS->numpricedpegs++; + else PEGS->numpairedpegs++; + PEGS->contracts[PEGS->numpegs++] = PEG; + PEG->peggymils = peggymils; + PEG->name.enabled = 1; + return(PEG); +} + +struct peggy_info *peggy_init(char *path,int32_t maxdays,char *maincurrency,uint64_t maincurrencyunitsize,uint64_t quorum,uint64_t decisionthreshold,struct price_resolution spread,uint32_t dailyrate,int32_t interesttenths,int32_t posboost,int32_t negpenalty,int32_t feediv,int32_t feemult,uint32_t firsttimestamp,uint32_t BTCD_price0) +{ + //struct peggy_limits limits = { { PERCENTAGE(10), PERCENTAGE(25), PERCENTAGE(33), PERCENTAGE(50) }, SATOSHIDEN * 10000, SATOSHIDEN * 1000, { 0, 30, 90, 180 }, 4 }; + struct peggy_lock default_lockparms = { 7, 365, 7, 0, 180, 0, -1 }; + struct price_resolution mindenom,price; struct peggy_info *PEGS = calloc(1,sizeof(*PEGS)); + //if ( default_limits != 0 ) + // limits = *default_limits; + spread.Pval = PERCENTAGE(1); + OS_ensure_directory(path); + strcpy(PEGS->maincurrency,maincurrency); + PEGS->mainbits = stringbits(maincurrency), PEGS->mainunitsize = maincurrencyunitsize, PEGS->quorum = quorum, PEGS->decisionthreshold = decisionthreshold; + PEGS->default_lockparms = default_lockparms, PEGS->default_lockparms.maxlockdays = maxdays; + //PEGS->default_limits = limits, + PEGS->default_spread = spread, PEGS->default_dailyrate = dailyrate; + PEGS->interesttenths = interesttenths, PEGS->posboost = posboost, PEGS->negpenalty = negpenalty, PEGS->feediv = feediv, PEGS->feemult = feemult; + mindenom.Pval = PRICE_RESOLUTION; + PEGS->genesistime = firsttimestamp; + price.Pval = PEGS->BTCD_price0 = BTCD_price0; + printf("set genesistime.%u BTCD0.%u\n",firsttimestamp,BTCD_price0); + peggy_createpair(PEGS,0,0,"BTCD","BTCD",0,SATOSHIDEN*1000000,SATOSHIDEN*100000,0,SATOSHIDEN,PEGGY_RATE_777,firsttimestamp,&price,1,spread,0,mindenom,0,1,peggy_mils(0)); + //PEGS->accts = accts777_init(path,0); + return(PEGS); +} +//////////// end of consensus safe + +long hdecode_varint(uint64_t *valp,uint8_t *ptr,long offset,long mappedsize) +{ + uint16_t s; uint32_t i; int32_t c; + if ( ptr == 0 ) + return(-1); + *valp = 0; + if ( offset < 0 || offset >= mappedsize ) + return(-1); + c = ptr[offset++]; + switch ( c ) + { + case 0xfd: if ( offset+sizeof(s) > mappedsize ) return(-1); memcpy(&s,&ptr[offset],sizeof(s)), *valp = s, offset += sizeof(s); break; + case 0xfe: if ( offset+sizeof(i) > mappedsize ) return(-1); memcpy(&i,&ptr[offset],sizeof(i)), *valp = i, offset += sizeof(i); break; + case 0xff: if ( offset+sizeof(*valp) > mappedsize ) return(-1); memcpy(valp,&ptr[offset],sizeof(*valp)), offset += sizeof(*valp); break; + default: *valp = c; break; + } + return(offset); +} + +struct peggy_info *peggy_genesis(int32_t lookbacks[OPRETURNS_CONTEXTS],struct peggy_info *PEGS,char *path,uint32_t firsttimestamp,char *opreturnstr) +{ + //struct peggy_limits limits = { { PERCENTAGE(10), PERCENTAGE(25), PERCENTAGE(33), PERCENTAGE(50) }, SATOSHIDEN * 10000, SATOSHIDEN * 1000, { 0, 30, 90, 180 }, 4 }; + char name[64],base[64],rel[64]; uint8_t opret[1024]; struct peggy_tx Ptx; struct peggy *PEG; + struct price_resolution mindenom,spread,price; uint64_t len; long offset; uint64_t maxsupply=0,maxnetbalance=0; + int32_t i,c,baseid,relid,peggymils=0,signedcount,datalen,n=0,maxmargin=0,numprices,err=-1; uint32_t pval = 0; + numprices = 1; + datalen = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opret,datalen,opreturnstr); + printf("peggy_genesis(%s)\n",opreturnstr); + if ( opret[0] == OP_RETURN_OPCODE ) + { + offset = hdecode_varint(&len,opret,1,sizeof(opret)); + if ( opret[offset] == 'P' && opret[offset+1] == 'A' && opret[offset+2] == 'X' ) + { + printf("deser\n"); + if ( (n= serdes777_deserialize(&signedcount,&Ptx,firsttimestamp,opret+offset+3,(int32_t)len-3)) > 0 ) + { + err = 0; + for (i=0; iaccts = accts777_init(path,0); + PEGS->genesis = opreturnstr, opreturnstr = 0; + } + } else printf("i.%d vs %d\n",i,Ptx.details.price.num); + } else printf("deser got n.%d\n",n); + } else printf("illegal opret.(%c%c%c)\n",opret[offset],opret[offset+1],opret[offset+2]); + } else printf("opret[0] %d\n",opret[0]); + if ( err < 0 || PEGS == 0 ) + return(0); + mindenom.Pval = PRICE_RESOLUTION; + spread.Pval = PERCENTAGE(1); + for (i=1; icontracts[baseid]->peggymils * 10000) / PEGS->contracts[relid]->peggymils; + if ( strcmp(PEGS->contracts[baseid]->name.base,base) == 0 && strcmp(PEGS->contracts[relid]->name.base,rel) == 0 ) + price.Pval = (PRICE_RESOLUTION * Ptx.details.price.feed[baseid]) / Ptx.details.price.feed[relid]; + else printf("mismatched %p base.(%s) baseid.%d (%s) or %p rel.(%s) relid.%d (%s)\n",PEGS->contracts[baseid],PEGS->contracts[baseid]->name.base,baseid,base,PEGS->contracts[relid],PEGS->contracts[relid]->name.base,relid,rel); + pval = (uint32_t)price.Pval; + } else printf("peggy_genesis RAN out of space\n"); + if ( (PEG= peggy_createpair(PEGS,0,0,name,base,rel,maxsupply,maxnetbalance,0,SATOSHIDEN*10,PEGGY_RATE_777,firsttimestamp,&price,numprices,spread,maxmargin,mindenom,i,iname.name,PEG->name.base,PEG->name.rel,Pval(&price),Pval(&x),pval,maxmargin,dstr(maxsupply),dstr(maxnetbalance),Pval(&spread),Pval(&mindenom),PEG->peggymils); + n++; + } + } + printf("genesis prices t%u vs %u\n",Ptx.timestamp,firsttimestamp); + return(PEGS); +} + +char *peggybase(uint32_t blocknum,uint32_t blocktimestamp) +{ + int32_t nonz; struct peggy_info *PEGS = opreturns_context("peggy",0); + if ( PEGS != 0 ) + return(peggy_emitprices(&nonz,PEGS,blocktimestamp,PEGS->genesis != 0 ? 0 : PEGGY_MAXLOCKDAYS)); + return(0); +} + +char *peggypayments(uint32_t blocknum,uint32_t blocktimestamp) +{ + int32_t peggy_payments(queue_t *PaymentsQ,struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp); + struct opreturn_payment payments[8192]; cJSON *json; + int32_t i,n; struct peggy_info *PEGS = opreturns_context("peggy",0); + memset(payments,0,sizeof(payments)); + if ( PEGS != 0 && PEGS->accts != 0 && (n= peggy_payments(&PEGS->accts->PaymentsQ,payments,sizeof(payments)/sizeof(*payments),blocknum,blocknum,blocktimestamp)) > 0 ) + { + json = cJSON_CreateObject(); + for (i=0; igenesis != 0 ? 0 : PEGGY_MAXLOCKDAYS); + if ( opreturnstr != 0 ) + { + printf("OPRETURN.(%s)\n",opreturnstr); + //if ( Debuglevel > 2 ) + printf("update.%d opreturns.(%s) t%u\n",PEGS->numopreturns,opreturnstr,timestamp); + sprintf(fname,"opreturns/%d",PEGS->numopreturns); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fwrite(opreturnstr,1,strlen(opreturnstr)+1,fp); + fclose(fp); + } + if ( nonz == 64 && PEGS->genesis == 0 ) + peggy_genesis(lookbacks,PEGS,PEGS->path,timestamp,opreturnstr); + else + { + num = 1; + peggylen = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opret,peggylen,opreturnstr); + opreturns_process(1,PEGS->numopreturns,PEGS->numopreturns,timestamp,0,0,opret,peggylen); + free(opreturnstr); + PEGS->numopreturns++; + } + } + } +} + +uint64_t map_apr(uint64_t *spreadp,int32_t maxdays,double apr) +{ + int64_t bestdiff,diff; int32_t i; uint64_t rate,bestsatoshis,satoshis,bestrate = 0,target; + target = PRICE_RESOLUTION * (1. + apr/100.); + bestrate = ((PRICE_RESOLUTION * log(apr)/10) / (365-1)); + satoshis = peggy_compound(0,PRICE_RESOLUTION,bestrate,365); + bestdiff = (satoshis - target); + if ( bestdiff < 0 ) + bestdiff = -bestdiff; + //err = ((double)bestdiff / target); + //n = (int32_t)(err * 4. * bestrate); + //if ( n < 1000 ) + // n = 1000; + //printf("err %f %d: new bestdiff %llu, bestrate %llu, satoshis %.8f target %.8f\n",err,n,(long long)bestdiff,(long long)bestrate,(double)satoshis/PRICE_RESOLUTION,(double)target/PRICE_RESOLUTION); + //for (i=0,rate=bestrate-n; rate<=bestrate+2*n; rate++,i++) + for (i=0,rate=1; rate %llu, rate %llu -> %llu, satoshis %.8f target %.8f\n",i,n,(long long)bestdiff,(long long)diff,(long long)bestrate,(long long)rate,(double)satoshis/PRICE_RESOLUTION,(double)target/PRICE_RESOLUTION); + bestdiff = diff, bestrate = rate, bestsatoshis = satoshis; + if ( diff == 0 ) + break; + } + } + //printf("\nnew bestdiff %llu rate %llu, satoshis %.8f target %.8f\n",(long long)bestdiff,(long long)bestrate,(double)bestsatoshis/PRICE_RESOLUTION,(double)target/PRICE_RESOLUTION); + *spreadp = PERCENTAGE((apr * maxdays)/365); + return(bestrate); +} + +uint64_t peggy_dailyrates() +{ + //struct peggy_limits limits = { { PERCENTAGE(10), PERCENTAGE(25), PERCENTAGE(33), PERCENTAGE(50) }, SATOSHIDEN * 10000, SATOSHIDEN * 1000, { 0, 30, 90, 180 }, 4 }; + uint64_t satoshis,maxspread; int64_t err,errsum; int32_t i,milliperc; + dailyrates[0] = (int32_t)map_apr(&maxspread,PEGGY_MAXLOCKDAYS,(double)7770/1000); + satoshis = peggy_compound(0,SATOSHIDEN,dailyrates[0],365); + printf("%.2f%% %d %llu -> %llu %.2f%%\n",(double)7770/1000,dailyrates[0],(long long)SATOSHIDEN,(long long)satoshis,100. * ((double)(satoshis-SATOSHIDEN)/SATOSHIDEN)); + for (errsum=i=0; i<=100; i++) + { + satoshis = peggy_compound(0,SATOSHIDEN,dailyrates[i],365); + //printf("%.1f%%: %d %llu -> %llu %.3f%%\n",(double)i*.1,dailyrates[i],(long long)PRICE_RESOLUTION,(long long)satoshis,100. * (double)satoshis/PRICE_RESOLUTION - 100.); + printf("%.2f%% ",100. * (double)satoshis/SATOSHIDEN - 100.); + err = (satoshis - SATOSHIDEN) - (i == 0 ? 7770000 : i*100000); + errsum += err < 0 ? -err : err; + //printf("i.%d err %lld sum %lld\n",i,(long long)err,(long long)errsum); + } + errsum /= 101; + printf("dailyrate check errsum %lld %f%% ave err\n",(long long)errsum,100*dstr(errsum)); + if ( errsum > 10000 ) + { + //int32_t dailyrates[101]; + for (milliperc=100; milliperc<=10000; milliperc+=100) + { + dailyrates[milliperc/100] = (int32_t)map_apr(&maxspread,PEGGY_MAXLOCKDAYS,(double)milliperc/1000); + satoshis = peggy_compound(0,SATOSHIDEN,dailyrates[milliperc/100],365); + printf("%.2f%% %d %llu -> %llu %.3f%%\n",(double)milliperc/1000,dailyrates[milliperc/100],(long long)SATOSHIDEN,(long long)satoshis,100. * ((double)(satoshis-SATOSHIDEN)/SATOSHIDEN)); + } + for (i=0; i<=100; i++) + printf("%d, ",dailyrates[i]); + printf("dailyrates in 0.1%% incr\n"); + printf("root.%lld resolution.%lld squared.%llu maxPval.%llu maxunits.%d\n",(long long)PRICE_RESOLUTION_ROOT,(long long)PRICE_RESOLUTION,(long long)PRICE_RESOLUTION2,(long long)PRICE_RESOLUTION_MAXPVAL,PRICE_RESOLUTION_MAXUNITS); + } + return(errsum); +} + +void *peggy_replay(char *path,struct txinds777_info *opreturns,void *_PEGS,uint32_t blocknum,char *opreturnstr,uint8_t *data,int32_t datalen) +{ + int32_t lookbacks[OPRETURNS_CONTEXTS]; long allocsize; uint64_t len; int32_t n,signedcount,valid=0; + long offset; struct price_resolution tmp; + char fname[512]; uint8_t opret[8192]; struct peggy_tx Ptx; struct peggy_info *PEGS = _PEGS; + if ( blocknum == 0 ) + opreturnstr = PEGGY_GENESIS; + //printf("replay genesis.%p opreturnstr.%p data.%p\n",PEGGY_GENESIS,opreturnstr,data); + if ( data == 0 ) + { + data = opret; + if ( opreturnstr == 0 ) + { + sprintf(fname,"%s/%d",path,blocknum); + if ( (opreturnstr= OS_filestr(&allocsize,fname)) != 0 ) + { + //printf("loaded.(%s) %s\n",fname,opreturnstr); + if ( is_hexstr(opreturnstr,(int32_t)strlen(opreturnstr)) != 0 ) + valid = 1; + } //else printf("couldnt find.(%s)\n",fname); + } else valid = 1; + if ( valid != 0 ) + { + datalen = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opret,datalen,opreturnstr); + } else return(0); + } + if ( data != 0 && data[0] == OP_RETURN_OPCODE ) + { + offset = hdecode_varint(&len,data,1,sizeof(opret)); + if ( data[offset] == 'P' && data[offset+1] == 'A' && data[offset+2] == 'X' ) + { + if ( (n= serdes777_deserialize(&signedcount,&Ptx,0,&data[offset+3],(int32_t)(len - 3))) < 0 ) + printf("peggy_process.%d peggy_deserialize error datalen.%d t%d\n",blocknum,datalen,Ptx.timestamp); + else + { + int32_t j,nonz = 0; + for (j=0; j PEGS->genesistime ) + { + Ptx.flags |= PEGGY_FLAGS_PEGGYBASE; + if ( peggy_process(PEGS,1,&Ptx.funding.src.coinaddr,Ptx.funding.amount,&data[offset+3],(int32_t)len-3,blocknum,Ptx.timestamp,blocknum) < 0 ) + { + printf("error processing blocknum.%u Ptx.blocknum %u\n",blocknum,blocknum); + } + } + if ( PEGS != 0 ) + PEGS->numopreturns++; + } + } else printf("illegal.(%c%c%c)\n",data[offset],data[offset+1],data[offset+2]); + } else printf("missing OP_RETURN_OPCODE [%02x]\n",data[0]); + return(PEGS); +} + +uint32_t peggy_currentblock(void *_PEGS) { struct peggy_info *PEGS; if ( (PEGS= _PEGS) != 0 ) return(PEGS->numopreturns); return(0); } + +void peggy_geninds() +{ + int32_t inds[PEGGY_NUMCOEFFS],tmp,i,n = PEGGY_NUMCOEFFS; + for (i=0; i 0 ) + { + i = ((rand() >> 8) % n); + //printf("(n.%d [%d] i.%d [%d]) ",n,inds[n],i,inds[i]); + n--; + tmp = inds[n]; + inds[n] = inds[i]; + inds[i] = tmp; + } + for (i=0; inumopreturns,(OS_milliseconds() - startmilli)/PEGS->numopreturns);// getchar(); + return(PEGS); +} + +int32_t peggy_init_contexts(struct txinds777_info *opreturns,uint32_t RTblocknum,uint32_t RTblocktimestamp,char *path,void *globals[OPRETURNS_CONTEXTS],int32_t lookbacks[OPRETURNS_CONTEXTS],int32_t maxcontexts) +{ + double startmilli; char buf[512]; struct price_resolution spread; struct peggy_info *PEGS=0,*PEGS2=0; + if ( maxcontexts != 2 ) + { + printf("peggy needs 2 contexts\n"); + exit(-1); + } + calc_smooth_code(127,7); + if ( sizeof(Peggy_inds)/sizeof(*Peggy_inds) != PEGGY_NUMCOEFFS ) + { + peggy_geninds(); + printf("need to update Peggy_inds with above\n"); + exit(-1); + } + peggy_dailyrates(); + spread.Pval = PERCENTAGE(1); + //if ( (PEGS= peggy_lchain(opreturns,"opreturns")) == 0 ) + PEGS = peggy_init(path,PEGGY_MAXLOCKDAYS,"BTCD",SATOSHIDEN/100,100,10,spread,PEGGY_RATE_777,40,10,2,5,2,0,0); + globals[0] = PEGS; + sprintf(buf,"%s_PERM",path); + globals[1] = PEGS2 = peggy_init(buf,PEGGY_MAXLOCKDAYS,"BTCD",SATOSHIDEN/100,1,1,spread,PEGGY_RATE_777,40,10,2,5,2,PEGS->genesistime,PEGS->BTCD_price0); + startmilli = OS_milliseconds(); + peggy_clone(buf,PEGS2,PEGS); + printf("cloned %d in %.3f millis per opreturn\n",PEGS->numopreturns,(OS_milliseconds() - startmilli)/PEGS->numopreturns); sleep(3); + return(2); +} diff --git a/iguana/peggy.h b/iguana/peggy.h new file mode 100755 index 000000000..c9b3e23a6 --- /dev/null +++ b/iguana/peggy.h @@ -0,0 +1,375 @@ +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +#ifndef INCLUDE_PAX_H +#define INCLUDE_PAX_H + +#define PEGGY_GENESIS "6aef504158ec0014fee05dc20a0006048ed63e523f6d1062feb23622da928cf23ddcc3b53f23566bc6cab5ebd77cfbf8f0bccb34bff73c55d742dd232994bfbffe1cbab7119ab3d653a256b02d5b6f56c05b8817799f0d242f48c26d35c992ebfff14acdefbe253345d394e84d975334cd55f7d6cbad5a7bd9425b1d5db44944d40be5304b7b62ba0dbc20d3323d2b35f05f654bc95a5a2fdb5a30e46c6fd33b5ea078255f7cad9fd0dbd2fa5031ada4474cbba7b2ee64ef35df06bf3fd3eef6cd3f48339f3c0e080158a92862bbf20bc6702018effbaee525502eb463c74f7ca0dff4ae7cb55ee55ef7cb1c915e655649" + +#include "iguana777.h" +// CfB "the rule is simple = others can know the redemption day only AFTER the price for that day is set in stone." +#define PEGGY_NUMCOEFFS 539 +#define ACCTS777_MAXRAMKVS 8 +#define BTCDADDRSIZE 36 + +#define HASH_SIZE 32 +#define PEGGY_MINUTE 60 +#define PEGGY_HOURTICKS (PEGGY_MINUTE * 60) +#define PEGGY_DAYTICKS (24 * PEGGY_HOURTICKS) +#define MAX_TIMEFRAME (24 * 3600 * 365) +#define MAX_PEGGYDAYS (365) +#define PEGGY_MINEXTRADAYS 3 + +#define PEGGY_MAXPRICEDPEGS 64 +#define PEGGY_MAXPAIREDPEGS 4096 +#define PEGGY_MAXPEGS (PEGGY_MAXPRICEDPEGS + PEGGY_MAXPAIREDPEGS) + +#define PEGGY_MAXVOTERS 4096 +#define PEGGY_MARGINMAX 100 +#define PEGGY_MIXRANGE 7777 +#define PEGGY_MARGINLOCKDAYS 30 +#define PEGGY_MARGINGAPDAYS 7 + +#define PEGGY_RATE_777 2052 + +#define OP_RETURN_OPCODE 0x6a +#define OPRETURNS_CONTEXTS 2 + +#define MAX_OPRETURNSIZE 4096 +#define PEGGY_MAXLOCKDAYS 180 +#define PEGGY_PASTSTAMP 3600 +#define PEGGY_FUTURESTAMP 60 + +#define PEGGY_RSTATUS_REDEEMED 0 +#define PEGGY_RSTATUS_AUTOPURGED 1 +#define PEGGY_RSTATUS_MARGINCALL 2 + +#define PEGGY_FLAGS_HASFUNDING 1 +#define PEGGY_FLAGS_PEGGYBASE 2 + +#define PEGGY_ADDRBTCD 0 +#define PEGGY_ADDRCREATE 1 +#define PEGGY_ADDRNXT 2 +#define PEGGY_ADDRUNIT 3 +#define PEGGY_ADDRPUBKEY 4 +#define PEGGY_ADDR777 5 +#define PEGGY_ADDRFUNDING 6 + +#define USD 0 +#define EUR 1 +#define JPY 2 +#define GBP 3 +#define AUD 4 +#define CAD 5 +#define CHF 6 +#define NZD 7 +#define CNY 8 +#define RUB 9 + +#define NZDUSD 0 +#define NZDCHF 1 +#define NZDCAD 2 +#define NZDJPY 3 +#define GBPNZD 4 +#define EURNZD 5 +#define AUDNZD 6 +#define CADJPY 7 +#define CADCHF 8 +#define USDCAD 9 +#define EURCAD 10 +#define GBPCAD 11 +#define AUDCAD 12 +#define USDCHF 13 +#define CHFJPY 14 +#define EURCHF 15 +#define GBPCHF 16 +#define AUDCHF 17 +#define EURUSD 18 +#define EURAUD 19 +#define EURJPY 20 +#define EURGBP 21 +#define GBPUSD 22 +#define GBPJPY 23 +#define GBPAUD 24 +#define USDJPY 25 +#define AUDJPY 26 +#define AUDUSD 27 + +#define USDNUM 28 +#define EURNUM 29 +#define JPYNUM 30 +#define GBPNUM 31 +#define AUDNUM 32 +#define CADNUM 33 +#define CHFNUM 34 +#define NZDNUM 35 + +#define NUM_CONTRACTS 28 +#define NUM_CURRENCIES 8 +#define NUM_COMBINED (NUM_CONTRACTS + NUM_CURRENCIES) +#define MAX_SPLINES 64 +#define MAX_LOOKAHEAD 48 + +#define MAX_EXCHANGES 64 +#define MAX_CURRENCIES 32 + +#define PRICE_RESOLUTION_ROOT ((int64_t)3163) +#define PRICE_RESOLUTION (PRICE_RESOLUTION_ROOT * PRICE_RESOLUTION_ROOT) // 10004569 +#define PRICE_RESOLUTION2 (PRICE_RESOLUTION * PRICE_RESOLUTION) // 100091400875761 +#define PRICE_RESOLUTION_MAXPVAL ((int64_t)3037000500u) // 303.5613528178975 vs 64 bits: 4294967295 429.30058206405493, +#define PRICE_RESOLUTION_MAXUNITS ((int16_t)((int64_t)0x7fffffffffffffffLLu / (SATOSHIDEN * PRICE_RESOLUTION))) // 9219 +#define SCALED_PRICE(val,scale) (((scale) * (val)) / PRICE_RESOLUTION) +#define Pval(r) ((double)(r)->Pval / PRICE_RESOLUTION) // for display only! +#define PERCENTAGE(perc) (((perc) * PRICE_RESOLUTION) / 100) + +struct price_resolution { int64_t Pval; }; +struct peggy_lock { int16_t peg,denom; uint16_t minlockdays,maxlockdays,clonesmear,mixrange,redemptiongapdays; uint8_t extralockdays,margin; }; + +struct peggy_newunit { bits256 sha256; struct peggy_lock newlock; }; +struct peggy_univaddr { uint8_t addrtype,rmd160[20]; char coin[7]; }; +union peggy_addr { struct peggy_univaddr coinaddr; struct peggy_newunit newunit; bits256 sha256; bits384 SaMbits; uint64_t nxt64bits; }; +struct peggy_input { uint8_t type,chainlen; union peggy_addr src; uint64_t amount; }; +struct peggy_output { uint8_t type,vin; union peggy_addr dest; uint32_t ratio; }; + +struct peggy_txprices { uint16_t num,maxlockdays; uint32_t timestamp; uint32_t feed[256]; }; +struct peggy_txbet { struct price_resolution prediction; char peg[15],binary; }; +struct peggy_txmicropay { bits256 claimhash,refundhash; uint32_t expiration; uint8_t chainlen,vin,vout; }; +struct peggy_time { uint32_t blocknum,blocktimestamp; }; +struct peggy_units { int64_t num,numoppo; }; +struct peggy_margin { int64_t deposits,margindeposits,marginvalue; }; +struct peggy_description { char name[32],base[16],rel[16]; uint64_t basebits,relbits,assetbits; int16_t id,baseid,relid; int8_t hasprice,enabled; }; +struct peggy_pool { struct peggy_margin funds; struct peggy_units liability; uint64_t quorum,decisionthreshold,mainunitsize,mainbits; }; +//struct peggy_limits { int64_t scales[MAX_TIMEFRAMES],maxsupply,maxnetbalance; uint32_t timeframes[MAX_TIMEFRAMES],numtimeframes; }; + +#define PEGGY_MAXSIGS 16 +#define PEGGY_MAXINPUTS 15 +#define PEGGY_MAXOUTPUTS 16 + +#define PEGGY_TXNORMAL 0 +#define PEGGY_TXBET 1 +#define PEGGY_TXPRICES 2 +#define PEGGY_TXTUNE 3 +#define PEGGY_TXMICROPAY 4 +union peggy_bytes8 { uint8_t bytes[8]; uint64_t val; }; +struct peggy_txtune { char type,peg[15]; uint64_t val; union peggy_bytes8 B; }; + +union peggy_txtype +{ + struct peggy_txprices price; struct peggy_txbet bets[64]; struct peggy_txtune tune[64]; + struct peggy_txmicropay micropays[16]; +}; + +struct PAX_sig { bits256 sigbits,pubkey; uint64_t signer64bits; uint32_t timestamp,allocsize; }; + +struct peggy_tx +{ + uint16_t datalen; uint8_t numinputs,numoutputs,txtype,flags,msglen,numdetails; uint32_t timestamp,activation,expiration; + struct peggy_input inputs[PEGGY_MAXINPUTS],funding; struct peggy_output outputs[PEGGY_MAXOUTPUTS]; + union peggy_txtype details; char hexstr[512]; + uint8_t data[4096]; + struct PAX_sig sigs[PEGGY_MAXSIGS]; + //uint64_t required; +}; + +struct peggy_unit +{ + int64_t estimated_interest,costbasis,amount,marginamount; uint32_t timestamp; int16_t dailyrate; uint8_t baseid,relid; + struct peggy_lock lock; bits256 lockhash; +}; + +struct peggy +{ + struct peggy_description name; struct peggy_pool pool; struct peggy_lock lockparms; int64_t maxsupply,maxnetbalance; + struct price_resolution spread,mindenomination,genesisprice,price,dayprice; uint32_t day,genesistime,maxdailyrate,unitincr,peggymils; + uint32_t dayprices[MAX_PEGGYDAYS],*baseprices,*relprices; int32_t RTminute; +}; + +struct peggy_pricedpeg +{ + struct peggy PEG; + uint32_t prices[MAX_PEGGYDAYS * 1440]; // In main currency units +}; + +union peggy_pair { struct peggy PEG; struct peggy_pricedpeg pricedPEG; }; + +struct peggy_bet { struct price_resolution prediction; uint64_t distbet,dirbet,payout,shares,dist; uint32_t timestamp,minutes; }; +struct peggy_vote { int32_t pval,tolerance; };//struct price_resolution price,tolerance; uint64_t nxt64bits,weight; }; +struct peggy_entry +{ + int64_t total,costbasis,satoshis,royalty,fee,estimated_interest,interest_unlocked,interestpaid,supplydiff,denomination; + int16_t dailyrate,baseid,relid,polarity; + struct peggy_units supply; struct price_resolution price,oppoprice; +}; + +struct peggy_balances { struct peggy_margin funds; int64_t privatebetfees,crypto777_royalty,APRfund,APRfund_reserved; }; + +struct PAX_data +{ + uint32_t ttimestamps[128]; double tbids[128],tasks[128]; + uint32_t ftimestamps[128]; double fbids[128],fasks[128]; + uint32_t itimestamps[128]; double ibids[128],iasks[128]; + char edate[128]; double ecbmatrix[32][32],dailyprices[MAX_CURRENCIES * MAX_CURRENCIES],metals[4]; + int32_t ecbdatenum,ecbyear,ecbmonth,ecbday; double RTmatrix[32][32],RTprices[128],RTmetals[4]; + double btcusd,btcdbtc,cryptos[8]; +}; + +struct PAX_spline { char name[64]; int32_t splineid,lasti,basenum,num,firstx,dispincr,spline32[MAX_SPLINES][4]; uint32_t utc32[MAX_SPLINES]; int64_t spline64[MAX_SPLINES][4]; double dSplines[MAX_SPLINES][4],pricevals[MAX_SPLINES+MAX_LOOKAHEAD],lastutc,lastval,aveslopeabs; }; + +struct peggy_info +{ + char maincurrency[16]; uint64_t basebits[256],mainbits,mainunitsize,quorum,decisionthreshold; int64_t hwmbalance,worstbalance,maxdrawdown; + struct price_resolution default_spread; struct peggy_lock default_lockparms; + struct peggy_balances bank,basereserves[256]; + int32_t default_dailyrate,interesttenths,posboost,negpenalty,feediv,feemult; + int32_t numpegs,numpairedpegs,numpricedpegs,numopreturns,numvoters; + struct accts777_info *accts; + struct PAX_data data,tmp; double cryptovols[2][8][2],btcusd,btcdbtc,cnyusd; + char path[512],*genesis; uint32_t genesistime,BTCD_price0,lastupdate; + struct PAX_spline splines[128]; + struct peggy_vote votes[PEGGY_MAXPRICEDPEGS][PEGGY_MAXVOTERS]; + struct peggy *contracts[PEGGY_MAXPEGS]; + struct peggy pairedpegs[PEGGY_MAXPRICEDPEGS + PEGGY_MAXPAIREDPEGS]; + struct peggy_pricedpeg pricedpegs[PEGGY_MAXPRICEDPEGS]; +}; + +struct txinds777_hdr { int64_t num,nextpos; uint32_t blocknum,timestamp,firstblocknum,lastblocknum; struct sha256_vstate state; bits256 sha256; }; +struct txinds777_info +{ + struct txinds777_hdr H; + FILE *txlogfp,*indexfp,*fp; char path[512],name[64]; int64_t curitem,*blockitems; +}; + +int64_t txind777_bundle(struct txinds777_info *txinds,uint32_t blocknum,uint32_t timestamp,int64_t *bundle,int32_t numtx); +int64_t txind777_create(struct txinds777_info *txinds,uint32_t blocknum,uint32_t timestamp,void *txdata,uint16_t len); +int32_t txind777_txbuf(uint8_t *txbuf,int32_t len,uint64_t val,int32_t size); +int32_t txinds777_flush(struct txinds777_info *txinds,uint32_t blocknum,uint32_t blocktimestamp); +struct txinds777_info *txinds777_init(char *path,char *name); +int64_t txinds777_seek(struct txinds777_info *txinds,uint32_t blocknum); +void *txinds777_read(int32_t *lenp,uint8_t *buf,struct txinds777_info *txinds); +void txinds777_purge(struct txinds777_info *txinds); + +struct ramkv777_item { UT_hash_handle hh; uint16_t valuesize,tbd; uint32_t rawind; uint8_t keyvalue[]; }; + +struct ramkv777 +{ + char name[63],threadsafe; + portable_mutex_t mutex; + struct ramkv777_item *table; + void **list; int32_t listsize,listmax; + struct sha256_vstate state; bits256 sha256; + int32_t numkeys,keysize,dispflag; uint8_t kvind; +}; + +#define ramkv777_itemsize(kv,valuesize) (sizeof(struct ramkv777_item) + (kv)->keysize + valuesize) +#define ramkv777_itemkey(item) (item)->keyvalue +#define ramkv777_itemvalue(kv,item) (&(item)->keyvalue[(kv)->keysize]) + +struct ramkv777_item *ramkv777_itemptr(struct ramkv777 *kv,void *value); +int32_t ramkv777_clone(struct ramkv777 *clone,struct ramkv777 *kv); +void ramkv777_free(struct ramkv777 *kv); + +int32_t ramkv777_delete(struct ramkv777 *kv,void *key); +void *ramkv777_write(struct ramkv777 *kv,void *key,void *value,int32_t valuesize); +void *ramkv777_read(int32_t *valuesizep,struct ramkv777 *kv,void *key); +void *ramkv777_iterate(struct ramkv777 *kv,void *args,void *(*iterator)(struct ramkv777 *kv,void *args,void *key,void *value,int32_t valuesize)); +struct ramkv777 *ramkv777_init(int32_t kvind,char *name,int32_t keysize,int32_t threadsafe); + +struct acct777 { uint32_t firstblocknum,firsttimestamp; int64_t balance; }; + +struct accts777_info +{ + queue_t PaymentsQ; + uint64_t balance; + struct peggy_unit *units; + int32_t numunits; uint8_t numkvs; + struct ramkv777 *bets,*pricefeeds,*hashaddrs,*coinaddrs,*SaMaddrs,*nxtaddrs,*addrkvs[16]; + bits256 peggyhash; + struct txinds777_info *txinds; +}; + +struct accts777_info *accts777_init(char *dirname,struct txinds777_info *txinds); + +#define YAHOO_METALS "XAU", "XAG", "XPT", "XPD" +extern char *peggy_bases[64],CURRENCIES[][8]; +extern int32_t MINDENOMS[],Peggy_inds[],dailyrates[]; + +struct price_resolution peggy_scaleprice(struct price_resolution price,int64_t peggymils); +char *peggy_tx(char *jsonstr); +void _crypto_update(struct peggy_info *PEGS,double cryptovols[2][8][2],struct PAX_data *dp,int32_t selector,int32_t peggyflag); +int32_t PAX_idle(struct peggy_info *PEGS,int32_t peggyflag,int32_t idlegap); +int32_t PAX_genspline(struct PAX_spline *spline,int32_t splineid,char *name,uint32_t *utc32,double *splinevals,int32_t maxsplines,double *refvals); +int32_t PAX_contractnum(char *base,char *rel); +int32_t PAX_basenum(char *base); +int32_t PAX_ispair(char *base,char *rel,char *contract); +void PAX_init(struct peggy_info *PEGS); +uint32_t peggy_mils(int32_t i); +void calc_smooth_code(int32_t smoothwidth,int32_t _maxprimes); +struct peggy *peggy_find(struct peggy_entry *entry,struct peggy_info *PEGS,char *name,int32_t polarity); +struct price_resolution peggy_priceconsensus(struct peggy_info *PEGS,struct peggy_time T,uint64_t seed,int16_t pricedpeg,struct peggy_vote *votes,uint32_t numvotes,struct peggy_bet *bets,uint32_t numbets); +struct price_resolution peggy_price(struct peggy *PEG,int32_t minute); +struct price_resolution peggy_shortprice(struct peggy *PEG,struct price_resolution price); +void peggy_delete(struct accts777_info *accts,struct peggy_unit *U,int32_t reason); +int32_t peggy_setprice(struct peggy *PEG,struct price_resolution price,int32_t minute); +int32_t peggy_pegstr(char *buf,struct peggy_info *PEGS,char *name); +struct acct777 *accts777_find(int32_t *valuesizep,struct accts777_info *accts,union peggy_addr *addr,int32_t type); +struct acct777 *accts777_create(struct accts777_info *accts,union peggy_addr *addr,int32_t type,uint32_t blocknum,uint32_t blocktimestamp); +int64_t acct777_balance(struct accts777_info *accts,uint32_t blocknum,uint32_t blocktimestamp,union peggy_addr *addr,int32_t type); +uint64_t peggy_redeem(struct peggy_info *PEGS,struct peggy_time T,int32_t readonly,char *name,int32_t polarity,uint64_t nxt64bits,bits256 pubkey,uint16_t lockdays,uint8_t chainlen); +#define accts777_getaddrkv(accts,type) ((accts != 0) ? (accts)->addrkvs[type] : 0) +uint64_t peggy_poolmainunits(struct peggy_entry *entry,int32_t dir,int32_t polarity,struct price_resolution price,struct price_resolution oppoprice,struct price_resolution spread,uint64_t poolincr,int16_t denomunits); +int32_t acct777_pay(struct accts777_info *accts,struct acct777 *srcacct,struct acct777 *acct,int64_t value,uint32_t blocknum,uint32_t blocktimestamp); +struct peggy *peggy_findpeg(struct peggy_entry *entry,struct peggy_info *PEGS,int32_t peg); +void peggy_thanks_you(struct peggy_info *PEGS,int64_t tip); +uint64_t peggy_createunit(struct peggy_info *PEGS,struct peggy_time T,struct peggy_unit *readU,uint64_t seed,char *name,uint64_t nxt64bits,bits256 lockhash,struct peggy_lock *lock,uint64_t amount,uint64_t marginamount); +int32_t peggy_swap(struct accts777_info *accts,uint64_t signerA,uint64_t signerB,bits256 hashA,bits256 hashB); +int32_t peggy_aprpercs(int64_t dailyrate); +int64_t peggy_lockrate(struct peggy_entry *entry,struct peggy_info *PEGS,struct peggy *PEG,uint64_t satoshis,uint16_t numdays); +char *peggy_emitprices(int32_t *nonzp,struct peggy_info *PEGS,uint32_t blocktimestamp,int32_t maxlockdays); +int64_t peggy_compound(int32_t dispflag,int64_t satoshis,int64_t dailyrate,int32_t n); + +#define MAX_OPRETURNSIZE 4096 +struct opreturn_payment { struct queueitem DL; uint64_t value; char coinaddr[BTCDADDRSIZE]; }; +struct opreturn_entry { struct opreturn_payment vout; uint32_t timestamp,blocknum; uint16_t isstaked,txind,v,datalen; uint8_t data[MAX_OPRETURNSIZE]; }; + +int64_t peggy_process(void *context,int32_t flags,void *fundedcoinaddr,uint64_t fundedvalue,uint8_t *data,int32_t datalen,uint32_t currentblocknum,uint32_t blocktimestamp,uint32_t stakedblock); +int32_t opreturns_gotnewblock(uint32_t blocknum,uint32_t blocktimestamp,char *opreturns[],int32_t numopreturns,char *peggybase_opreturnstr); +char *opreturns_stakinginfo(char opreturnstr[8192],uint32_t blocknum,uint32_t blocktimestamp); + +int32_t opreturns_process(int32_t flags,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp,struct opreturn_entry *list,int32_t num,uint8_t *peggyopreturn,int32_t peggylen); +int32_t opreturns_queue_payment(queue_t *PaymentsQ,uint32_t blocktimestamp,char *coinaddr,int64_t value); +int32_t opreturns_init(uint32_t blocknum,uint32_t blocktimestamp,char *path); +void *opreturns_context(char *name,int32_t context); +long hdecode_varint(uint64_t *valp,uint8_t *ptr,long offset,long mappedsize); + +uint64_t conv_acctstr(char *acctstr); +int32_t serdes777_deserialize(int32_t *signedcountp,struct peggy_tx *Ptx,uint32_t blocktimestamp,uint8_t *data,int32_t totallen); +int32_t serdes777_serialize(struct peggy_tx *Ptx,uint32_t blocktimestamp,bits256 privkey,uint32_t timestamp); +int32_t peggy_univ2addr(char *coinaddr,struct peggy_univaddr *ua); +int32_t peggy_addr2univ(struct peggy_univaddr *ua,char *coinaddr,char *coin); +uint64_t PAX_validate(struct PAX_sig *sig,uint32_t timestamp,uint8_t *data,int32_t datalen); +uint64_t PAX_signtx(struct PAX_sig *sig,bits256 privkey,uint32_t timestamp,uint8_t *data,int32_t datalen); + +int64_t peggy_process(void *context,int32_t flags,void *fundedcoinaddr,uint64_t fundedvalue,uint8_t *data,int32_t datalen,uint32_t currentblocknum,uint32_t blocktimestamp,uint32_t stakedblock); +int32_t peggy_emit(void *context,uint8_t opreturndata[MAX_OPRETURNSIZE],struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp); +int32_t peggy_flush(void *context,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp); +int32_t peggy_init_contexts(struct txinds777_info *opreturns,uint32_t blocknum,uint32_t blocktimestamp,char *path,void *globals[OPRETURNS_CONTEXTS],int32_t lookbacks[OPRETURNS_CONTEXTS],int32_t maxcontexts); +uint32_t peggy_clone(char *path,void *dest,void *src); +void *peggy_replay(char *path,struct txinds777_info *opreturns,void *_PEGS,uint32_t blocknum,char *opreturnstr,uint8_t *data,int32_t datalen); +uint32_t peggy_currentblock(void *globals); + +struct peggy_unit *peggy_match(struct accts777_info *accts,int32_t peg,uint64_t nxt64bits,bits256 lockhash,uint16_t lockdays); +int32_t peggy_addunit(struct accts777_info *accts,struct peggy_unit *U,bits256 lockhash); + +#endif diff --git a/iguana/peggy_accts.c b/iguana/peggy_accts.c new file mode 100755 index 000000000..7dbe1c2f6 --- /dev/null +++ b/iguana/peggy_accts.c @@ -0,0 +1,325 @@ +/****************************************************************************** + * 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 "peggy.h" + +#define accts777_getaddrkv(accts,type) ((accts != 0) ? (accts)->addrkvs[type] : 0) + +bits256 PAX_hashiter(bits256 privkey,bits256 pubkey,int32_t lockdays,uint8_t chainlen) +{ + uint16_t lockseed,signlen = 0; uint8_t signbuf[16]; bits256 shared,lockhash; + lockseed = (chainlen & 0x7f) | (lockdays << 7); + signlen = 0, signbuf[signlen++] = lockseed & 0xff, signbuf[signlen++] = (lockseed >> 8) & 0xff; + + privkey.bytes[0] &= 248, privkey.bytes[31] &= 127, privkey.bytes[31] |= 64; + shared = curve25519(privkey,pubkey); + vcalc_sha256cat(lockhash.bytes,shared.bytes,sizeof(shared),signbuf,signlen); + return(lockhash); +} + +bits256 PAX_lockhash(bits256 pubkey,int32_t lockdays,uint8_t chainlen) +{ + bits256 lockhash = GENESIS_PRIVKEY; + while ( chainlen > 0 ) + lockhash = PAX_hashiter(lockhash,pubkey,lockdays,chainlen--); + return(lockhash); +} + +bits256 PAX_invoicehash(bits256 *invoicehash,uint16_t lockdays,uint8_t chainlen) +{ + int32_t i; bits256 lockhash,privkey; + OS_randombytes(privkey.bytes,sizeof(privkey)); // both privkey and pubkey are sensitive. pubkey allows verification, privkey proves owner + lockhash = privkey; + for (i=0; i>=8) + buf[i] = (t & 0xff); + sig->timestamp = timestamp; + shared = curve25519(privkey,otherpubkey); + memcpy(&buf[sizeof(timestamp)],shared.bytes,sizeof(shared)); + vcalc_sha256cat(sig->sigbits.bytes,buf,sizeof(buf),data,datalen); + sig->pubkey = acct777_pubkey(privkey), sig->signer64bits = acct777_nxt64bits(sig->pubkey); + //printf(" calcsig.%llx pubkey.%llx signer.%llu | t%u crc.%08x len.%d shared.%llx <- %llx * %llx\n",(long long)sig->sigbits.txid,(long long)sig->pubkey.txid,(long long)sig->signer64bits,timestamp,_crc32(0,data,datalen),datalen,(long long)shared.txid,(long long)privkey.txid,(long long)otherpubkey.txid); + return(sig->signer64bits); +} + +uint64_t PAX_validate(struct PAX_sig *sig,uint32_t timestamp,uint8_t *data,int32_t datalen) +{ + struct PAX_sig checksig; + PAX_sign(&checksig,GENESIS_PRIVKEY,sig->pubkey,timestamp,data,datalen); + if ( memcmp(checksig.sigbits.bytes,sig->sigbits.bytes,sizeof(checksig.sigbits)) != 0 ) + { + printf("sig compare error using sig->pub from %llu\n",(long long)acct777_nxt64bits(sig->pubkey)); + return(0); + } + return(acct777_nxt64bits(sig->pubkey)); +} + +uint64_t PAX_signtx(struct PAX_sig *sig,bits256 privkey,uint32_t timestamp,uint8_t *data,int32_t datalen) +{ + return(PAX_sign(sig,privkey,GENESIS_PUBKEY,timestamp,data,datalen)); +} + +uint64_t PAX_swaptx(bits256 privkey,struct PAX_sig *sig,uint32_t timestamp,uint8_t *data,int32_t datalen) +{ + uint64_t othernxt; + if ( (othernxt= PAX_validate(sig,timestamp,data,datalen)) != sig->signer64bits ) + return(0); + return(PAX_sign(sig,privkey,GENESIS_PUBKEY,timestamp,data,datalen)); +} + +struct accts777_info *accts777_init(char *dirname,struct txinds777_info *txinds) +{ + struct accts777_info *accts = calloc(1,sizeof(*accts)); + accts->hashaddrs = ramkv777_init(accts->numkvs++,"hashaddrs",sizeof(bits256),1); + accts->coinaddrs = ramkv777_init(accts->numkvs++,"coinaddrs",BTCDADDRSIZE,1); + accts->nxtaddrs = ramkv777_init(accts->numkvs++,"nxtaddrs",sizeof(uint64_t),1); + accts->SaMaddrs = ramkv777_init(accts->numkvs++,"SaMaddrs",sizeof(bits384),1); + accts->bets = ramkv777_init(accts->numkvs++,"bets",BTCDADDRSIZE,1); + accts->pricefeeds = ramkv777_init(accts->numkvs++,"pricefeeds",sizeof(uint32_t) * 2,1);//, accts->pricefeeds->dispflag = 0; + if ( accts->numkvs > ACCTS777_MAXRAMKVS ) + { + printf("too many ramkvs for accts %d vs %d\n",accts->numkvs,ACCTS777_MAXRAMKVS); + exit(-1); + } + accts->addrkvs[PEGGY_ADDRFUNDING] = accts->addrkvs[PEGGY_ADDRBTCD] = accts->coinaddrs; + accts->addrkvs[PEGGY_ADDR777] = accts->SaMaddrs; + accts->addrkvs[PEGGY_ADDRNXT] = accts->nxtaddrs; + accts->addrkvs[PEGGY_ADDRCREATE] = accts->addrkvs[PEGGY_ADDRUNIT] = accts->addrkvs[PEGGY_ADDRPUBKEY] = accts->hashaddrs; + if ( (accts->txinds= txinds) == 0 ) + accts->txinds = txinds777_init(dirname,"txinds"); + return(accts); +} + +void accts777_free(struct accts777_info *accts) +{ + int32_t i; + queue_free(&accts->PaymentsQ); + for (i=0; iaddrkvs)/sizeof(*accts->addrkvs); i++) + if ( accts->addrkvs[i] != 0 ) + ramkv777_free(accts->addrkvs[i]); + free(accts); +} + +struct accts777_info *accts777_clone(char *path,struct accts777_info *accts) +{ + struct accts777_info *clone; + clone = accts777_init(path,accts->txinds); + queue_clone(&clone->PaymentsQ,&accts->PaymentsQ,sizeof(struct opreturn_payment)); + if ( accts->numunits > 0 && accts->units != 0 ) + { + clone->units = calloc(accts->numunits,sizeof(*accts->units)); + memcpy(clone->units,accts->units,accts->numunits * sizeof(*accts->units)); + } + clone->peggyhash = accts->peggyhash; + ramkv777_clone(clone->bets,accts->bets); + ramkv777_clone(clone->pricefeeds,accts->pricefeeds); + ramkv777_clone(clone->hashaddrs,accts->hashaddrs); + ramkv777_clone(clone->coinaddrs,accts->coinaddrs); + ramkv777_clone(clone->SaMaddrs,accts->SaMaddrs); + ramkv777_clone(clone->nxtaddrs,accts->nxtaddrs); + return(clone); +} + +void *accts777_key(union peggy_addr *addr,int32_t type) +{ + void *key; + switch ( type ) + { + case PEGGY_ADDRFUNDING: case PEGGY_ADDRBTCD: key = &addr->coinaddr; break; + case PEGGY_ADDRNXT: key = &addr->nxt64bits; break; + case PEGGY_ADDR777: key = &addr->SaMbits; break; + case PEGGY_ADDRCREATE: key = &addr->newunit.sha256; break; + case PEGGY_ADDRUNIT: key = &addr->sha256; break; + case PEGGY_ADDRPUBKEY: key = &addr->sha256; break; + default: key = 0; break; + } + return(key); +} + +struct acct777 *accts777_find(int32_t *valuesizep,struct accts777_info *accts,union peggy_addr *addr,int32_t type) +{ + void *key; + if ( (key= accts777_key(addr,type)) != 0 ) + return(ramkv777_read(valuesizep,accts->addrkvs[type],key)); + else + { + if ( valuesizep != 0 ) + *valuesizep = 0; + return(0); + } +} + +struct acct777 *accts777_create(struct accts777_info *accts,union peggy_addr *addr,int32_t type,uint32_t blocknum,uint32_t blocktimestamp) +{ + struct acct777 *acct,A; + if ( (acct= accts777_find(0,accts,addr,type)) == 0 ) + { + memset(&A,0,sizeof(A)); + A.firstblocknum = blocknum, A.firsttimestamp = blocktimestamp; + acct = ramkv777_write(accts->addrkvs[type],accts777_key(addr,type),&A,sizeof(A)); + } + else if ( blocknum < acct->firstblocknum || blocktimestamp < acct->firsttimestamp ) + { + printf("accts777_create: already exists but with an earlier block/timestamp? %u:%u vs %u:%u\n",blocknum,acct->firstblocknum,blocktimestamp,acct->firsttimestamp); + return(0); + } + return(acct); +} + +void peggy_delete(struct accts777_info *accts,struct peggy_unit *U,int32_t reason) +{ + memcpy(U,&accts->units[--accts->numunits],sizeof(struct peggy_unit)); + //U->redeemed = (uint32_t)time(NULL); + //if ( PEGS->lockhashes != 0 ) + // kv777_delete(PEGS->lockhashes,U->lockPeriodHash,HASH_SIZE); +} + +int32_t peggy_addunit(struct accts777_info *accts,struct peggy_unit *U,bits256 lockhash) +{ + U->lockhash = lockhash; + accts->units = realloc(accts->units,sizeof(*accts->units) * (accts->numunits + 1)); + accts->units[accts->numunits] = *U; + //if ( PEGS->lockhashes != 0 ) + // kv777_write(PEGS->lockhashes,lockPeriodHash,HASH_SIZE,U,sizeof(*U)); + return(accts->numunits++); +} + +struct peggy_unit *peggy_match(struct accts777_info *accts,int32_t peg,uint64_t nxt64bits,bits256 lockhash,uint16_t lockdays) +{ + int32_t i,size; struct peggy_unit *U; + if ( accts->hashaddrs == 0 ) + { + for (i=0,U=&accts->units[0]; inumunits; i++,U++) + { + //if ( U->nxt64bits == 0 || U->nxt64bits == nxt64bits ) + { + if ( U->lock.peg == peg && lockdays >= U->lock.minlockdays && lockdays <= U->lock.maxlockdays ) + { + if ( memcmp(lockhash.bytes,U->lockhash.bytes,sizeof(lockhash)) == 0 ) + return(U); + return(0); + } + } + } + } + else + { + size = sizeof(*U); + if ( (U= ramkv777_read(&size,accts->hashaddrs,lockhash.bytes)) != 0 && size == sizeof(U) ) + { + //if ( U->nxt64bits == 0 || U->nxt64bits == nxt64bits ) + { + if ( U->lock.peg == peg && lockdays >= U->lock.minlockdays && lockdays <= U->lock.maxlockdays ) + return(U); + } + } + } + return(0); +} + +int32_t peggy_swap(struct accts777_info *accts,uint64_t signerA,uint64_t signerB,bits256 hashA,bits256 hashB) +{ + struct peggy_unit *U,*U2; int32_t size; uint64_t nxtA,nxtB; + size = sizeof(*U); + if ( (U= ramkv777_read(&size,accts->hashaddrs,hashA.bytes)) != 0 && size == sizeof(U) ) + { + if ( (U2= ramkv777_read(&size,accts->hashaddrs,hashB.bytes)) != 0 && size == sizeof(U2) ) + { + nxtA = acct777_nxt64bits(hashA), nxtB = acct777_nxt64bits(hashB); + if ( (nxtA == signerA && nxtB == signerB) || (nxtA == signerB && nxtB == signerA) ) + { + // need to verify ownership + U2->lockhash = hashA, U->lockhash = hashB; + return(0); + } + } + } + return(-1); +} + +int32_t acct777_pay(struct accts777_info *accts,struct acct777 *srcacct,struct acct777 *acct,int64_t value,uint32_t blocknum,uint32_t blocktimestamp) +{ + if ( srcacct != 0 ) + { + if ( srcacct->balance < value ) + return(-1); + srcacct->balance -= value; + } + acct->balance += value; + return(0); +} + +int64_t acct777_balance(struct accts777_info *accts,uint32_t blocknum,uint32_t blocktimestamp,union peggy_addr *addr,int32_t type) +{ + int64_t balance = 0; + struct acct777 *acct; + if ( (acct= accts777_find(0,accts,addr,type)) != 0 ) + balance = acct->balance; + return(balance); +} + +int32_t peggy_flush(void *_PEGS,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp) +{ + struct peggy_info *PEGS = _PEGS; + if ( PEGS != 0 && PEGS->accts != 0 ) + return(txinds777_flush(PEGS->accts->txinds,blocknum,blocktimestamp)); + else return(-1); +} + +int32_t peggy_payments(queue_t *PaymentsQ,struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp) +{ + struct opreturn_payment *payment; int32_t n = 0; + while ( max > 0 && (payment= queue_dequeue(PaymentsQ,0)) != 0 ) + { + if ( payment->value != 0 && payment->coinaddr[0] != 0 ) + *payments++ = *payment; + free(payment); + n++; + } + return(n); +} + +int32_t peggy_emit(void *_PEGS,uint8_t opreturndata[MAX_OPRETURNSIZE],struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp) +{ + char *opreturnstr; int32_t nonz,len = 0; struct peggy_info *PEGS = _PEGS; + if ( payments != 0 && max > 1 && PEGS->accts != 0 && peggy_payments(&PEGS->accts->PaymentsQ,payments,max,currentblocknum,blocknum,blocktimestamp) < 0 ) + return(-1); + if ( opreturndata != 0 && (opreturnstr= peggy_emitprices(&nonz,PEGS,blocktimestamp,0)) != 0 ) + { + memset(opreturndata,0,MAX_OPRETURNSIZE); + len = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opreturndata,len,opreturnstr); + free(opreturnstr); + } + return(len); +} + +uint32_t peggy_clone(char *path,void *dest,void *src) +{ + struct peggy_info *destPEGS,*srcPEGS; + printf("inside peggy_clone sizeof peggy_info %d %d %d\n",(int32_t)sizeof(*destPEGS),(int32_t)sizeof(destPEGS->pricedpegs),(int32_t)sizeof(destPEGS->pairedpegs));//, getchar(); + destPEGS = dest, srcPEGS = src; + *destPEGS = *srcPEGS; + destPEGS->accts = accts777_clone(path,srcPEGS->accts); + return(0); +} diff --git a/iguana/peggy_consensus.c b/iguana/peggy_consensus.c new file mode 100755 index 000000000..809a10060 --- /dev/null +++ b/iguana/peggy_consensus.c @@ -0,0 +1,829 @@ +/****************************************************************************** + * 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 "peggy.h" + +uint64_t peggy_smooth_coeffs[PEGGY_NUMCOEFFS] = // numprimes.13 +{ + 962714545, 962506087, 962158759, 961672710, 961048151, 960285354, 959384649, 958346426, 957171134, // x.8 + 955859283, 954411438, 952828225, 951110328, 949258485, 947273493, 945156207, 942907532, 940528434, // x.17 + 938019929, 935383089, 932619036, 929728945, 926714044, 923575608, 920314964, 916933485, 913432593, // x.26 + 909813756, 906078486, 902228342, 898264923, 894189872, 890004874, 885711650, 881311964, 876807614, // x.35 + 872200436, 867492300, 862685110, 857780804, 852781347, 847688737, 842505000, 837232189, 831872382, // x.44 + 826427681, 820900212, 815292123, 809605581, 803842772, 798005901, 792097186, 786118864, 780073180, // x.53 + 773962395, 767788778, 761554609, 755262175, 748913768, 742511686, 736058231, 729555707, 723006417, // x.62 + 716412665, 709776755, 703100984, 696387648, 689639036, 682857428, 676045100, 669204315, 662337327, // x.71 + 655446378, 648533696, 641601496, 634651978, 627687325, 620709702, 613721256, 606724115, 599720386, // x.80 + 592712154, 585701482, 578690411, 571680955, 564675105, 557674825, 550682053, 543698699, 536726645, // x.89 + 529767743, 522823816, 515896658, 508988029, 502099660, 495233249, 488390461, 481572928, 474782249, // x.98 + 468019988, 461287675, 454586804, 447918836, 441285195, 434687268, 428126409, 421603932, 415121117, // x.107 + 408679208, 402279408, 395922888, 389610779, 383344175, 377124134, 370951677, 364827785, 358753406, // x.116 + 352729449, 346756785, 340836251, 334968645, 329154729, 323395230, 317690838, 312042206, 306449955, // x.125 + 300914667, 295436891, 290017141, 284655897, 279353604, 274110676, 268927490, 263804394, 258741701, // x.134 + 253739694, 248798623, 243918709, 239100140, 234343077, 229647649, 225013957, 220442073, 215932043, // x.143 + 211483883, 207097585, 202773112, 198510404, 194309373, 190169909, 186091877, 182075118, 178119452, // x.152 + 174224676, 170390565, 166616873, 162903335, 159249664, 155655556, 152120688, 148644718, 145227287, // x.161 + 141868021, 138566528, 135322401, 132135218, 129004542, 125929924, 122910901, 119946997, 117037723, // x.170 + 114182582, 111381062, 108632643, 105936795, 103292978, 100700645, 98159238, 95668194, 93226942, // x.179 + 90834903, 88491495, 86196126, 83948203, 81747126, 79592292, 77483092, 75418916, 73399150, // x.188 + 71423178, 69490383, 67600142, 65751837, 63944844, 62178541, 60452305, 58765515, 57117547, // x.197 + 55507781, 53935597, 52400377, 50901505, 49438366, 48010349, 46616844, 45257246, 43930951, // x.206 + 42637360, 41375878, 40145912, 38946876, 37778185, 36639262, 35529533, 34448428, 33395384, // x.215 + 32369842, 31371249, 30399057, 29452725, 28531717, 27635503, 26763558, 25915365, 25090413, // x.224 + 24288196, 23508216, 22749980, 22013003, 21296806, 20600917, 19924870, 19268206, 18630475, // x.233 + 18011231, 17410035, 16826458, 16260073, 15710466, 15177224, 14659944, 14158231, 13671694, // x.242 + 13199950, 12742625, 12299348, 11869759, 11453500, 11050225, 10659590, 10281262, 9914910, // x.251 + 9560213, 9216856, 8884529, 8562931, 8251764, 7950739, 7659571, 7377984, 7105706, // x.260 + 6842471, 6588020, 6342099, 6104460, 5874861, 5653066, 5438844, 5231969, 5032221, // x.269 + 4839386, 4653254, 4473620, 4300287, 4133059, 3971747, 3816167, 3666139, 3521488, // x.278 + 3382043, 3247640, 3118115, 2993313, 2873079, 2757266, 2645728, 2538325, 2434919, // x.287 + 2335380, 2239575, 2147382, 2058677, 1973342, 1891262, 1812325, 1736424, 1663453, // x.296 + 1593311, 1525898, 1461118, 1398879, 1339091, 1281666, 1226519, 1173569, 1122736, // x.305 + 1073944, 1027117, 982185, 939076, 897725, 858065, 820033, 783568, 748612, // x.314 + 715108, 682999, 652233, 622759, 594527, 567488, 541597, 516808, 493079, // x.323 + 470368, 448635, 427841, 407948, 388921, 370725, 353326, 336692, 320792, // x.332 + 305596, 291075, 277202, 263950, 251292, 239204, 227663, 216646, 206130, // x.341 + 196094, 186517, 177381, 168667, 160356, 152430, 144874, 137671, 130806, // x.350 + 124264, 118031, 112093, 106437, 101050, 95921, 91039, 86391, 81968, // x.359 + 77759, 73755, 69945, 66322, 62877, 59602, 56488, 53528, 50716, // x.368 + 48043, 45505, 43093, 40803, 38629, 36564, 34604, 32745, 30980, // x.377 + 29305, 27717, 26211, 24782, 23428, 22144, 20927, 19774, 18681, // x.386 + 17646, 16665, 15737, 14857, 14025, 13237, 12491, 11786, 11118, // x.395 + 10487, 9890, 9325, 8791, 8287, 7810, 7359, 6933, 6531, // x.404 + 6151, 5792, 5453, 5133, 4831, 4547, 4278, 4024, 3785, // x.413 + 3560, 3347, 3147, 2958, 2779, 2612, 2454, 2305, 2164, // x.422 + 2032, 1908, 1791, 1681, 1577, 1480, 1388, 1302, 1221, // x.431 + 1145, 1073, 1006, 942, 883, 827, 775, 725, 679, // x.440 + 636, 595, 557, 521, 487, 456, 426, 399, 373, // x.449 + 348, 325, 304, 284, 265, 248, 231, 216, 202, // x.458 + 188, 175, 164, 153, 142, 133, 124, 115, 107, // x.467 + 100, 93, 87, 81, 75, 70, 65, 61, 56, // x.476 + 53, 49, 45, 42, 39, 36, 34, 31, 29, // x.485 + 27, 25, 23, 22, 20, 19, 17, 16, 15, // x.494 + 14, 13, 12, 11, 10, 9, 9, 8, 7, // x.503 + 7, 6, 6, 5, 5, 5, 4, 4, 4, // x.512 + 3, 3, 3, 3, 2, 2, 2, 2, 2, // x.521 + 2, 2, 1, 1, 1, 1, 1, 1, 1, // x.530 + 1, 1, 1, 1, 1, 1, 0, 0, // isum 100000000000 +}; + +int32_t dailyrates[101] = +{ + 0, 27, 55, 82, 110, 137, 164, 192, 219, 246, 273, 300, 327, 355, 382, 409, 436, 463, 489, 516, 543, 570, 597, 624, 651, 677, 704, 731, 757, 784, 811, 837, 864, 890, 917, 943, 970, 996, 1023, 1049, 1076, 1102, 1128, 1155, 1181, 1207, 1233, 1259, 1286, 1312, 1338, 1364, 1390, 1416, 1442, 1468, 1494, 1520, 1546, 1572, 1598, 1624, 1649, 1675, 1701, 1727, 1752, 1778, 1804, 1830, 1855, 1881, 1906, 1932, 1957, 1983, 2008, 2034, 2059, 2085, 2110, 2136, 2161, 2186, 2212, 2237, 2262, 2287, 2313, 2338, 2363, 2388, 2413, 2438, 2463, 2488, 2513, 2538, 2563, 2588, 2613 +}; + +int32_t peggy_setprice(struct peggy *PEG,struct price_resolution price,int32_t minute) +{ + if ( PEG->name.hasprice != 0 ) + { + if ( price.Pval > PRICE_RESOLUTION_MAXPVAL ) + { + printf("peggy_setdayprice clip.%lld with %lld\n",(long long)price.Pval,(long long)PRICE_RESOLUTION_MAXPVAL); + price.Pval = PRICE_RESOLUTION_MAXPVAL; + } + else if ( price.Pval <= 0 ) + { + printf("peggy_setdayprice illegal negative of zeroprice %lld %s\n",(long long)price.Pval,PEG->name.name); + price.Pval = 0; + } + if ( PEG->baseprices[minute] != 0 ) + price.Pval = (uint32_t)(price.Pval + PEG->baseprices[minute]) >> 1; + else if ( minute > PEG->RTminute ) + PEG->RTminute = minute; + PEG->baseprices[minute] = (uint32_t)price.Pval; + while ( --minute > 0 && PEG->baseprices[minute] == 0 ) + PEG->baseprices[minute] = (uint32_t)price.Pval; + } + return(minute); +} + +struct price_resolution peggy_shortprice(struct peggy *PEG,struct price_resolution price) +{ + struct price_resolution shortprice; + memset(&shortprice,0,sizeof(shortprice)); + if ( price.Pval != 0 ) + shortprice.Pval = ((PRICE_RESOLUTION * PEG->genesisprice.Pval) / price.Pval); + return(shortprice); +} + +struct price_resolution peggy_price(struct peggy *PEG,int32_t minute) +{ + struct price_resolution relprice,price; + memset(&price,0,sizeof(price)); + if ( minute == PEG->RTminute ) + minute--; + while ( (price.Pval= PEG->baseprices[minute]) == 0 && minute >= 0 ) + minute--; + if ( PEG->name.hasprice == 0 ) + { + relprice.Pval = PEG->relprices[minute]; + if ( relprice.Pval != 0 ) + { + if ( price.Pval < PRICE_RESOLUTION_MAXPVAL ) + price.Pval = (PRICE_RESOLUTION * price.Pval) / relprice.Pval; + else price.Pval = PRICE_RESOLUTION_ROOT * ((PRICE_RESOLUTION_ROOT * price.Pval) / relprice.Pval); + } else price.Pval = 0; + } + return(price); +} + +struct price_resolution peggy_aveprice(struct peggy *PEG,int32_t day,int32_t width) +{ + int32_t i,n; struct price_resolution price,aveprice; + aveprice.Pval = 0; + for (i=n=0; idayprices[day]; + if ( price.Pval != 0 ) + aveprice.Pval += price.Pval, n++; + } + if ( n != 0 ) + aveprice.Pval /= n; + return(aveprice); +} + +int32_t peggy_aprpercs(int64_t dailyrate) +{ + int32_t i; + if ( dailyrate == PEGGY_RATE_777 ) + return(777); + else if ( dailyrate == -PEGGY_RATE_777 ) + return(-777); + for (i=0; i= dailyrates[i] && dailyrate < dailyrates[i+1] ) + return(i*10); + return(0); +} + +char *peggy_aprstr(int64_t dailyrate) +{ + static char aprstr[16]; + int32_t apr,dir = 1; + if ( dailyrate < 0 ) + dir = -1, dailyrate = -dailyrate; + apr = peggy_aprpercs(dailyrate); + sprintf(aprstr,"%c%d.%02d%% APR",dir<0?'-':'+',apr/100,(apr%100)); + return(aprstr); +} + +int64_t peggy_compound(int32_t dispflag,int64_t satoshis,int64_t dailyrate,int32_t n) +{ + int32_t i; int64_t compounded = satoshis; + if ( dailyrate == 0 ) + return(satoshis); + if ( dispflag != 0 ) + printf("peggy_compound rate.%lld n.%d %.8f %lld %lld -> ",(long long)dailyrate,n,dstr(satoshis),(long long)compounded,(long long)SCALED_PRICE(compounded,dailyrate)); + for (i=0; ideposits += satoshis; + else + { + funds->margindeposits += amount; + funds->marginvalue += (amount * margin); + } +} + +void peggy_thanks_you(struct peggy_info *PEGS,int64_t tip) { PEGS->bank.crypto777_royalty += tip; } + +void peggy_changereserve(struct peggy_info *PEGS,struct peggy *PEG,int32_t dir,struct peggy_entry *entry,int64_t satoshis,uint16_t margin,int64_t marginamount) +{ + int64_t *dest; uint64_t replenish = 0,fee = 0; + if ( Debuglevel > 2 ) + printf("CHANGE %.8f: %c%s: %lld costbasis %.8f %s fee %.8f royalty %.8f estimated %.8f unlocked %.8f, interestpaid %.8f | units.%lld oppo.%lld\n",dstr(satoshis),entry->polarity<0?'-':'+',PEG->name.name,(long long)entry->denomination,dstr(entry->costbasis),peggy_aprstr(entry->dailyrate),dstr(entry->fee),dstr(entry->royalty),dstr(entry->estimated_interest),dstr(entry->interest_unlocked),dstr(entry->interestpaid),(long long)entry->supply.num,(long long)entry->supply.numoppo); + PEGS->bank.APRfund_reserved += (entry->estimated_interest - entry->interest_unlocked); + if ( PEG->pool.funds.deposits > 0 && PEGS->bank.funds.deposits > 0 ) + { + if ( PEGS->bank.APRfund < 0 ) + PEGS->bank.APRfund += entry->fee; + else + { + fee = entry->fee / PEGS->feediv, fee *= PEGS->feemult; + PEGS->bank.APRfund += ((entry->fee - fee) - entry->interestpaid); + } + } else replenish = entry->fee; + peggy_thanks_you(PEGS,entry->royalty + fee); + peggy_updatemargin(&PEG->pool.funds,satoshis + replenish,margin,marginamount); + peggy_updatemargin(&PEGS->bank.funds,satoshis + replenish,margin,marginamount); + peggy_updatemargin(&PEGS->basereserves[entry->baseid].funds,dir * satoshis,margin,dir * marginamount); + peggy_updatemargin(&PEGS->basereserves[entry->relid].funds,-dir * satoshis,margin,-dir * marginamount); + //printf("dir.%d polarity.%d baseid.%d relid.%d sats %.8f [%.8f %.8f]\n",dir,entry->polarity,entry->baseid,entry->relid,dstr(satoshis),dstr(PEGS->basereserves[entry->baseid]),dstr(PEGS->basereserves[entry->relid])); + dest = (entry->polarity < 0) ? &PEG->pool.liability.numoppo : &PEG->pool.liability.num; + *dest += (dir * entry->denomination); + if ( Debuglevel > 2 || (rand() % 1000) == 0 ) + printf(">>>>>>> %c%s %lld: cost %11.8f %s royalties %.8f APR.(R%.8f B%.8f) satoshis %11.8f %s.(+%lld -%lld) base.(%.8f %.8f) total %s (%.8f %.8f %.8f) (%.8f %.8f %.8f)\n",entry->polarity<0?'-':'+',PEG->name.name,(long long)entry->denomination,dstr(entry->costbasis),peggy_aprstr(entry->dailyrate),dstr(PEGS->bank.crypto777_royalty),dstr(PEGS->bank.APRfund_reserved),dstr(PEGS->bank.APRfund),dstr(satoshis),PEG->name.name,(long long)PEG->pool.liability.num,(long long)PEG->pool.liability.numoppo,dstr(PEGS->basereserves[entry->baseid].funds.deposits),dstr(PEGS->basereserves[entry->relid].funds.deposits),PEG->name.name,dstr(PEG->pool.funds.deposits),dstr(PEG->pool.funds.margindeposits),dstr(PEG->pool.funds.marginvalue),dstr(PEGS->bank.funds.deposits),dstr(PEGS->bank.funds.margindeposits),dstr(PEGS->bank.funds.marginvalue)); +} + +uint64_t peggy_satoshis(int32_t polarity,int16_t denomination,int64_t price,int64_t oppoprice) +{ + uint64_t satoshi; + if ( polarity < 0 ) + { + //satoshi = (denomination * price) / PRICE_RESOLUTION; + //satoshi = (satoshi * oppoprice) / PRICE_RESOLUTION; + //return((SATOSHIDEN * satoshi) / PRICE_RESOLUTION); + + satoshi = (oppoprice * price) / PRICE_RESOLUTION_ROOT; + satoshi = ((SATOSHIDEN / PRICE_RESOLUTION_ROOT) * (satoshi * denomination)) / PRICE_RESOLUTION; + return(satoshi); + //return(denomination * price * oppoprice * (10 / (PRICE_RESOLUTION * PRICE_RESOLUTION * PRICE_RESOLUTION))); + } + else + { + //satoshi = (denomination * price) / PRICE_RESOLUTION; + //return((SATOSHIDEN * satoshi) / PRICE_RESOLUTION); + return((SATOSHIDEN * denomination * price) / PRICE_RESOLUTION); + } +} + +uint64_t peggy_poolmainunits(struct peggy_entry *entry,int32_t dir,int32_t polarity,struct price_resolution price,struct price_resolution oppoprice,struct price_resolution spread,uint64_t poolincr,int16_t denomunits) +{ + uint64_t mainunits,satoshis; struct price_resolution fee; + entry->denomination = denomunits; + entry->costbasis = peggy_satoshis(polarity,denomunits,price.Pval,oppoprice.Pval); + if ( (entry->baseid != 0 || entry->relid != 0) && spread.Pval != 0 && (fee.Pval= SCALED_PRICE(price.Pval,spread.Pval)) != 0 ) + price.Pval += dir * fee.Pval; + else fee.Pval = 0; + satoshis = peggy_satoshis(polarity,denomunits,price.Pval,oppoprice.Pval); + if ( (satoshis % poolincr) == 0 ) + dir = 0; + mainunits = dir + (satoshis / poolincr); + entry->total = poolincr * mainunits; + entry->fee = (entry->total - entry->costbasis); + if ( Debuglevel > 2 ) + printf("mainunits %llu: origcost %.8f [%.8f] denomination %d poolincr %.8f price %.6f spread %.6f fee %.8f\n",(long long)mainunits,dstr(entry->costbasis),dstr(entry->fee),denomunits,dstr(poolincr),Pval(&price),Pval(&spread),Pval(&fee)); + return(entry->total); +} + +int64_t peggy_pairabs(int64_t basebalance,int64_t relbalance) +{ + int64_t baserelbalance; + if ( (baserelbalance= basebalance) < 0 ) + baserelbalance = -baserelbalance; + if ( relbalance < 0 ) + baserelbalance -= relbalance; + else baserelbalance += relbalance; + return(baserelbalance); +} + +int64_t peggy_lockrate(struct peggy_entry *entry,struct peggy_info *PEGS,struct peggy *PEG,uint64_t satoshis,uint16_t numdays) +{ + int64_t diff,compounded,prod,dailyrate=0,both,needed = 0; + if ( (both= entry->supply.num + entry->supply.numoppo) != 0 ) + { + if ( (diff= (entry->supply.numoppo - entry->supply.num)) < 0 ) + entry->supplydiff = -diff; + else entry->supplydiff = diff; + prod = (PEG->maxdailyrate * diff); + if ( prod > 0 ) + prod *= PEGS->posboost; + dailyrate = (prod / both) + dailyrates[PEGS->interesttenths]; + if ( dailyrate > PEGGY_RATE_777 ) + dailyrate = PEGGY_RATE_777; + else if ( dailyrate < -PEGGY_RATE_777 ) + dailyrate = -PEGGY_RATE_777; + if ( prod < 0 && dailyrate > 0 ) + dailyrate /= PEGS->negpenalty; + compounded = peggy_compound(0,satoshis,dailyrate,numdays); + needed = (compounded - satoshis); + needed *= 3, needed /= 2; + if ( Debuglevel > 2 ) + printf("2x needed %.8f dailyrate.%lld compounded %lld <- %lld diff.%lld prod.%lld both.%lld -> %lld %s\n",dstr(needed),(long long)dailyrate,(long long)compounded,(long long)satoshis,(long long)diff,(long long)prod,(long long)both,(long long)dailyrate,peggy_aprstr(dailyrate)); + if ( (PEGS->bank.APRfund_reserved + needed) > PEGS->bank.APRfund ) + { + compounded = peggy_compound(1,satoshis,dailyrate,numdays); + printf("reserved %.8f + needed %.8f) > APRfund %.8f\n",dstr(PEGS->bank.APRfund_reserved),dstr(needed),dstr(PEGS->bank.APRfund)); + needed = dailyrate = 0; + } else entry->estimated_interest = needed; + } + entry->dailyrate = dailyrate; + return(dailyrate); +} + +int32_t peggy_islegal_amount(struct peggy_entry *entry,struct peggy_info *PEGS,struct peggy *PEG,int32_t dir,int64_t satoshis,int32_t numdays,uint16_t margin,struct price_resolution price) +{ + uint64_t newsupply; int64_t baserelbalance,newbaserel; + if ( margin == 0 ) + entry->dailyrate = peggy_lockrate(entry,PEGS,PEG,satoshis,numdays); + if ( entry->baseid == entry->relid ) + { + printf("illegal baseid.%d relid.%d (%s)\n",PEG->name.baseid,PEG->name.relid,PEG->name.name); + //getchar(); + return(1); + } + if ( PEG->name.id == 0 ) + { + printf("BTCD is legal\n"); + return(1); + } + if ( (newsupply= ((PEG->pool.funds.deposits + PEG->pool.funds.marginvalue) + satoshis)) > PEG->maxsupply ) + { + printf("peggy_islegal_amount %.8f %.8f newsupply %.8f > limits %.8f\n",dstr(PEG->pool.funds.deposits),dstr(PEG->pool.funds.marginvalue),dstr(newsupply),dstr(PEG->maxsupply)); + return(0); + } + //printf("baseid.%d relid.%d\n",entry->baseid,entry->relid); + baserelbalance = peggy_pairabs(PEGS->basereserves[entry->baseid].funds.deposits,PEGS->basereserves[entry->relid].funds.deposits); + newbaserel = peggy_pairabs(PEGS->basereserves[entry->baseid].funds.deposits + satoshis,PEGS->basereserves[entry->relid].funds.deposits - satoshis); + if ( Debuglevel > 2 ) + printf("baseid.%d relid.%d satoshis %.8f baserelbalance %.8f newbaserel %.8f\n",entry->baseid,entry->relid,dstr(satoshis),dstr(baserelbalance),dstr(newbaserel)); + if ( newbaserel <= baserelbalance ) + return(1); + //printf("entry->supplydiff.%lld diff %.8f vs maxnetbalance %.8f\n",(long long)entry->supplydiff,(double)(price.Pval*entry->supplydiff)/PRICE_RESOLUTION,dstr(PEG->limits.maxnetbalance)); + if ( PEG->maxnetbalance != 0 && (price.Pval * entry->supplydiff) / PRICE_RESOLUTION > PEG->maxnetbalance/SATOSHIDEN ) + { + printf("entry->supplydiff.%lld diff %.8f vs maxnetbalance %.8f\n",(long long)entry->supplydiff,(double)(price.Pval*entry->supplydiff)/PRICE_RESOLUTION,dstr(PEG->maxnetbalance)); + return(0); + } + return(1); +} + +static uint64_t peggy_assetbits(char *name) { return((is_decimalstr(name) != 0) ? calc_nxt64bits(name) : stringbits(name)); } + +struct peggy *peggy_findpair(struct peggy_info *PEGS,char *name) +{ + int32_t i; uint64_t assetbits; + if ( (assetbits= peggy_assetbits(name)) != 0 ) + { + for (i=0; inumpegs; i++) + { + if ( PEGS->contracts[i]->name.assetbits == assetbits ) + return(PEGS->contracts[i]); + } + } + return(0); +} + +struct peggy *peggy_found(struct peggy_entry *entry,struct peggy *PEG,int32_t polarity) +{ + int64_t num,numoppo; + memset(entry,0,sizeof(*entry)); + num = PEG->pool.liability.num, numoppo = PEG->pool.liability.numoppo; + if ( polarity >= 0 ) + entry->polarity = 1, entry->baseid = PEG->name.baseid, entry->relid = PEG->name.relid, entry->supply.num = num, entry->supply.numoppo = numoppo; + else entry->polarity = -1, entry->baseid = PEG->name.relid, entry->relid = PEG->name.baseid, entry->supply.num = numoppo, entry->supply.numoppo = num; + //printf("(%s) -> baseid.%d relid.%d\n",PEG->name.name,entry->baseid,entry->relid); + return(PEG); +} + +struct peggy *peggy_find(struct peggy_entry *entry,struct peggy_info *PEGS,char *name,int32_t polarity) +{ + struct peggy *PEG; + if ( (PEG= peggy_findpair(PEGS,name)) != 0 ) + return(peggy_found(entry,PEG,polarity)); + return(0); +} + +struct peggy *peggy_findpeg(struct peggy_entry *entry,struct peggy_info *PEGS,int32_t peg) +{ + if ( peg >= 0 ) + return(peggy_found(entry,PEGS->contracts[peg],peg)); + else return(peggy_found(entry,PEGS->contracts[-peg],peg)); +} + +int32_t peggy_pegstr(char *buf,struct peggy_info *PEGS,char *name) +{ + int32_t peg=0; struct peggy *PEG; + buf[0] = 0; + if ( name != 0 ) + { + strcpy(buf,name); + if ( (PEG= peggy_findpair(PEGS,name)) != 0 ) + return(PEG->name.id); + } + return(peg); +} + +int32_t peggy_setname(char *buf,char *name) +{ + return(peggy_pegstr(buf,opreturns_context("peggy",0),name)); +} + +int64_t peggy_calcspread(int64_t spread,int32_t lockdays) { return((lockdays < 30) ? spread : ((30 * spread) / lockdays)); } + +uint64_t peggy_setunit(struct peggy_unit *U,struct peggy_entry *entry,struct peggy_info *PEGS,struct peggy_time T,struct peggy *PEG,uint64_t seed,uint64_t nxt64bits,struct peggy_lock *lock) +{ + int32_t numdays,polarity; uint64_t poolincr; int16_t denom; struct price_resolution spread; + memset(U,0,sizeof(*U)); + U->lock = *lock; + if ( (denom= lock->denom) < 0 ) + polarity = -1, denom = -denom; + else polarity = 1; + if ( denom >= PRICE_RESOLUTION_MAXUNITS ) + { + printf("denom.%d is too big max %lld\n",denom,(long long)PRICE_RESOLUTION_MAXUNITS); + return(0); + } + if ( U->lock.margin != 0 ) + { + if ( U->lock.maxlockdays > PEGGY_MARGINLOCKDAYS ) + { + printf("error: maxlockdays cant be more than PEGGY_MARGINLOCKDAYS %d for margin trading\n",PEGGY_MARGINLOCKDAYS); + return(0); + } + else if ( U->lock.margin > PEG->lockparms.margin ) + { + printf("error: margin.%d cant be more than %d for margin trading %s\n",U->lock.margin,PEG->lockparms.margin,PEG->name.name); + return(0); + } + else if ( denom < U->lock.margin ) + { + printf("error: denomination %lld must be >= margin %dx trading %s\n",(long long)denom,U->lock.margin,PEG->name.name); + return(0); + } + else if ( (denom + entry->supply.num) > entry->supply.numoppo ) + { + //printf("error: denom.%d supply %d %d > oppo %d -> balance violation %s\n",denom,entry->supply.num,denom+entry->supply.num,entry->supply.numoppo,PEG->name.name); + return(0); + } + U->lock.redemptiongapdays = PEGGY_MARGINGAPDAYS; + } else U->lock.redemptiongapdays = PEG->lockparms.redemptiongapdays; + if ( U->lock.maxlockdays <= PEG->lockparms.maxlockdays ) + U->lock.maxlockdays = PEG->lockparms.maxlockdays; + if ( U->lock.minlockdays >= PEG->lockparms.minlockdays ) + U->lock.minlockdays = PEG->lockparms.minlockdays; + if ( U->lock.minlockdays > U->lock.maxlockdays ) + U->lock.minlockdays = U->lock.maxlockdays; + if ( U->lock.clonesmear > PEG->lockparms.clonesmear ) + U->lock.clonesmear = PEG->lockparms.clonesmear; + if ( U->lock.mixrange > PEG->lockparms.mixrange ) + U->lock.mixrange = PEG->lockparms.mixrange; + U->lock.extralockdays = PEGGY_MINEXTRADAYS + (seed % PEG->lockparms.extralockdays); + entry->price = PEG->dayprice;//peggy_nonzprice(PEGS,T,PEG,1,day); + entry->oppoprice = peggy_shortprice(PEG,entry->price);//peggy_nonzprice(PEGS,T,PEG,-1,day); + poolincr = PEG->pool.mainunitsize; + U->timestamp = T.blocktimestamp, U->baseid = entry->baseid, U->relid = entry->relid; //, U->nxt64bits = nxt64bits, + U->lock.peg = PEG->name.id * polarity; + spread.Pval = peggy_calcspread(PEG->spread.Pval,U->lock.minlockdays + U->lock.extralockdays); + peggy_poolmainunits(entry,1,polarity,entry->price,entry->oppoprice,spread,poolincr,denom); + U->costbasis = entry->costbasis; + numdays = (polarity > 0) ? (U->lock.maxlockdays + PEG->lockparms.extralockdays) : (U->lock.minlockdays + PEG->lockparms.extralockdays); + return(entry->total * peggy_islegal_amount(entry,PEGS,PEG,polarity,entry->total,numdays,U->lock.margin,entry->price)); +} + +int64_t peggy_redeemhash(struct peggy_entry *entry,struct peggy_info *PEGS,struct peggy_time T,struct peggy_unit *U,int32_t lockdays) +{ + struct price_resolution price,oppoprice,spread; struct peggy *PEG; int32_t n,delta; uint64_t poolincr,interest,satoshis = 0; + if ( (PEG= peggy_findpeg(entry,PEGS,U->lock.peg)) != 0 ) + { + poolincr = PEG->pool.mainunitsize, oppoprice.Pval = spread.Pval = 0; + delta = (T.blocktimestamp - U->timestamp) / PEGGY_DAYTICKS; + lockdays += U->lock.extralockdays; + if ( delta < lockdays ) + return(0); + else if ( delta > (lockdays + U->lock.redemptiongapdays) ) + return(-1); + T.blocktimestamp = U->timestamp + (lockdays * PEGGY_DAYTICKS); + if ( (n= (int32_t)(U->costbasis / PEG->unitincr)) > 0 ) + T.blocktimestamp -= (n * PEGGY_DAYTICKS) / 2; + else n = 1; + price = peggy_aveprice(PEG,(T.blocktimestamp - PEG->genesistime) / PEGGY_DAYTICKS,n); + if ( entry->polarity < 0 ) + oppoprice = peggy_shortprice(PEG,price); + spread.Pval = peggy_calcspread(PEG->spread.Pval,lockdays); + satoshis = peggy_poolmainunits(entry,-1,entry->polarity,price,oppoprice,spread,poolincr,U->lock.denom); + entry->costbasis = U->costbasis; + if ( U->estimated_interest != 0 ) + { + interest = peggy_compound(0,satoshis,U->dailyrate,lockdays + U->lock.extralockdays) - satoshis; + entry->interestpaid = (interest / poolincr) * poolincr; + if ( entry->interestpaid > U->estimated_interest ) + entry->interestpaid = U->estimated_interest; + entry->royalty += (interest - entry->interestpaid); + entry->interest_unlocked = U->estimated_interest; + } + if ( U->lock.margin == 0 ) + { + if ( PEG->pool.funds.deposits < satoshis ) + satoshis = PEG->pool.funds.deposits; + else if (PEG->pool.funds.deposits >= (satoshis + entry->interestpaid) ) + satoshis += entry->interestpaid; + } + else + { + if ( PEG->pool.funds.margindeposits < satoshis ) + satoshis = PEG->pool.funds.margindeposits; + } + } + return(satoshis); +} + +uint64_t peggy_redeem(struct peggy_info *PEGS,struct peggy_time T,int32_t readonly,char *name,int32_t polarity,uint64_t nxt64bits,bits256 pubkey,uint16_t lockdays,uint8_t chainlen) +{ + struct peggy_entry entry; struct peggy_unit *U; struct peggy *PEG; int32_t peg; int64_t satoshis = 0; bits256 lockhash; + if ( (PEG= peggy_findpair(PEGS,name)) != 0 ) + { + peg = PEG->name.id * polarity; + lockhash = acct777_lockhash(pubkey,lockdays,chainlen); + if ( (U= peggy_match(PEGS->accts,peg,nxt64bits,lockhash,lockdays)) != 0 ) + { + if ( (satoshis= peggy_redeemhash(&entry,PEGS,T,U,lockdays)) < 0 ) + { + printf("Autopurge unit.%p\n",U); + satoshis = 0; + } + if ( readonly == 0 ) + { + peggy_changereserve(PEGS,PEG,-1,&entry,satoshis,U->lock.margin,U->marginamount); + peggy_delete(PEGS->accts,U,satoshis == 0 ? PEGGY_RSTATUS_AUTOPURGED : PEGGY_RSTATUS_REDEEMED); + } + } + } + return(satoshis); +} + +uint64_t peggy_createunit(struct peggy_info *PEGS,struct peggy_time T,struct peggy_unit *readU,uint64_t seed,char *name,uint64_t nxt64bits,bits256 lockhash,struct peggy_lock *lock,uint64_t amount,uint64_t marginamount) +{ + struct peggy_entry entry; struct peggy_unit U; int32_t peg,polarity; int16_t denomination; int64_t satoshis = 0; struct peggy *PEG = 0; + denomination = lock->denom; + if ( denomination < 0 ) + polarity = -1, denomination = -denomination; + else polarity = 1; + if ( denomination >= PRICE_RESOLUTION_MAXUNITS ) + { + printf("denomination.%d is too big max %lld\n",denomination,(long long)PRICE_RESOLUTION_MAXUNITS); + return(0); + } + if ( name == 0 ) + { + if ( (peg= lock->peg) == 0 ) + PEG = PEGS->contracts[0]; + else if ( lock->peg < 0 ) + peg = -peg, polarity = -polarity; + if ( peg >= PEGS->numpegs ) + { + printf("illegal peg id.%d\n",lock->peg); + return(0); + } + PEG = PEGS->contracts[peg]; + PEG = peggy_find(&entry,PEGS,PEG->name.name,polarity); + } else PEG = peggy_find(&entry,PEGS,name,polarity); + if ( PEG != 0 ) + { + if ( (satoshis= peggy_setunit(&U,&entry,PEGS,T,PEG,seed,nxt64bits,lock)) != 0 ) + { + U.estimated_interest = entry.estimated_interest, U.amount = amount, U.marginamount = marginamount; + if ( readU == 0 ) + { + if ( Debuglevel > 2 ) + printf("%s.%d amount %.8f satoshis %.8f incr.%.8f price.%.8f\n",PEG->name.name,PEG->name.id,dstr(amount),dstr(satoshis),dstr(PEG->pool.mainunitsize),Pval(&entry.price)); + if ( (lock->margin == 0 && amount >= satoshis) || (marginamount * lock->margin) >= satoshis ) + { + peggy_changereserve(PEGS,PEG,1,&entry,entry.costbasis,lock->margin,marginamount); + peggy_addunit(PEGS->accts,&U,lockhash); + if ( Debuglevel > 2 ) + printf("id.%d needed for interest reserved %.8f BTCD, royalty %.8f | dailyrate %lld %s\n",PEG->name.id,dstr(U.estimated_interest),dstr(amount) - dstr(satoshis),(long long)U.dailyrate,peggy_aprstr(U.dailyrate)); + } else printf("%s amount %.8f not enough for unit %.8f or margin.%d %llu %.8f\n",PEG->name.name,dstr(amount),dstr(satoshis),lock->margin,(long long)marginamount,dstr(marginamount * lock->margin)), satoshis = 0; + } + } + if ( readU != 0 ) *readU = U, printf("%c%s cost %.8f %s\n",polarity < 0 ? '-' : '+',PEG->name.name,dstr(satoshis),peggy_aprstr(U.dailyrate)); + } else printf("peggy_createunit: cant find.(%s)\n",name); + return(satoshis); +} + +uint64_t peggy_gamblers(struct peggy_info *PEGS,struct peggy_time T,struct price_resolution prevprice,struct price_resolution newprice,struct peggy_bet *bets,int32_t numbets) +{ + int32_t i,j,match,oppo,numbest = 0; int64_t diff,preddiff,tmp,dist,bestdist; + uint64_t bet,payout,totalbets,losingbets,winningbets,totalpayout,matchbets,oppobets,matchshares; + matchshares = matchbets = oppobets = losingbets = winningbets = bestdist = totalpayout = match = oppo = 0; + if ( bets != 0 ) + { + for (totalbets=i=0; i 0 ) + diff = 1; + for (j=0; j 0 ) + preddiff = 1; + if ( (tmp= diff*preddiff) > 0 ) + match++, matchbets += bet, bets[j].shares = (bet * bets[j].minutes), matchshares += (bet * (1 + bets[j].minutes)); + else if ( tmp < 0 ) + oppo++, oppobets += bet; + } + if ( (bet= bets[j].distbet) != 0 ) + { + if ( (dist= ((int64_t)newprice.Pval - bets[j].prediction.Pval)) < 0 ) + dist = -dist; + bets[j].dist = ++dist; + if ( bestdist == 0 || dist < bestdist ) + bestdist = dist; + } + bets[j].payout = 0; + } + for (j=0; jbank.privatebetfees += (totalbets - payout); + if ( numbets != 0 ) + printf("royalty %.8f (%.8f - payout %.8f) numbest.%d winningbets %.8f vs losingbets %.8f | match.%d %.8f, oppo.%d %.8f\n",dstr(totalbets - payout),dstr(totalbets),dstr(payout),numbest,dstr(winningbets),dstr(losingbets),match,dstr(matchbets),oppo,dstr(oppobets)); + return(totalpayout); +} + +struct price_resolution peggy_newprice(struct peggy_info *PEGS,struct peggy *PEG,struct peggy_time T,uint32_t newpval) +{ + uint64_t sum,den,gap; int64_t diff; int32_t i,j,minute,iter; struct price_resolution price,shortprice,newprice; + gap = (PEG->spread.Pval * newpval) / PRICE_RESOLUTION; + if ( (newprice.Pval= newpval) != 0 ) + { + for (iter=0; iter<1; iter++) + { + sum = den = 0; + sum = (((uint64_t)peggy_smooth_coeffs[0]) * newprice.Pval); + den = peggy_smooth_coeffs[0]; + minute = (T.blocktimestamp - PEG->genesistime) / PEGGY_MINUTE; + //printf("peggy_newprice day.%d: %u sum %lld\n",day,newpval,(long long)sum); + for (i=1; i 0 ) + { + price = peggy_price(PEG,j); + if ( price.Pval != 0 ) + { + sum += (((uint64_t)peggy_smooth_coeffs[i]) * price.Pval); + den += peggy_smooth_coeffs[i]; + } + //printf("i.%d ind.%d coeff.%llu add.%lld sum %lld den %lld %.6f -> %.7f\n",i,j,(long long)peggy_smooth_coeffs[i],(long long)price.Pval,(long long)sum,(long long)den,Pval(&price),(double)sum/(den)); + } else break; + } + price.Pval = newpval; + //printf("sum %lld den %lld %.10f -> %.10f || ",(long long)sum,(long long)den,Pval(&price),(double)sum/(den)); + if ( den != 0 ) + price.Pval = (sum / den); + else break; + newprice = price; + diff = (newprice.Pval - newpval); + if ( diff < 0 ) + diff = -diff; + if ( diff < gap ) + break; + newprice.Pval = (newprice.Pval*7 + newpval) / 8; + //printf("%.8f ",Pval(&newprice)); + } + peggy_setprice(PEG,newprice,minute); + shortprice = peggy_shortprice(PEG,newprice); + price.Pval = newpval; + if ( Debuglevel > 2 ) + fprintf(stderr,"t.%u M%d day.%-4d new %.8f short.%.8f pval.%.8f | first %.10f ",T.blocktimestamp,minute,minute/1440,Pval(&newprice),Pval(&shortprice),Pval(&price),Pval(&PEG->genesisprice)); + } + return(newprice); +} + +void peggy_margincalls(struct peggy_info *PEGS,struct peggy_time T,struct peggy *PEG,struct price_resolution newprice,struct price_resolution shortprice) +{ + int32_t i; struct peggy_unit *U; int64_t satoshis,gain,threshold; struct peggy_entry entry; + for (i=0,U=&PEGS->accts->units[0]; iaccts->numunits; i++,U++) + { + if ( U->lock.margin != 0 && PEG != 0 && (PEG->name.id == U->lock.peg || PEG->name.id == -U->lock.peg) ) + { + if ( (PEG= peggy_findpeg(&entry,PEGS,U->lock.peg)) != 0 ) + { + satoshis = peggy_poolmainunits(&entry,-1,entry.polarity,newprice,shortprice,PEG->spread,PEG->pool.mainunitsize,U->lock.denom); + gain = entry.polarity * (satoshis - U->costbasis), threshold = -U->costbasis/U->lock.margin; + if ( gain < threshold ) + { + printf("%s %8.6f %8.6f %2dx gain %11.8f polarity.%-2d (%11.8f - cost %11.8f) -> profit %11.8f margincall %11.8f ",PEG->name.name,Pval(&newprice),Pval(&shortprice),U->lock.margin,dstr(gain),entry.polarity,dstr(satoshis),dstr(U->costbasis),dstr(gain),dstr(threshold)); + printf("MARGINCALLED\n"); + peggy_changereserve(PEGS,PEG,-1,&entry,satoshis,U->lock.margin,U->marginamount); + peggy_delete(PEGS->accts,U,PEGGY_RSTATUS_MARGINCALL); + } + } + } + } +} + +struct price_resolution peggy_priceconsensus(struct peggy_info *PEGS,struct peggy_time T,uint64_t seed,int16_t pricedpeg,struct peggy_vote *votes,uint32_t numvotes,struct peggy_bet *bets,uint32_t numbets) +{ + struct peggy_entry entry; struct price_resolution newprice,dayprice,tmp; struct peggy *PEG; + int64_t delta,weight,totalwt = 0; int32_t i,j,n,minute,day,wts[PEGGY_NUMCOEFFS]; uint32_t start,k; uint64_t ind; + newprice.Pval = 0; + if ( (PEG= peggy_find(&entry,PEGS,PEGS->contracts[pricedpeg]->name.name,1)) != 0 ) + { + for (i=n=0; ipool.quorum || totalwt < PEG->pool.decisionthreshold ) + return(PEG->price); + start = (uint32_t)(pricedpeg * seed); + for (k=0; k (totalwt >> 1) ) ////votes[j].weight; + break; + } + } + } + } + //if ( strcmp("SuperNET",PEG->name.name) == 0 ) + // fprintf(stderr,"%d.(%.6f %llu) ",i,(double)votes[i].pval/PRICE_RESOLUTION,(long long)weight); + if ( weight > (totalwt >> 1) ) + { + if ( Debuglevel > 2 ) + fprintf(stderr,"%6d k%-4d %4d-> %.6f wt.%-4lld/%4lld ",votes[i].pval,k,i,Pval(&PEG->price),(long long)weight,(long long)totalwt); + PEG->price = peggy_newprice(PEGS,PEG,T,votes[i].pval); + break; + } + } + if ( 0 && k == numvotes ) + fprintf(stderr,"no consensus for %s %6d k%-4d %4d-> %.6f wt.%-4lld/%4lld ",PEG->name.name,votes[i].tolerance,k,i,Pval(&PEG->price),(long long)weight,(long long)totalwt); + if ( (day= (T.blocktimestamp - PEG->genesistime)/PEGGY_DAYTICKS) != PEG->day ) + { + peggy_gamblers(PEGS,T,PEG->dayprice,PEG->price,bets,numbets); + dayprice.Pval = 0; + for (minute=PEG->day*1440,i=n=0; i<1440; i++,minute++) + { + tmp = peggy_price(PEG,minute); + if ( tmp.Pval != 0 ) + dayprice.Pval += tmp.Pval, n++; + } + if ( n != 0 ) + dayprice.Pval /= n; + PEG->dayprice = dayprice; + PEG->day = day; + PEG->dayprices[day] = (uint32_t)dayprice.Pval; + if ( Debuglevel > 2 ) + printf(">>>>>>>>>>>> DAY PRICE.%d %s %.8f\n",day,PEG->name.name,Pval(&dayprice)); + while ( --day > 0 && PEG->dayprices[day] == 0 ) + PEG->dayprices[day] = (uint32_t)dayprice.Pval; + } + peggy_margincalls(PEGS,T,PEG,PEG->price,peggy_shortprice(PEG,PEG->price)); + newprice = PEG->price; + } else printf("cant find peg.%d\n",pricedpeg); + return(newprice); +} diff --git a/iguana/peggy_price.c b/iguana/peggy_price.c new file mode 100755 index 000000000..cf8997b59 --- /dev/null +++ b/iguana/peggy_price.c @@ -0,0 +1,837 @@ +/****************************************************************************** + * 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 "peggy.h" + +#define _extrapolate_Spline(Splines,gap) ((double)(Splines)[0] + ((gap) * ((double)(Splines)[1] + ((gap) * ((double)(Splines)[2] + ((gap) * (double)(Splines)[3])))))) +#define _extrapolate_Slope(Splines,gap) ((double)(Splines)[1] + ((gap) * ((double)(Splines)[2] + ((gap) * (double)(Splines)[3])))) + +#define PRICE_BLEND(oldval,newval,decay,oppodecay) ((oldval == 0.) ? newval : ((oldval * decay) + (oppodecay * newval))) +#define PRICE_BLEND64(oldval,newval,decay,oppodecay) ((oldval == 0) ? newval : ((oldval * decay) + (oppodecay * newval) + 0.499)) + +#define dto64(x) ((int64_t)((x) * (double)SATOSHIDEN * SATOSHIDEN)) +#define dto32(x) ((int32_t)((x) * (double)SATOSHIDEN)) +#define i64tod(x) ((double)(x) / ((double)SATOSHIDEN * SATOSHIDEN)) +#define i32tod(x) ((double)(x) / (double)SATOSHIDEN) +#define _extrapolate_spline64(spline64,gap) ((double)i64tod((spline64)[0]) + ((gap) * ((double)i64tod(.001*.001*(spline64)[1]) + ((gap) * ((double)i64tod(.001*.001*.001*.001*(spline64)[2]) + ((gap) * (double)i64tod(.001*.001*.001*.001*.001*.001*(spline64)[3]))))))) +#define _extrapolate_spline32(spline32,gap) ((double)i32tod((spline32)[0]) + ((gap) * ((double)i32tod(.001*.001*(spline32)[1]) + ((gap) * ((double)i32tod(.001*.001*.001*.001*(spline32)[2]) + ((gap) * (double)i32tod(.001*.001*.001*.001*.001*.001*(spline32)[3]))))))) + +static char *Yahoo_metals[] = { YAHOO_METALS }; +uint64_t Currencymasks[NUM_CURRENCIES+1]; + +short Contract_base[NUM_COMBINED+1] = { 7, 7, 7, 7, 3, 1, 4, 5, 5, 0, 1, 3, 4, 0, 6, 1, 3, 4, 1, 1, 1, 1, 3, 3, 3, 0, 4, 4, 0,1,2,3,4,5,6,7, 8 };// Contract_base }; +short Contract_rel[NUM_COMBINED+1] = { 0, 6, 5, 2, 7, 7, 7, 2, 6, 5, 5, 5, 5, 6, 2, 6, 6, 6, 0, 4, 2, 3, 0, 2, 4, 2, 2, 0, 0,1,2,3,4,5,6,7,8 };// Contract_rel + +short Baserel_contractdir[NUM_CURRENCIES+1][NUM_CURRENCIES+1] = +{ + { 1, -1, 1, -1, -1, 1, 1, -1, -1 }, + { 1, 1, 1, 1, 1, 1, 1, 1, -1 }, + { -1, -1, 1, -1, -1, -1, -1, -1, 0 }, + { 1, -1, 1, 1, 1, 1, 1, 1, -1 }, + { 1, -1, 1, -1, 1, 1, 1, 1, -1 }, + { -1, -1, 1, -1, -1, 1, 1, -1, 0 }, + { -1, -1, 1, -1, -1, -1, 1, -1, -1 }, + { 1, -1, 1, -1, -1, 1, 1, 1, 0 }, + { -1, -1, 0, -1, -1, 0, -1, 0, 1 }, +}; + +short Currency_contracts[NUM_CURRENCIES+1][NUM_CURRENCIES] = +{ + { 0, 9, 13, 18, 22, 25, 27, 28, }, + { 5, 10, 15, 18, 19, 20, 21, 29, }, + { 3, 7, 14, 20, 23, 25, 26, 30, }, + { 4, 11, 16, 21, 22, 23, 24, 31, }, + { 6, 12, 17, 19, 24, 26, 27, 32, }, + { 2, 7, 8, 9, 10, 11, 12, 33, }, + { 1, 8, 13, 14, 15, 16, 17, 34, }, + { 0, 1, 2, 3, 4, 5, 6, 35, }, + { 36, 37, -1, 38, 39, -1, 40, 41, }, +}; + +short Currency_contractothers[NUM_CURRENCIES+1][NUM_CURRENCIES] = // buggy! +{ + { 7, 5, 6, 1, 3, 2, 4, 0, }, + { 7, 5, 6, 0, 4, 2, 3, 1, }, + { 7, 5, 6, 1, 3, 0, 4, 2, }, + { 7, 5, 6, 1, 0, 2, 4, 3, }, + { 7, 5, 6, 1, 3, 2, 0, 4, }, + { 7, 2, 6, 0, 1, 3, 4, 5, }, + { 7, 5, 0, 2, 1, 3, 4, 6, }, + { 0, 6, 5, 2, 1, 3, 4, 7, }, + { 0, 1,-1, 3, 4,-1, 5,-1, }, +}; + +int32_t MINDENOMS[] = { 1000, 1000, 100000, 1000, 1000, 1000, 1000, 1000, // major currencies + 10000, 100000, 10000, 1000, 100000, 10000, 1000, 10000, 1000, 10000, 10000, 10000, 10000, 100000, 1000, 1000000, 1000, 10000, 1000, 1000, 10000, 1000, 10000000, 10000, // end of currencies + 1, 100, 1, 1, // metals, gold must be first + 1, 10, 100000, 100, 100, 10000000, 10000, 1000, 1000, 1000, 100000, 100000, 1000000 // cryptos +}; + +int32_t PAX_mindenomination(int32_t base) +{ + return(MINDENOMS[base]); +} + +void norm_smooth_wts(int32_t j,double *smoothwts,int32_t n) +{ + double wt; int32_t iter,i; + for (iter=0; iter<13; iter++) + { + wt = 0.; + for (i=0; i=3; numprimes--) + { + for (p=1; p SMALLVAL ) + printf("x.%d error %.20f != %.20f [%.20f]\n",x,smoothbuf[5000 - x],smoothbuf[5000 + x],smoothbuf[5000 - x] - smoothbuf[5000 + x]); + _coeffs[x-1] = (smoothbuf[5000 - x] + smoothbuf[5000 + x]) / 2.; + } + sum = 0.; + for (x=0; x= 64 ) + return(10000); + else if ( peggy_bases[i] != 0 ) + { + if ( is_decimalstr(peggy_bases[i]+strlen(peggy_bases[i])-2) != 0 || strcmp(peggy_bases[i],"BTCRUB") == 0 ) + minmils = 1; + else if ( strncmp(peggy_bases[i],"XAU",3) == 0 || strcmp(peggy_bases[i],"BTCCNY") == 0 || strcmp(peggy_bases[i],"BTCUSD") == 0 || strncmp(peggy_bases[i],"XPD",3) == 0 || strncmp(peggy_bases[i],"XPT",3) == 0 ) + minmils = 10; + else if ( strcmp(peggy_bases[i],"BUND") == 0 || strcmp(peggy_bases[i],"UKOIL") == 0 || strcmp(peggy_bases[i],"USOIL") == 0 ) + minmils = 100; + else if ( strncmp(peggy_bases[i],"LTC",3) == 0 || strcmp(peggy_bases[i],"SuperNET") == 0 || strncmp(peggy_bases[i],"XAG",3) == 0 || strncmp(peggy_bases[i],"ETH",3) == 0 || strncmp(peggy_bases[i],"XCP",3) == 0 ) + minmils = 1000; + else if ( strncmp(peggy_bases[i],"XMR",3) == 0 ) + minmils = 10000; + else if ( strncmp(peggy_bases[i],"NXT",3) == 0 || strncmp(peggy_bases[i],"BTS",3) == 0 ) + minmils = 1000000; + else if ( strncmp(peggy_bases[i],"DOGE",3) == 0 ) + minmils = 100000000; + else minmils = 10000; + } + return(minmils); +} + +int32_t peggy_prices(struct price_resolution prices[64],double btcusd,double btcdbtc,char *contracts[],int32_t num,double *cprices,double *basevals) +{ + double btcdusd,price_in_btcd,dprice,usdcny,usdrub,btccny,btcrub,xauusd,usdprice=0.,usdval,btcprice=0.; int32_t contractnum,base,nonz = 0; + if ( btcusd > SMALLVAL && btcdbtc > SMALLVAL && (usdval= basevals[0]) > SMALLVAL ) + { + xauusd = usdcny = usdrub = btccny = btcrub = 0.; + for (contractnum=0; contractnum SMALLVAL ) + { + usdcny = (basevals[0] * peggy_mils(8)) / (basevals[8] * peggy_mils(0)); + btccny = 1000 * btcusd * usdcny; + } + if ( basevals[9] > SMALLVAL ) + { + usdrub = (basevals[0] * peggy_mils(9)) / (basevals[9] * peggy_mils(0)); + btcrub = 1000 * btcusd * usdrub; + } + btcdusd = (btcusd * btcdbtc); + printf("xauusd %f usdval %f %f %f usdcny %f usdrub %f btcusd %f btcdbtc %f btcdusd %f btccny %f btcrub %f\n",xauusd,usdval,basevals[8],basevals[9],usdcny,usdrub,btcusd,btcdbtc,btcdusd,btccny,btcrub); + prices[0].Pval = (PRICE_RESOLUTION * 100. * btcdbtc); + for (base=0,contractnum=1; base<32; base++,contractnum++) + { + if ( strcmp(contracts[contractnum],CURRENCIES[base]) == 0 ) + { + if ( (dprice= basevals[base]) > SMALLVAL ) + { + nonz++; + if ( base == 0 ) + usdprice = price_in_btcd = (1. / btcdusd); + else price_in_btcd = (dprice / (btcdusd * usdval)); + prices[contractnum].Pval = (PRICE_RESOLUTION * price_in_btcd); + } + } else printf("unexpected list entry %s vs %s at %d\n",contracts[contractnum],CURRENCIES[base],contractnum); + } + if ( strcmp(contracts[contractnum],"BTCUSD") != 0 ) + printf("unexpected contract (%s) at %d\n",contracts[contractnum],contractnum); + btcprice = (1. / btcdbtc); + prices[contractnum++].Pval = (PRICE_RESOLUTION / btcdbtc) / 1000.; + printf("btcprice %f = 1/%f %llu\n",btcprice,1./btcdbtc,(long long)prices[contractnum-1].Pval); + for (; contractnum<64; contractnum++) + { + //dprice = 0; + if ( contractnum == 63 && strcmp(contracts[contractnum],"BTCUSD") == 0 ) + dprice = btcusd; + else if ( contractnum == 62 && strcmp(contracts[contractnum],"BTCCNY") == 0 ) + dprice = btccny; + else if ( contractnum == 61 && strcmp(contracts[contractnum],"BTCRUB") == 0 ) + dprice = btcrub; + else if ( contractnum == 60 && strcmp(contracts[contractnum],"XAUUSD") == 0 ) + dprice = xauusd; + else + { + dprice = cprices[contractnum]; + if ( dprice > SMALLVAL && strlen(contracts[contractnum]) > 3 ) + { + if ( strcmp(contracts[contractnum]+strlen(contracts[contractnum])-3,"USD") == 0 || strcmp(contracts[contractnum],"COPPER") == 0 || strcmp(contracts[contractnum],"NGAS") == 0 || strcmp(contracts[contractnum],"UKOIL") == 0 || strcmp(contracts[contractnum],"USOIL") == 0 ) + dprice *= usdprice; + else if ( strcmp(contracts[contractnum],"SuperNET") == 0 ) + { + printf("SuperNET %f -> %f\n",dprice,dprice*btcprice); + dprice *= btcprice; + } + else if ( strcmp(contracts[contractnum]+strlen(contracts[contractnum])-3,"BTC") == 0 ) + dprice *= btcprice; + } + } + prices[contractnum].Pval = (uint64_t)((PRICE_RESOLUTION * dprice) * ((double)peggy_mils(contractnum) / 10000.)); + //if ( Debuglevel > 2 ) + { + struct price_resolution tmp; + tmp = peggy_scaleprice(prices[contractnum],peggy_mils(contractnum)); + printf("%.8f btcprice %.6f %f -->>> %s %.6f -> %llu %.6f mils.%d\n",cprices[contractnum],btcprice,cprices[contractnum]*btcprice,contracts[contractnum],Pval(&tmp),(long long)prices[contractnum].Pval,Pval(&prices[contractnum]),peggy_mils(contractnum)); + } + } + } + return(nonz); +} + +void init_Currencymasks() +{ + int32_t base,j,c; uint64_t basemask; + for (base=0; base= 0 ) + { + basemask |= (1L << c); + //printf("(%s %lx) ",CONTRACTS[c],1L<num - 1); + if ( timestamp >= spline->utc32[ind] ) + { + gap = (timestamp - spline->utc32[ind]); + if ( gap < lookahead ) + return(_extrapolate_spline64(spline->spline64[ind],gap)); + else return(0.); + } + else if ( timestamp <= spline->utc32[0] ) + { + gap = (spline->utc32[0] - timestamp); + if ( gap < lookahead ) + return(_extrapolate_spline64(spline->spline64[0],gap)); + else return(0.); + } + for (i=0; inum-1; i++) + { + ind = (i + spline->lasti) % (spline->num - 1); + if ( timestamp >= spline->utc32[ind] && timestamp < spline->utc32[ind+1] ) + { + spline->lasti = ind; + return(_extrapolate_spline64(spline->spline64[ind],timestamp - spline->utc32[ind])); + } + } + return(0.); +} + +double PAX_calcspline(struct PAX_spline *spline,double *outputs,double *slopes,int32_t dispwidth,uint32_t *utc32,double *splinevals,int32_t num) +{ + static double errsums[3]; static int errcount; + double c[MAX_SPLINES],f[MAX_SPLINES],dd[MAX_SPLINES],dl[MAX_SPLINES],du[MAX_SPLINES],gaps[MAX_SPLINES]; + int32_t n,i,lasti,x,numsplines,nonz; double vx,vy,vw,vz,gap,sum,xval,yval,abssum,lastval,lastxval,yval64,yval32,yval3; uint32_t gap32; + sum = lastxval = n = lasti = nonz = 0; + for (i=0; i 0 ) + { + if ( (gaps[n-1]= utc32[i] - lastxval) < 0 ) + { + printf("illegal gap %f to t%d\n",lastxval,utc32[i]); + return(0); + } + } + spline->utc32[n] = lastxval = utc32[i]; + n++; + } + } + if ( (numsplines= n) < 4 ) + return(0); + for (i=0; i=0; i--) + c[i] -= c[i+1] * du[i]; + //tridiagonal(n-2, dl, dd, du, c); + + for (i=n-3; i>=0; i--) + c[i+1] = c[i]; + c[0] = (1.0 + (double)gaps[0] / gaps[1]) * c[1] - ((double)gaps[0] / gaps[1] * c[2]); + c[n-1] = (1.0 + (double)gaps[n-2] / gaps[n-3] ) * c[n-2] - ((double)gaps[n-2] / gaps[n-3] * c[n-3]); + //printf("c[n-1] %f, n-2 %f, n-3 %f\n",c[n-1],c[n-2],c[n-3]); + abssum = nonz = lastval = 0; + outputs[spline->firstx] = f[0]; + spline->num = numsplines; + for (i=0; iutc32[i],(vx),vy*1000*1000,vz*1000*1000*1000*1000,vw*1000*1000*1000*1000*1000*1000,gap,conv_unixtime(&tmp,spline->utc32[i])); + spline->dSplines[i][0] = vx, spline->dSplines[i][1] = vy, spline->dSplines[i][2] = vz, spline->dSplines[i][3] = vw; + spline->spline64[i][0] = dto64(vx), spline->spline64[i][1] = dto64(vy*1000*1000), spline->spline64[i][2] = dto64(vz*1000*1000*1000*1000), spline->spline64[i][3] = dto64(vw*1000*1000*1000*1000*1000*1000); + spline->spline32[i][0] = dto32(vx), spline->spline32[i][1] = dto32(vy*1000*1000), spline->spline32[i][2] = dto32(vz*1000*1000*1000*1000), spline->spline32[i][3] = dto32(vw*1000*1000*1000*1000*1000*1000); + gap32 = gap = spline->dispincr; + xval = spline->utc32[i] + gap; + lastval = vx; + while ( i < n-1 ) + { + x = spline->firstx + ((xval - spline->utc32[0]) / spline->dispincr); + if ( x > dispwidth-1 ) x = dispwidth-1; + if ( x < 0 ) x = 0; + if ( (i < n-2 && gap > gaps[i] + spline->dispincr) ) + break; + if ( i == n-2 && xval > spline->utc32[n-1] + MAX_LOOKAHEAD*spline->dispincr ) + { + //printf("x.%d dispwidth.%d xval %f > utc[n-1] %f + %f\n",x,dispwidth,xval,utc[n-1],MAX_LOOKAHEAD*incr); + break; + } + if ( x >= 0 ) + { + yval = _extrapolate_Spline(spline->dSplines[i],gap); + yval64 = _extrapolate_spline64(spline->spline64[i],gap32); + if ( (yval3 = PAX_splineval(spline,gap32 + spline->utc32[i],MAX_LOOKAHEAD*spline->dispincr)) != 0 ) + { + yval32 = _extrapolate_spline32(spline->spline32[i],gap32); + errsums[0] += fabs(yval - yval64), errsums[1] += fabs(yval - yval32), errsums[2] += fabs(yval - yval3), errcount++; + if ( fabs(yval - yval3) > SMALLVAL ) + printf("(%.10f vs %.10f %.10f %.10f [%.16f %.16f %.16f]) ",yval,yval64,yval32,yval3, errsums[0]/errcount,errsums[1]/errcount,errsums[2]/errcount); + } + if ( yval > 5000. ) yval = 5000.; + else if ( yval < -5000. ) yval = -5000.; + if ( isnan(yval) == 0 ) + { + outputs[x] = yval; + spline->lastval = outputs[x], spline->lastutc = xval; + if ( 1 && fabs(lastval) > SMALLVAL ) + { + if ( lastval != 0 && outputs[x] != 0 ) + { + if ( slopes != 0 ) + slopes[x] = (outputs[x] - lastval), abssum += fabs(slopes[x]); + nonz++; + } + } + } + //else outputs[x] = 0.; + //printf("x.%-4d %d %f %f %f i%-4d: gap %9.6f %9.6f last %9.6f slope %9.6f | %9.1f [%9.1f %9.6f %9.6f %9.6f %9.6f]\n",x,firstx,xval,utc[0],incr,i,gap,yval,lastval,slopes[x],xval,utc[i+1],dSplines[i][0],dSplines[i][1]*1000*1000,dSplines[i][2]*1000*1000*1000*1000,dSplines[i][3]*1000*1000*1000*1000*1000*1000); + } + gap32 += spline->dispincr, gap += spline->dispincr, xval += spline->dispincr; + } + //double pred = (i>0) ? _extrapolate_Spline(dSplines[i-1],gaps[i-1]) : 0.; + //printf("%2d: w%8.1f [gap %f -> %9.6f | %9.6f %9.6f %9.6f %9.6f %9.6f]\n",i,weekinds[i],gap,pred,f[i],dSplines[i].x,1000000*dSplines[i].y,1000000*1000000*dSplines[i].z,1000000*1000000*1000*dSplines[i].w); + } + if ( nonz != 0 ) + abssum /= nonz; + spline->aveslopeabs = abssum; + return(lastval); +} + +int32_t PAX_genspline(struct PAX_spline *spline,int32_t splineid,char *name,uint32_t *utc32,double *splinevals,int32_t maxsplines,double *refvals) +{ + int32_t i; double output[2048],slopes[2048],origvals[MAX_SPLINES]; + memset(spline,0,sizeof(*spline)), memset(output,0,sizeof(output)), memset(slopes,0,sizeof(slopes)); + spline->dispincr = 3600, spline->basenum = splineid, strcpy(spline->name,name); + memcpy(origvals,splinevals,sizeof(*splinevals) * MAX_SPLINES); + spline->lastval = PAX_calcspline(spline,output,slopes,sizeof(output)/sizeof(*output),utc32,splinevals,maxsplines); + for (i=0; inum+3; i++) + { + if ( i < spline->num ) + { + if ( refvals[i] != 0 && output[i * 24] != refvals[i] ) + printf("{%.8f != %.8f}.%d ",output[i * 24],refvals[i],i); + } + else printf("{%.8f %.3f} ",output[i * 24],slopes[i * 24]/spline->aveslopeabs); + spline->pricevals[i] = output[i * 24]; + } + printf("spline.%s num.%d\n",name,spline->num); + return(spline->num); +} + +int32_t PAX_calcmatrix(double matrix[32][32]) +{ + int32_t basenum,relnum,nonz,vnum,iter,numbase,numerrs = 0; double sum,vsum,price,price2,basevals[32],errsum=0; + memset(basevals,0,sizeof(basevals)); + for (iter=0; iter<2; iter++) + { + numbase = 32; + for (basenum=0; basenum price ) + // printf("base.%d rel.%d price2 %f vs %f\n",basenum,relnum,1/price2,price); + } + } + if ( iter == 0 ) + sum += 1., vsum += 1.; + if ( nonz != 0 ) + sum /= nonz; + if ( vnum != 0 ) + vsum /= vnum; + if ( iter == 0 ) + basevals[basenum] = (sum + 1./vsum) / 2.; + else errsum += (sum + vsum)/2, numerrs++;//, printf("(%.8f %.8f) ",sum,vsum); + //printf("date.%d (%.8f/%d %.8f/%d).%02d -> %.8f\n",i,sum,nonz,vsum,vnum,basenum,basevals[basenum]); + } + if ( iter == 0 ) + { + for (sum=relnum=0; relnumdata.ecbmatrix,sizeof(PEGS->data.ecbmatrix)); + PAX_calcmatrix(Hmatrix); + /*for (i=0; i<32; i++) + { + for (j=0; j<32; j++) + printf("%.6f ",Hmatrix[i][j]); + printf("%s\n",CURRENCIES[i]); + }*/ + btcusd = PEGS->data.btcusd; + btcdbtc = PEGS->data.btcdbtc; + if ( btcusd > SMALLVAL ) + dxblend(&PEGS->btcusd,btcusd,.9); + if ( btcdbtc > SMALLVAL ) + dxblend(&PEGS->btcdbtc,btcdbtc,.9); + // char *cryptostrs[8] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp" }; + // "BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced + for (i=0; ibtcusd; + continue; + } + else if ( i == num-2 && strcmp(contracts[i],"BTCCNY") == 0 ) + { + continue; + } + else if ( i == num-3 && strcmp(contracts[i],"BTCRUB") == 0 ) + { + continue; + } + else if ( i == num-4 && strcmp(contracts[i],"XAUUSD") == 0 ) + { + continue; + } + if ( strcmp(contracts[i],"NXTBTC") == 0 ) + RTprices[i] = PEGS->data.cryptos[1]; + else if ( strcmp(contracts[i],"SuperNET") == 0 ) + RTprices[i] = PEGS->data.cryptos[2]; + else if ( strcmp(contracts[i],"ETHBTC") == 0 ) + RTprices[i] = PEGS->data.cryptos[3]; + else if ( strcmp(contracts[i],"LTCBTC") == 0 ) + RTprices[i] = PEGS->data.cryptos[4]; + else if ( strcmp(contracts[i],"XMRBTC") == 0 ) + RTprices[i] = PEGS->data.cryptos[5]; + else if ( strcmp(contracts[i],"BTSBTC") == 0 ) + RTprices[i] = PEGS->data.cryptos[6]; + else if ( strcmp(contracts[i],"XCPBTC") == 0 ) + RTprices[i] = PEGS->data.cryptos[7]; + else if ( i < 32 ) + { + basevals[i] = Hmatrix[i][i]; + //if ( Debuglevel > 2 ) + printf("(%s %f).%d ",CURRENCIES[i],basevals[i],i); + } + else if ( (c= PAX_contractnum(contracts[i],0)) >= 0 ) + { + RTprices[i] = PEGS->data.RTprices[c]; + //if ( is_decimalstr(contracts[i]+strlen(contracts[i])-2) != 0 ) + // cprices[i] *= .0001; + } + else + { + for (j=0; jdata.RTmetals[j]; + break; + } + } + } + //if ( Debuglevel > 2 ) + printf("(%f %f) i.%d num.%d %s %f\n",PEGS->btcusd,PEGS->btcdbtc,i,num,contracts[i],RTprices[i]); + //printf("RT.(%s %f) ",contracts[i],RTprices[i]); + } + return(PEGS->data.ecbdatenum); +} + +char *peggy_emitprices(int32_t *nonzp,struct peggy_info *PEGS,uint32_t blocktimestamp,int32_t maxlockdays) +{ + double matrix[32][32],RTmatrix[32][32],cprices[64],basevals[64]; struct price_resolution prices[256]; + cJSON *json,*array; char *jsonstr,*opreturnstr = 0; int32_t i,nonz = 0; + memset(cprices,0,sizeof(cprices)); + //printf("peggy_emitprices\n"); + if ( PAX_getmatrix(basevals,PEGS,matrix,cprices+1,peggy_bases+1,sizeof(peggy_bases)/sizeof(*peggy_bases)-1,blocktimestamp) > 0 ) + { + cprices[0] = PEGS->btcdbtc; + /*for (i=0; i<32; i++) + printf("%f ",basevals[i]); + printf("basevals\n"); + for (i=0; i<64; i++) + printf("%f ",cprices[i]); + printf("cprices\n");*/ + json = cJSON_CreateObject(), array = cJSON_CreateArray(); + memset(prices,0,sizeof(prices)); + memset(matrix,0,sizeof(matrix)); + memset(RTmatrix,0,sizeof(RTmatrix)); + peggy_prices(prices,PEGS->btcusd,PEGS->btcdbtc,peggy_bases,sizeof(peggy_bases)/sizeof(*peggy_bases),cprices,basevals); + for (i=0; i 2 ) + printf("{%s %.6f %u}.%d ",peggy_bases[i],Pval(&prices[i]),(uint32_t)prices[i].Pval,peggy_mils(i)); + } + jaddnum(json,"txtype",PEGGY_TXPRICES); + //jaddnum(json,"btcusd",btc.Pval); + if ( maxlockdays != 0 ) + { + jaddnum(json,"timestamp",blocktimestamp); + jaddnum(json,"maxlockdays",maxlockdays); + } + //jaddstr(json,"privkey","1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b"); + jadd(json,"details",array); + jsonstr = jprint(json,1); + //printf("%s\n",jsonstr); + opreturnstr = peggy_tx(jsonstr); + free(jsonstr); + } else printf("pricematrix returned null\n"); + *nonzp = nonz; + //printf("nonz.%d\n",nonz); + return(opreturnstr); +} + +double PAX_baseprice(struct peggy_info *PEGS,uint32_t timestamp,int32_t basenum) +{ + double btc,btcd,btcdusd,usdval; + btc = 1000. * _pairaved(PAX_splineval(&PEGS->splines[MAX_CURRENCIES+0],timestamp,0),PAX_splineval(&PEGS->splines[MAX_CURRENCIES+1],timestamp,0)); + btcd = .01 * PAX_splineval(&PEGS->splines[MAX_CURRENCIES+2],timestamp,0); + if ( btc != 0. && btcd != 0. ) + { + btcdusd = (btc * btcd); + usdval = PAX_splineval(&PEGS->splines[USD],timestamp,0); + if ( basenum == USD ) + return(1. / btcdusd); + else return(PAX_splineval(&PEGS->splines[basenum],timestamp,0) / (btcdusd * usdval)); + } + return(0.); +} + +double PAX_getprice(char *retbuf,char *base,char *rel,char *contract,struct peggy_info *PEGS) +{ + int32_t i,c,basenum,relnum,n = 0; double yprice,daily,revdaily,price; + struct PAX_data *dp = &PEGS->data; + price = yprice = daily = revdaily = 0.; + PAX_ispair(base,rel,contract); + if ( base[0] != 0 && rel[0] != 0 ) + { + basenum = PAX_basenum(base), relnum = PAX_basenum(rel); + if ( basenum >= 0 && relnum >= 0 && basenum < MAX_CURRENCIES && relnum < MAX_CURRENCIES ) + daily = dp->dailyprices[basenum*MAX_CURRENCIES + relnum], revdaily = dp->dailyprices[relnum*MAX_CURRENCIES + basenum]; + } + for (i=0; imetals[i]; + break; + } + sprintf(retbuf,"{\"result\":\"success\",\"contract\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\"",contract,base,rel); + if ( (c= PAX_contractnum(contract,0)) >= 0 ) + { + if ( dp->tbids[c] != 0. && dp->tasks[c] != 0. ) + { + price += (dp->tbids[c] + dp->tasks[c]), n += 2; + sprintf(retbuf+strlen(retbuf),",\"truefx\":{\"timestamp\":\"%u\",\"bid\":%.8f,\"ask\":%.8f}",dp->ttimestamps[c],dp->tbids[c],dp->tasks[c]); + } + if ( dp->fbids[c] != 0. && dp->fasks[c] != 0. ) + { + price += (dp->fbids[c] + dp->fasks[c]), n += 2; + sprintf(retbuf+strlen(retbuf),",\"fxcm\":{\"bid\":%.8f,\"ask\":%.8f}",dp->fbids[c],dp->fasks[c]); + } + if ( dp->ibids[c] != 0. && dp->iasks[c] != 0. ) + { + price += (dp->ibids[c] + dp->iasks[c]), n += 2; + sprintf(retbuf+strlen(retbuf),",\"instaforex\":{\"timestamp\":%u,\"bid\":%.8f,\"ask\":%.8f}",dp->itimestamps[c],dp->ibids[c],dp->iasks[c]); + } + if ( yprice != 0. ) + sprintf(retbuf+strlen(retbuf),",\"yahoo\":{\"price\":%.8f}",yprice); + if ( daily != 0. || revdaily != 0. ) + sprintf(retbuf+strlen(retbuf),",\"ecb\":{\"date\":\"%s\",\"daily\":%.8f,\"reverse\":%.8f}",dp->edate,daily,revdaily); + } + if ( n > 0 ) + price /= n; + sprintf(retbuf+strlen(retbuf),",\"aveprice\":%.8f,\"n\":%d}",price,n); + return(price); +} + + +#include "../includes/iguana_apidefs.h" +#include "../includes/iguana_apideclares.h" + +void PAX_init(struct peggy_info *PEGS) +{ + double commission = 0.; + init_Currencymasks(); + tradebot_monitorall(0,0,0,0,"fxcm",commission); + tradebot_monitorall(0,0,0,0,"truefx",commission); + tradebot_monitorall(0,0,0,0,"instaforex",commission); +} + +#include "../includes/iguana_apiundefs.h" diff --git a/iguana/peggy_ramkv.c b/iguana/peggy_ramkv.c new file mode 100755 index 000000000..b8d6e1b30 --- /dev/null +++ b/iguana/peggy_ramkv.c @@ -0,0 +1,243 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "peggy.h" + +void ramkv777_lock(struct ramkv777 *kv) +{ + if ( kv->threadsafe != 0 ) + portable_mutex_lock(&kv->mutex); +} + +void ramkv777_unlock(struct ramkv777 *kv) +{ + if ( kv->threadsafe != 0 ) + portable_mutex_unlock(&kv->mutex); +} + +int32_t ramkv777_delete(struct ramkv777 *kv,void *key) +{ + int32_t retval = -1; struct ramkv777_item *ptr = 0; + if ( kv == 0 ) + return(-1); + ramkv777_lock(kv); + HASH_FIND(hh,kv->table,key,kv->keysize,ptr); + if ( ptr != 0 ) + { + HASH_DELETE(hh,kv->table,ptr); + free(ptr); + retval = 0; + } + ramkv777_lock(kv); + return(retval); +} + +void *ramkv777_read(int32_t *valuesizep,struct ramkv777 *kv,void *key) +{ + struct ramkv777_item *item = 0; + if ( kv == 0 ) + { + printf("ramkv777_read: null ramkv??\n"); + return(0); + } + //printf("search for [%llx] keysize.%d\n",*(long long *)key,keysize); + ramkv777_lock(kv); + HASH_FIND(hh,kv->table,key,kv->keysize,item); + ramkv777_unlock(kv); + if ( item != 0 ) + { + if ( valuesizep != 0 ) + *valuesizep = item->valuesize; + return(ramkv777_itemvalue(kv,item)); + } //else printf("cant find key.%llx keysize.%d\n",*(long long *)key,kv->keysize); + if ( valuesizep != 0 ) + *valuesizep = 0; + return(0); +} + +void *ramkv777_write(struct ramkv777 *kv,void *key,void *value,int32_t valuesize) +{ + struct ramkv777_item *item = 0; int32_t keysize = kv->keysize; + if ( kv == 0 ) + return(0); + ramkv777_lock(kv); + HASH_FIND(hh,kv->table,key,keysize,item); + if ( item != 0 ) + { + printf("item being added, already there\n"); + if ( valuesize == item->valuesize ) + { + if ( memcmp(ramkv777_itemvalue(kv,item),value,valuesize) != 0 ) + { + vupdate_sha256(kv->sha256.bytes,&kv->state,key,kv->keysize); + vupdate_sha256(kv->sha256.bytes,&kv->state,value,valuesize); + memcpy(ramkv777_itemvalue(kv,item),value,valuesize); + } + ramkv777_unlock(kv); + return(item); + } + HASH_DELETE(hh,kv->table,item); + free(item); + vupdate_sha256(kv->sha256.bytes,&kv->state,key,kv->keysize); + } + item = calloc(1,ramkv777_itemsize(kv,valuesize)); + memcpy(item->keyvalue,key,kv->keysize); + memcpy(ramkv777_itemvalue(kv,item),value,valuesize); + item->valuesize = valuesize; + item->rawind = (kv->numkeys++ * ACCTS777_MAXRAMKVS) | kv->kvind; + //printf("add.(%s) kv->numkeys.%d keysize.%d valuesize.%d [%llx]\n",kv->name,kv->numkeys,keysize,valuesize,*(long long *)ramkv777_itemkey(item)); + HASH_ADD_KEYPTR(hh,kv->table,ramkv777_itemkey(item),kv->keysize,item); + vupdate_sha256(kv->sha256.bytes,&kv->state,key,kv->keysize); + vupdate_sha256(kv->sha256.bytes,&kv->state,value,valuesize); + ramkv777_unlock(kv); + if ( kv->dispflag != 0 ) + fprintf(stderr,"%016llx ramkv777_write numkeys.%d kv.%p table.%p write kep.%p key.%llx size.%d, value.(%08x) size.%d\n",(long long)kv->sha256.txid,kv->numkeys,kv,kv->table,key,*(long long *)key,keysize,calc_crc32(0,value,valuesize),valuesize); + return(ramkv777_itemvalue(kv,item)); +} + +void *ramkv777_iterate(struct ramkv777 *kv,void *args,void *(*iterator)(struct ramkv777 *kv,void *args,void *key,void *value,int32_t valuesize)) +{ + struct ramkv777_item *item,*tmp; void *retval = 0; + if ( kv == 0 ) + return(0); + ramkv777_lock(kv); + HASH_ITER(hh,kv->table,item,tmp) + { + if ( (retval= (*iterator)(kv,args!=0?args:item,item->keyvalue,ramkv777_itemvalue(kv,item),item->valuesize)) != 0 ) + { + ramkv777_unlock(kv); + return(retval); + } + } + ramkv777_unlock(kv); + return(0); +} + +void *ramkv777_saveiterator(struct ramkv777 *kv,void *args,void *key,void *value,int32_t valuesize) +{ + FILE *fp = args; + if ( args != 0 ) + { + if ( fwrite(key,1,kv->keysize,fp) != kv->keysize ) + { + printf("Error saving key.[%d]\n",kv->keysize); + return(key); + } + } + return(0); +} + +/*char *OS_mvstr() +{ +#ifdef __WIN32 + return("rename"); +#else + return("mv"); +#endif +}*/ +char *OS_mvstr(); +long ramkv777_save(struct ramkv777 *kv) +{ + FILE *fp; long retval = -1; char fname[512],oldfname[512],cmd[512]; + sprintf(fname,"%s.tmp",kv->name); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( ramkv777_iterate(kv,fp,ramkv777_saveiterator) == 0 ) + { + printf("save %ld to HDD\n",ftell(fp)); + retval = ftell(fp); + } + else printf("error saving item at %ld\n",ftell(fp)); + fclose(fp); + } else printf("error creating(%s)\n",fname); + if ( retval > 0 ) + { + sprintf(oldfname,"%s.%u",kv->name,(uint32_t)time(NULL)); + sprintf(cmd,"%s %s %s",OS_mvstr(),kv->name,oldfname), system(cmd); + sprintf(cmd,"%s %s %s",OS_mvstr(),fname,kv->name), system(cmd); + } + return(retval); +} + +struct ramkv777 *ramkv777_init(int32_t kvind,char *name,int32_t keysize,int32_t threadsafe) +{ + struct ramkv777 *kv; + printf("ramkv777_init.(%s)\n",name); + kv = calloc(1,sizeof(*kv)); + strcpy(kv->name,name); + kv->threadsafe = threadsafe, kv->keysize = keysize, kv->kvind = kvind;//, kv->dispflag = 1; + portable_mutex_init(&kv->mutex); + vupdate_sha256(kv->sha256.bytes,&kv->state,0,0); + return(kv); +} + +int32_t ramkv777_disp(struct ramkv777 *kv) +{ + struct ramkv777_item *item,*tmp; int32_t n = 0; + printf("ramkv777_disp.(%s)\n",kv->name); + if ( kv == 0 ) + return(0); + ramkv777_lock(kv); + HASH_ITER(hh,kv->table,item,tmp) + { + n++; + printf("%llx: %llx\n",*(long long *)ramkv777_itemkey(item),*(long long *)ramkv777_itemvalue(kv,item)); + } + ramkv777_unlock(kv); + printf("ramkv777_disp.(%s) n.%d items\n",kv->name,n); + return(n); +} + +void ramkv777_free(struct ramkv777 *kv) +{ + struct ramkv777_item *ptr,*tmp; + if ( kv != 0 ) + { + HASH_ITER(hh,kv->table,ptr,tmp) + { + HASH_DEL(kv->table,ptr); + free(ptr); + } + free(kv); + } +} + +int32_t ramkv777_clone(struct ramkv777 *clone,struct ramkv777 *kv) +{ + struct ramkv777_item *item,*tmp; int32_t n = 0; + if ( kv != 0 ) + { + HASH_ITER(hh,kv->table,item,tmp) + { + ramkv777_write(clone,item->keyvalue,ramkv777_itemvalue(kv,item),item->valuesize); + n++; + } + } + return(n); +} + +struct ramkv777_item *ramkv777_itemptr(struct ramkv777 *kv,void *value) +{ + struct ramkv777_item *item = 0; + if ( kv != 0 && value != 0 ) + { + value = (void *)((long)value - (kv)->keysize); + item = (void *)((long)value - ((long)item->keyvalue - (long)item)); + } + return(item); +} + + + diff --git a/iguana/peggy_serdes.c b/iguana/peggy_serdes.c new file mode 100755 index 000000000..c24cc3c8e --- /dev/null +++ b/iguana/peggy_serdes.c @@ -0,0 +1,812 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "peggy.h" + +int32_t serdes777_rwbits(int32_t rwflag,void *ptr,int32_t len,HUFF *hp) +{ + int32_t i,bit; + if ( rwflag == 0 ) + { + for (i=0; i= (1 << sizebits) ) + { + printf("numbits overflow.%d doesnt fit into sizebits.%d\n",numbits,sizebits); + return(-10); + } + } + if ( serdes777_rwbits(rwflag,&numbits,sizebits,hp) != sizebits ) + return(-20); + if ( serdes777_rwbits(rwflag,xptr,numbits+1,hp) != numbits+1 ) + return(-30); + //printf("return.(%02x) numbits.%d + 1 + sizebits.%d\n",*(uint8_t *)xptr,numbits,sizebits); + //printf("(%02x) ",*(uint8_t *)xptr); + return(numbits + 1 + sizebits); + } +} + +#define serdes777_rwchar(rwflag,x,hp) serdes777_rwsizebits(rwflag,xptr,*(uint8_t *)xptr,3,hp) +#define serdes777_rwshort(rwflag,x,hp) serdes777_rwsizebits(rwflag,xptr,*(uint16_t *)xptr,4,hp) +#define serdes777_rwint(rwflag,x,hp) serdes777_rwsizebits(rwflag,xptr,*(uint32_t *)xptr,5,hp) +#define serdes777_rwlong(rwflag,x,hp) serdes777_rwsizebits(rwflag,xptr,*(uint64_t *)xptr,6,hp) + +int32_t serdes777_convstr(int32_t encoding,void *dest,void *src,int32_t len) +{ + if ( encoding == 16 ) + { + len >>= 1; + decode_hex(dest,len,src); + return(8 * len); + } + else if ( encoding == -16 ) + { + init_hexbytes_noT(dest,src,len); + return(8 * ((len << 1) + 1)); + } + else if ( encoding == 32 ) + return(decode_base32(dest,src,len)); + else if ( encoding == -32 ) + return(init_base32(dest,src,len)); + return(-1); +} + +int32_t serdes777_rwvarstr(int32_t rwflag,uint8_t *data,int32_t *lenp,HUFF *hp) +{ + int32_t i,n,numbits,total; void *xptr = lenp; + if ( (total= serdes777_rwchar(rwflag,lenp,hp)) < 0 ) + return(total); + n = *lenp; + for (i=0; ipeg) }, { (long)&lock->denom - (long)lock, sizeof(lock->denom) }, + { (long)&lock->minlockdays - (long)lock, sizeof(lock->minlockdays) }, { (long)&lock->maxlockdays - (long)lock, sizeof(lock->maxlockdays) }, + { (long)&lock->clonesmear - (long)lock, sizeof(lock->clonesmear) }, { (long)&lock->mixrange - (long)lock, sizeof(lock->mixrange) }, + { (long)&lock->margin - (long)lock, sizeof(lock->margin) }, + }; + return(serdes777_codec(rwflag,lock,sizeof(*lock),serdes777_locktokens,sizeof(serdes777_locktokens)/sizeof(*serdes777_locktokens),TX)); +} + +int32_t serdes777_rwaddr(int32_t rwflag,union peggy_addr *addr,int32_t type,HUFF *TX) +{ + int32_t n,numbits = 0; + switch ( type ) + { + case PEGGY_ADDRBTCD: numbits = serdes777_rw(rwflag,&addr->coinaddr,0,TX); break; + case PEGGY_ADDRNXT: numbits = serdes777_rw(rwflag,&addr->nxt64bits,(int32_t)-sizeof(addr->nxt64bits),TX); break; + case PEGGY_ADDRCREATE: + if ( (numbits= serdes777_rw(rwflag,&addr->newunit.sha256.bytes,(int32_t)-sizeof(addr->newunit.sha256),TX)) < 0 ) + return(-3); + if ( (n= serdes777_rwlock(rwflag,&addr->newunit.newlock,TX)) < 0 ) + return(-2); + numbits += n; + break; + case PEGGY_ADDRUNIT: + case PEGGY_ADDRPUBKEY: + if ( (numbits= serdes777_rw(rwflag,&addr->newunit.sha256.bytes,(int32_t)-sizeof(addr->newunit.sha256),TX)) < 0 ) + return(-3); + if ( (n= serdes777_rw(rwflag,&addr->newunit.newlock.peg,sizeof(addr->newunit.newlock.peg),TX)) < 0 ) + return(-2); + if ( (n= serdes777_rw(rwflag,&addr->newunit.newlock.minlockdays,sizeof(addr->newunit.newlock.minlockdays),TX)) < 0 ) + return(-2); + case PEGGY_ADDR777: + numbits = serdes777_rw(rwflag,&addr->SaMbits.bytes,(int32_t)-sizeof(addr->SaMbits),TX); break; + default: numbits = -1; break; + } + return(numbits); +} + +int32_t serdes777_rwbets(int32_t rwflag,struct peggy_txbet *bets,int32_t numbets,HUFF *TX) +{ + long serdes777_bettokens[][2] = + { + { 0, sizeof(bets[0].prediction) }, + { (long)&bets[0].peg - (long)bets, 0 }, + { (long)&bets[0].binary - (long)bets, sizeof(bets[0].binary) } + }; + int32_t i,n,numbits = 0; + if ( numbets <= 0 ) + return(0); + for (i=0; itype,sizeof(in->type),TX); + b = serdes777_rw(rwflag,&in->chainlen,sizeof(in->chainlen),TX); + c = serdes777_rwaddr(rwflag,&in->src,in->type,TX); + d = serdes777_rw(rwflag,&in->amount,sizeof(in->amount),TX); + type = in->type; + } + else + { + out = inout; + a = serdes777_rw(rwflag,&out->type,sizeof(out->type),TX); + b = serdes777_rw(rwflag,&out->vin,sizeof(out->vin),TX); + c = serdes777_rwaddr(rwflag,&out->dest,out->type,TX); + d = serdes777_rw(rwflag,&out->ratio,sizeof(out->ratio),TX); + type = out->type; + } + if ( a < 0 || b < 0 || c < 0 || d < 0 ) + { + printf("serdes777_rwinput.%d error encoding type.%d %d %d %d %d\n",rwflag,type,a,b,c,d); + //getchar(); + return(-1); + } + return(a + b + c + d); +} + +int32_t serdes777_rwprices(int32_t rwflag,struct peggy_txprices *price,HUFF *TX) +{ + long serdes777_pricetokens[][2] = + { + { 0, sizeof(price->num) }, //{ (long)&prices->btcusd - (long)prices, sizeof(prices->btcusd) }, + { (long)&price->timestamp - (long)price, sizeof(price->timestamp) }, + { (long)&price->maxlockdays - (long)price, sizeof(price->maxlockdays) } + }; + long serdes777_pricetoken2[][2] = { { 0, sizeof(price->feed[0]) } }; + int32_t i,n,numbits = -1; + if ( (numbits= serdes777_codec(rwflag,&price->num,sizeof(price->num),serdes777_pricetokens,sizeof(serdes777_pricetokens)/sizeof(*serdes777_pricetokens),TX)) < 0 ) + return(-1); + //printf("numprices.%u btcusd %.6f: ",prices->num,(double)1000.*prices->btcusd); + for (i=0; inum; i++) + { + if ( (n= serdes777_codec(rwflag,&price->feed[i],sizeof(price->feed[i]),serdes777_pricetoken2,sizeof(serdes777_pricetoken2)/sizeof(*serdes777_pricetoken2),TX)) < 0 ) + return(-1); + //printf("(%d of %d %u) ",i,prices->num,prices->prices[i]); + numbits += n; + } + return(numbits); +} + +int32_t serdes777_rwtune(int32_t rwflag,struct peggy_txtune *tune,int32_t numtunes,HUFF *TX) +{ + long serdes777_tunetokens[][2] = + { + { 0, sizeof(tune[0].type) }, + { (long)&tune[0].peg - (long)tune, 0 }, + { (long)&tune[0].val - (long)tune, sizeof(tune[0].val) }, + { (long)&tune[0].B - (long)tune, sizeof(tune[0].B) }, + }; + int32_t i,n,numbits = -1; + if ( numtunes <= 0 ) + return(0); + for (i=0; ibitoffset,Ptx->txtype); + switch ( Ptx->txtype ) + { + case PEGGY_TXBET: numbits = serdes777_rwbets(rwflag,Ptx->details.bets,Ptx->numdetails,TX); break; + case PEGGY_TXPRICES: numbits = serdes777_rwprices(rwflag,&Ptx->details.price,TX); break; + case PEGGY_TXTUNE: break; numbits = serdes777_rwtune(rwflag,Ptx->details.tune,Ptx->numdetails,TX); break; + case PEGGY_TXMICROPAY: numbits = serdes777_rwmicropay(rwflag,Ptx->details.micropays,Ptx->numdetails,TX); break; + } + if ( numbits < 0 ) + return(-1); + if ( Ptx->msglen != 0 ) + { + if ( (n = serdes777_rwstr(rwflag,(uint8_t *)Ptx->hexstr,TX,16)) < 0 ) + return(-1); + numbits += n; + } + return(numbits); +} + +int32_t serdes777_sethdrtokens(long serdes777_hdrtokens[][2],struct peggy_tx *Ptx) +{ + long hdrtokens[][2] = + { + { 0, -sizeof(Ptx->datalen) }, + { (long)&Ptx->numinputs - (long)Ptx, sizeof(Ptx->numinputs) }, + { (long)&Ptx->numoutputs - (long)Ptx, sizeof(Ptx->numoutputs) }, + { (long)&Ptx->txtype - (long)Ptx, sizeof(Ptx->txtype) }, + { (long)&Ptx->flags - (long)Ptx, sizeof(Ptx->flags) }, + { (long)&Ptx->msglen - (long)Ptx, sizeof(Ptx->msglen) }, + { (long)&Ptx->numdetails - (long)Ptx, sizeof(Ptx->numdetails) }, + { (long)&Ptx->timestamp - (long)Ptx, sizeof(Ptx->timestamp) }, + { (long)&Ptx->activation - (long)Ptx, sizeof(Ptx->activation) }, + { (long)&Ptx->expiration - (long)Ptx, sizeof(Ptx->expiration) }, + }; + memcpy(serdes777_hdrtokens,hdrtokens,sizeof(hdrtokens)); + return((int32_t)(sizeof(hdrtokens)/sizeof(*hdrtokens))); +} + +int32_t serdes777_rwtx(int32_t rwflag,struct peggy_tx *Ptx,HUFF *TX) +{ + int32_t i,n,iter,numbits,totalbits = 0; void *ptr; long serdes777_hdrtokens[16][2]; + //printf("peggy_rwtx.%d %p %p size.%d\n",rwflag,Ptx,TX,TX->endpos); + if ( (totalbits= serdes777_codec(rwflag,Ptx,sizeof(*Ptx),serdes777_hdrtokens,serdes777_sethdrtokens(serdes777_hdrtokens,Ptx),TX)) < 0 ) + { + printf("serdes777_process error decoding opreturn datalen.%d hdrtokens\n",totalbits); + return(-1); + } + if ( (Ptx->flags & PEGGY_FLAGS_HASFUNDING) != 0 ) + { + if ( (numbits= serdes777_rwinout(rwflag,0,&Ptx->funding,TX)) < 0 ) + { + printf("serdes777_process error serdes.%d funding %.8f %p\n",rwflag,dstr(Ptx->funding.amount),&Ptx->funding.src.coinaddr); + return(-1); + } + totalbits += numbits; + } + n = Ptx->numinputs; + for (iter=0; iter<2; iter++) + { + for (i=0; iinputs[i]; + else ptr = &Ptx->outputs[i]; + if ( (numbits= serdes777_rwinout(rwflag,iter,ptr,TX)) < 0 ) + { + printf("serdes777_process error serdes.%d input.%d\n",rwflag,i); + return(-1); + } + totalbits += numbits; + printf("%d iter.%d .%d\n",i,iter,totalbits/8); + } + n = Ptx->numoutputs; + } + if ( (numbits= serdes777_rwdetails(rwflag,Ptx,TX)) < 0 ) + { + printf("serdes777_process error serdes777_rwdetails.%d datalen.%d\n",i,totalbits); + return(-1); + } + totalbits += numbits; + return(totalbits); +} + +int serdes777_checktimestamp(uint32_t blocktimestamp,uint32_t timestamp) +{ + if ( blocktimestamp == 0 || timestamp == 0 ) + return(0); + else if ( timestamp < ((int64_t)blocktimestamp - PEGGY_PASTSTAMP) || timestamp > ((int64_t)blocktimestamp + PEGGY_FUTURESTAMP) ) + return(-1); + return(0); +} + +int32_t serdes777_deserialize(int32_t *signedcountp,struct peggy_tx *Ptx,uint32_t blocktimestamp,uint8_t *data,int32_t totallen) +{ + int32_t i,n,len,totalbits,remains; HUFF TX; + memset(Ptx,0,sizeof(*Ptx)); + memcpy(Ptx->data,data,totallen); + memset(&TX,0,sizeof(TX)), _init_HUFF(&TX,totallen,data), TX.endpos = (totallen * 8); + if ( (totalbits= serdes777_rwtx(0,Ptx,&TX)) < 0 ) + return(-1); + if ( serdes777_checktimestamp(blocktimestamp,Ptx->timestamp) < 0 ) + { + printf("serdes777_deserialize: timestamp.%u too different from Ptx %u %d\n",blocktimestamp,Ptx->timestamp,blocktimestamp - Ptx->timestamp); + return(-1); + } + if ( (len= (int32_t)hconv_bitlen(totalbits)) > totallen ) + { + printf("serdes777_process error totalbits.%d len.%d exceeded totallen.%d\n",totalbits,len,totallen); + return(-1); + } + Ptx->datalen = len; + //for (i=0; idata[i]); + //printf(" crc.%08x datalen.%d vs totallen.%d\n",_crc32(0,Ptx->data,len),len,totallen); + remains = (totallen - len); + if ( (remains % sizeof(bits256)) != 0 ) + { + printf("serdes777_process error totalbits.%d remains.%d nonzero modval.%d\n",totalbits,remains,(int32_t)(remains % sizeof(bits256))); + return(-1); + } + n = (int32_t)(remains / sizeof(bits256)); + //printf("n.%d remains.%d\n",n,remains); + if ( n > 0 ) + { + if ( Ptx->numinputs == 1 && Ptx->inputs[0].type == PEGGY_ADDRPUBKEY && n == 1 ) + { + memcpy(Ptx->sigs[0].sigbits.bytes,&data[len],sizeof(bits256)), len += sizeof(bits256); + Ptx->sigs[0].pubkey = Ptx->inputs[0].src.sha256; + } + else + { + for (i=0; isigs[i/2].sigbits.bytes : Ptx->sigs[i/2].pubkey.bytes,&data[len],sizeof(bits256)); + } + for (i=0; isigs[i].sigbits.txid != 0 ) + { + if ( (Ptx->sigs[i].signer64bits= PAX_validate(&Ptx->sigs[i],Ptx->timestamp,Ptx->data,Ptx->datalen)) == 0 ) + { + printf("Tx validation error at sig.%d\n",i); + return(-1); + } + (*signedcountp)++; + printf("len.%d verify.%d t%u %llx %llu\n",len,i,Ptx->timestamp,(long long)Ptx->sigs[i].sigbits.txid,(long long)Ptx->sigs[i].signer64bits); + } + else break; + } + } + return(len); +} + +int32_t serdes777_serialize(struct peggy_tx *Ptx,uint32_t blocktimestamp,bits256 privkey,uint32_t timestamp) +{ + int32_t i,len,numbits; HUFF TX; + memset(Ptx->data,0,sizeof(Ptx->data)); + memset(&TX,0,sizeof(TX)), _init_HUFF(&TX,sizeof(Ptx->data),Ptx->data); + if ( Ptx->timestamp == 0 ) + Ptx->timestamp = timestamp; + else if ( timestamp != 0 && serdes777_checktimestamp(blocktimestamp,timestamp) < 0 ) + { + printf("serdes777_serialize: timestamp.%u too different from Ptx %u %d\n",timestamp,Ptx->timestamp,timestamp - Ptx->timestamp); + return(-1); + } + if ( (numbits= serdes777_rwtx(1,Ptx,&TX)) < 0 ) + return(-1); + //printf("TX.bitoffset.%d\n",TX.bitoffset); + len = (int32_t)hconv_bitlen(TX.bitoffset); + Ptx->datalen = len; + hseek(&TX,0,SEEK_SET); + if ( serdes777_rw(1,&Ptx->datalen,-(int32_t)sizeof(Ptx->datalen),&TX) < 0 ) + return(-1); + //for (i=0; idata[i]); + //printf(" crc.%08x datalen.%d\n",_crc32(0,Ptx->data,len),len); + for (i=0; isigs)/sizeof(*Ptx->sigs); i++) + { + //printf("scan sig.%d\n",i); + if ( Ptx->sigs[i].sigbits.txid == 0 ) + break; + if ( PAX_validate(&Ptx->sigs[i],Ptx->timestamp,Ptx->data,len) != Ptx->sigs[i].signer64bits ) + { + printf("Tx validation error at sig.%d\n",i); + return(-1); + } + memcpy(&Ptx->data[len],Ptx->sigs[i].sigbits.bytes,sizeof(Ptx->sigs[i].sigbits)), len += sizeof(Ptx->sigs[i].sigbits); + memcpy(&Ptx->data[len],Ptx->sigs[i].pubkey.bytes,sizeof(Ptx->sigs[i].pubkey)), len += sizeof(Ptx->sigs[i].pubkey); + } + if ( i < sizeof(Ptx->sigs)/sizeof(*Ptx->sigs)-1 && Ptx->timestamp != 0 && privkey.txid != 0 ) + { + Ptx->sigs[i].signer64bits = PAX_signtx(&Ptx->sigs[i],privkey,Ptx->timestamp,Ptx->data,len); + printf("len.%d sign sig.%d %llx %llu t%u\n",len,i,(long long)Ptx->sigs[i].sigbits.txid,(long long)Ptx->sigs[i].signer64bits,Ptx->timestamp); + memcpy(&Ptx->data[len],Ptx->sigs[i].sigbits.bytes,sizeof(Ptx->sigs[i].sigbits)), len += sizeof(Ptx->sigs[i].sigbits); + memcpy(&Ptx->data[len],Ptx->sigs[i].pubkey.bytes,sizeof(Ptx->sigs[i].pubkey)), len += sizeof(Ptx->sigs[i].pubkey); + if ( Ptx->sigs[i].signer64bits != PAX_validate(&Ptx->sigs[i],Ptx->timestamp,Ptx->data,Ptx->datalen) ) + { + printf("Tx validation error at sig.%d\n",i); + //return(-1); + } + printf("len.%d verify.%d t%u %llx %llu\n",len,i,Ptx->timestamp,(long long)Ptx->sigs[i].sigbits.txid,(long long)Ptx->sigs[i].signer64bits); + } //else printf("skip signing t%u %llu\n",timestamp,(long long)privkey.txid); + return(len); +} + +int32_t accts777_parse(union peggy_addr *addr,cJSON *item,int32_t type) +{ + int32_t peggy_setname(char *buf,char *name); + char name[16],*coinaddr,*hashstr; struct peggy_lock *lock; + if ( item == 0 ) + return(-1); + switch ( type ) + { + case PEGGY_ADDRBTCD: + if ( (coinaddr= jstr(item,"BTCD")) != 0 && peggy_addr2univ(&addr->coinaddr,coinaddr,"BTCD") < 0 ) + { + printf("illegal coinaddr.(%s)\n",coinaddr); + return(-1); + } + break; + case PEGGY_ADDRCREATE: + if ( (hashstr= jstr(item,"lockhash")) != 0 && strlen(hashstr) == 64 ) + decode_hex(addr->newunit.sha256.bytes,sizeof(bits256),hashstr); + lock = &addr->newunit.newlock; + lock->peg = peggy_setname(name,jstr(item,"peg")); + lock->denom = jint(item,"denom"); + lock->minlockdays = jint(item,"minlockdays"); + lock->maxlockdays = jint(item,"maxlockdays"); + lock->clonesmear = jint(item,"clonesmear"); + lock->mixrange = jint(item,"mixrange"); + lock->margin = jint(item,"margin"); + break; + case PEGGY_ADDRNXT: + addr->nxt64bits = j64bits(item,"NXT"); + break; + case PEGGY_ADDRUNIT: + if ( (hashstr= jstr(item,"unithash")) != 0 && strlen(hashstr) == 64 ) + decode_hex(addr->sha256.bytes,sizeof(bits256),hashstr); + break; + case PEGGY_ADDR777: + if ( (hashstr= jstr(item,"SaMbits")) != 0 && strlen(hashstr) == 96 ) + decode_hex(addr->SaMbits.bytes,sizeof(bits384),hashstr); + break; + case PEGGY_ADDRPUBKEY: + if ( (hashstr= jstr(item,"unlockpubkey")) != 0 && strlen(hashstr) == 64 ) + decode_hex(addr->newunit.sha256.bytes,sizeof(bits256),hashstr); + lock = &addr->newunit.newlock; + lock->peg = peggy_setname(name,jstr(item,"peg")); + lock->minlockdays = lock->maxlockdays = jint(item,"lockdays"); + if ( jint(item,"denom") < 0 ) + lock->peg = -lock->peg; + break; + } + return(0); +} + +int32_t peggy_inputs(struct peggy_tx *Ptx,cJSON *array) +{ + int32_t i,n = 0; cJSON *item; + if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; iinputs[i].type = juint(item,"type"); + Ptx->inputs[i].chainlen = juint(item,"chainlen"); + Ptx->inputs[i].amount = juint(item,"amount"); + accts777_parse(&Ptx->inputs[i].src,item,Ptx->inputs[i].type); + } + } + return(n); +} + +int32_t peggy_outputs(struct peggy_tx *Ptx,cJSON *array) +{ + int32_t i,n=0; cJSON *item; + if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ioutputs[i].type = juint(item,"type"); + Ptx->outputs[i].vin = juint(item,"vin"); + Ptx->outputs[i].ratio = juint(item,"ratio"); + accts777_parse(&Ptx->outputs[i].dest,item,Ptx->outputs[i].type); + } + } + return(n); +} + +int32_t peggy_details(struct peggy_tx *Ptx,cJSON *json,int32_t txtype,uint32_t btcusd) +{ + struct destbuf name; + int32_t i,n=0; cJSON *item,*array; char *hashstr,*refundstr; struct peggy_txtune *tune; struct peggy_txmicropay *mp; struct peggy_txbet *bet; + Ptx->details.price.timestamp = juint(json,"genesistime"); + Ptx->details.price.maxlockdays = juint(json,"maxlockdays"); + //printf("BTCUSD.%d vs %d\n",Ptx->details.prices.btcusd,btcusd); + if ( (array= jarray(&n,json,"details")) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + if ( txtype == PEGGY_TXPRICES ) + Ptx->details.price.num = n; + for (i=0; idetails.bets[i]; + copy_cJSON(&name,jobj(item,"peg")); + safecopy(bet->peg,name.buf,sizeof(bet->peg)); + bet->binary = juint(item,"binary"); + bet->prediction.Pval = juint(item,"prediction"); + break; + case PEGGY_TXPRICES: + Ptx->details.price.feed[i] = juint(item,0); + break; + case PEGGY_TXTUNE: + tune = &Ptx->details.tune[i]; + copy_cJSON(&name,jobj(item,"peg")); + safecopy(tune->peg,name.buf,sizeof(bet->peg)); + tune->type = juint(item,"type"); + tune->val = j64bits(item,"val"); + tune->B.val = j64bits(item,"valB"); + tune->B.bytes[0] = j64bits(item,"interesttenths"); + tune->B.bytes[1] = j64bits(item,"posboost"); + tune->B.bytes[2] = j64bits(item,"negpenalty"); + tune->B.bytes[3] = j64bits(item,"feediv"); + tune->B.bytes[4] = j64bits(item,"feemult"); + break; + case PEGGY_TXMICROPAY: + mp = &Ptx->details.micropays[i]; + if ( (hashstr= jstr(item,"claimhash")) != 0 && strlen(hashstr) == 64 ) + decode_hex(mp->claimhash.bytes,sizeof(bits256),hashstr); + if ( (refundstr= jstr(item,"refundhash")) != 0 && strlen(refundstr) == 64 ) + decode_hex(mp->refundhash.bytes,sizeof(bits256),refundstr); + mp->expiration = juint(item,"expiration"); + mp->chainlen = juint(item,"chainlen"); + mp->vin = juint(item,"vin"); + mp->vout = juint(item,"vout"); + break; + } + } + } + return(0); +} + +char *peggy_tx(char *jsonstr) +{ + cJSON *json; int32_t i,n,len,signedcount; char *hexstr,opreturnstr[8192],retbuf[4096],retbufstr[8192],checkstr[8192]; + struct peggy_tx Ptx,checkPtx; bits256 privkey; struct destbuf tmp; + memset(&Ptx,0,sizeof(Ptx)); + opreturnstr[0] = 0; + memset(privkey.bytes,0,sizeof(privkey)); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + printf("(%s)\n",jsonstr); + Ptx.flags = juint(json,"flags"); + Ptx.txtype = juint(json,"txtype"); + Ptx.numinputs = peggy_inputs(&Ptx,jarray(&n,json,"inputs")); + Ptx.numoutputs = peggy_outputs(&Ptx,jarray(&n,json,"outputs")); + if ( Ptx.txtype != PEGGY_TXNORMAL ) + Ptx.numdetails = peggy_details(&Ptx,json,Ptx.txtype,juint(json,"btcusd")); + if ( (hexstr= jstr(json,"privkey")) != 0 && strlen(hexstr) == 64 ) + decode_hex(privkey.bytes,sizeof(privkey),hexstr); + //else printf("no privkey.%p (%s)\n",hexstr,jsonstr); + if ( (hexstr= jstr(json,"hexstr")) != 0 && strlen(hexstr) < sizeof(Ptx.hexstr) ) + strcpy(Ptx.hexstr,hexstr), Ptx.msglen = (int32_t)strlen(hexstr)/2; + Ptx.activation = juint(json,"activation"); + Ptx.expiration = juint(json,"expiration"); + if ( (Ptx.funding.amount= juint(json,"funds")) != 0 ) + { + copy_cJSON(&tmp,jobj(json,"fundsaddr")); + //safecopy(Ptx.funding.src.coinaddr,tmp.buf,sizeof(Ptx.funding.src.coinaddr)); + if ( peggy_addr2univ(&Ptx.funding.src.coinaddr,tmp.buf,"BTCD") < 0 ) + { + printf("warning: illegal funding address.(%s)\n",tmp.buf); + } + Ptx.flags |= PEGGY_FLAGS_HASFUNDING; + Ptx.funding.type = PEGGY_ADDRFUNDING; + } + Ptx.timestamp = (uint32_t)time(NULL); + len = serdes777_serialize(&Ptx,Ptx.timestamp,privkey,Ptx.timestamp); + init_hexbytes_noT(opreturnstr,Ptx.data,len); + //printf("datalen.%d (%s).%ld\n",Ptx.datalen,opreturnstr,strlen(opreturnstr)); + /*if ( PEGS != 0 && peggy_txind(&tipvalue,PEGS->accts,0,Ptx.timestamp,0,&Ptx,fundsvalue,fundsaddr) < 0 ) + { + printf("%s\nerror validating tx\n",opreturnstr); + //return(clonestr("\"error\":\"error validating tx\"}")); + }*/ + len = serdes777_deserialize(&signedcount,&checkPtx,Ptx.timestamp,Ptx.data,len); + retbuf[0] = OP_RETURN_OPCODE; + if ( len+3 < 0xfe ) + { + retbuf[1] = len+3; + strcpy(retbuf+2,"PAX"); + memcpy(retbuf+5,Ptx.data,len); + init_hexbytes_noT(retbufstr,(void *)retbuf,len+5); + } + else + { + retbuf[1] = 0xfe; + retbuf[2] = (len+3) & 0xff; + retbuf[3] = ((len+3) >> 8) & 0xff; + strcpy(retbuf+4,"PAX"); + memcpy(retbuf+7,Ptx.data,len); + init_hexbytes_noT(retbufstr,(void *)retbuf,len+7); + } + init_hexbytes_noT(checkstr,checkPtx.data,len); + if ( strcmp(checkstr,opreturnstr) != 0 ) + { + for (i=0; inum * sizeof(price->feed[0]); + if ( stakedblock != 0 || nxt64bits != 0 ) + { + for (i=0; inum; i++) + len = txind777_txbuf(txbuf,len,price->feed[i],sizeof(price->feed[i]));//, fprintf(stderr,"%d ",price->feed[i]); + key[0] = blocknum, key[1] = 0; + ramkv777_write(accts->pricefeeds,key,price->feed,size); + return(len); + } else printf("unsigned pricefeed not staked blocknum.%d t%u\n",blocknum,blocktimestamp); + // add to daily list for eval in daily settlement + return(-1); +} + +int32_t peggy_create_bet(uint8_t *txbuf,struct accts777_info *accts,uint32_t blocknum,uint32_t blocktimestamp,uint64_t nxt64bits,uint64_t value,char *coinaddr,struct peggy_txbet *bet) +{ + uint64_t key[2]; + key[0] = blocktimestamp, key[1] = nxt64bits; + // add to daily list for eval in daily settlement + return(0); +} + +int32_t peggy_enable(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->name.enabled = (int32_t)val; + return(0); +} + +int32_t peggy_dailyrate(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->maxdailyrate = (int32_t)val; + return(0); +} + +int32_t peggy_quorum(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->pool.quorum = val; + return(0); +} + +int32_t peggy_decisionthreshold(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->pool.decisionthreshold = val; + return(0); +} + +int32_t peggy_maxnetbalance(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->maxnetbalance = val; + return(0); +} + +int32_t peggy_maxsupply(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->maxsupply = val; + return(0); +} + +/*int32_t peggy_numtimeframes(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) + { + PEG->limits.numtimeframes = (int32_t)val; + return(0); + } + + int32_t peggy_timeframe(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) + { + if ( val < PEG->limits.numtimeframes ) + PEG->limits.timeframes[val] = (int32_t)valB; + return(0); + } + + int32_t peggy_timescale(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) + { + if ( val < PEG->limits.numtimeframes ) + PEG->limits.scales[val] = valB; + return(0); + }*/ + +int32_t peggy_lockdays(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->lockparms.minlockdays = val, PEG->lockparms.maxlockdays = valB; + return(0); +} + +int32_t peggy_clonesmear(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->lockparms.clonesmear = val; + return(0); +} + +int32_t peggy_mixrange(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->lockparms.mixrange = val; + return(0); +} + +int32_t peggy_redemptiongap(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->lockparms.redemptiongapdays = val; + return(0); +} + +int32_t peggy_extralockdays(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->lockparms.extralockdays = val; + return(0); +} + +int32_t peggy_maxmargin(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->lockparms.margin = val; + return(0); +} + +int32_t peggy_mindenomination(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->mindenomination.Pval = val; + return(0); +} + +int32_t peggy_spread(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) +{ + PEG->spread.Pval = val; + return(0); +} + +int32_t peggy_fees(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint8_t interesttenths,uint8_t posboost,uint8_t negpenalty,uint8_t feediv,uint8_t feemult) +{ + PEGS->interesttenths = interesttenths, PEGS->posboost = posboost, PEGS->negpenalty = negpenalty, PEGS->feediv = feediv, PEGS->feemult = feemult; + return(0); +} + +int32_t (*tunefuncs[])(struct peggy_info *PEGS,struct peggy *PEG,uint32_t blocktimestamp,int32_t actionflag,uint64_t val,uint64_t valB) = +{ + peggy_enable, peggy_dailyrate, peggy_quorum, peggy_decisionthreshold, peggy_maxnetbalance, peggy_maxsupply, peggy_lockdays, peggy_clonesmear, peggy_mixrange, peggy_redemptiongap, peggy_extralockdays, peggy_maxmargin, peggy_mindenomination, peggy_spread +}; + +uint64_t peggy_onesigner(struct peggy_tx *Ptx) +{ + if ( Ptx->sigs[0].signer64bits != 0 && Ptx->sigs[1].signer64bits == 0 ) + return(Ptx->sigs[0].signer64bits); + else return(0); +} + +int32_t peggy_twosigners(uint64_t signers[2],struct peggy_tx *Ptx) +{ + if ( Ptx->sigs[0].signer64bits != 0 && Ptx->sigs[1].signer64bits != 0 && Ptx->sigs[2].signer64bits == 0 ) + { + signers[0] = Ptx->sigs[0].signer64bits; + signers[1] = Ptx->sigs[1].signer64bits; + return(2); + } + else return(-1); +} + +int64_t peggy_txind_tune(struct peggy_info *PEGS,uint32_t blocknum,uint32_t blocktimestamp,int32_t actionflag,struct peggy_tx *Ptx,struct peggy_txtune *tune,int32_t numtunes) +{ + static char *accts[] = { "NXT-SQ9J-JCAN-8XVY-5XN7K", "NXT-J698-WN8Q-XR8A-92TLD", "NXT-JNES-HJ86-KNXQ-AQ33Z", "NXT-RQYG-UPJP-HMMH-7WHFZ" }; + char name[16]; int32_t i,peg,flag = 0; uint64_t nxt64bits; struct peggy *PEG; int64_t txind=0,txinds[256]; + if ( Ptx->numoutputs != 0 || Ptx->numinputs != 0 || (nxt64bits= peggy_onesigner(Ptx)) == 0 ) + return(-1); + for (i=0; i 0 ) + { + for (i=0; i= PEGS->numpegs ) + return(-1); + if ( actionflag <= 0 ) + continue; + PEG = PEGS->contracts[peg]; + if ( tune[i].type == 77 && peggy_fees(PEGS,PEG,blocktimestamp,actionflag,tune[i].B.bytes[0],tune[i].B.bytes[1],tune[i].B.bytes[2],tune[i].B.bytes[3],tune[i].B.bytes[4]) < 0 ) + return(-1); + else if ( tune[i].type >= sizeof(tunefuncs)/sizeof(*tunefuncs) ) + return(-1); + else if ( (*tunefuncs[i])(PEGS,PEG,blocktimestamp,actionflag,tune->val,tune->B.val) < 0 ) + return(-1); + txinds[i] = txind777_create(PEGS->accts->txinds,blocknum,blocktimestamp,&tune[i],sizeof(tune[i])); + } + txind = txind777_bundle(PEGS->accts->txinds,blocknum,blocktimestamp,txinds,numtunes); + } + return(txind); +} + +int64_t peggy_txind_micropay(uint8_t *txbuf,int32_t len,struct accts777_info *accts,uint32_t blocknum,uint32_t blocktimestamp,int32_t actionflag,struct peggy_tx *Ptx,struct peggy_txmicropay *micropays,int32_t num) +{ + uint64_t nxt64bits,both[2]; + if ( (nxt64bits= peggy_onesigner(Ptx)) != 0 ) + { + if ( Ptx->numoutputs != 1 || Ptx->numinputs != 1 || micropays[0].vin != 0 || micropays[0].vout != 0 || num != 1 ) + return(-1); + if ( actionflag != 0 && (len= peggy_create_micropay(txbuf,len,accts,blocknum,blocktimestamp,nxt64bits,micropays,Ptx->inputs,Ptx->outputs)) < 0 ) + return(-1); + } + else if ( peggy_twosigners(both,Ptx) > 0 ) + { + if ( Ptx->numoutputs != 2 || Ptx->numinputs != 2 || num != 2 ) + return(-1); + if ( micropays[0].vin != 0 || micropays[0].vout != 0 || micropays[1].vin != 1 || micropays[1].vout != 1 ) + return(-1); + if ( actionflag != 0 ) + { + if ( (len= peggy_create_micropair(txbuf,len,accts,blocknum,blocktimestamp,both[0],µpays[0],&Ptx->inputs[0],&Ptx->outputs[0],both[1],µpays[1],&Ptx->inputs[1],&Ptx->outputs[1])) < 0 ) + return(-1); + } + } + if ( len > 0 ) + return(txind777_create(accts->txinds,blocknum,blocktimestamp,txbuf,len)); + return(-1); +} + +int64_t peggy_txind_prices(uint8_t *txbuf,int32_t len,struct accts777_info *accts,uint32_t blocknum,uint32_t blocktimestamp,int32_t actionflag,struct peggy_tx *Ptx,struct peggy_txprices *prices,uint32_t stakedblock) +{ + if ( Ptx->numoutputs != 0 || Ptx->numinputs != 0 ) + { + printf("peggy_txind_prices: unexpected numinputs.%d numoutputs.%d\n",Ptx->numoutputs,Ptx->numinputs); + return(-1); + } + if ( actionflag != 0 ) + { + if ( (len= peggy_create_prices(txbuf,len,accts,blocknum,blocktimestamp,stakedblock == 0 ? peggy_onesigner(Ptx) : 0,prices,stakedblock)) < 0 ) + return(-1); + // printf("len.%d txinds.%p\n",len,accts->txinds); + return(txind777_create(accts->txinds,blocknum,blocktimestamp,txbuf,len)); + } + return(-1); +} + +int32_t txind777_txbuf_lock(uint8_t *txbuf,int32_t len,struct peggy_lock *lock) +{ + if ( txbuf != 0 ) + { + len = txind777_txbuf(txbuf,len,lock->peg,sizeof(lock->peg)); + len = txind777_txbuf(txbuf,len,lock->denom,sizeof(lock->denom)); + len = txind777_txbuf(txbuf,len,lock->minlockdays,sizeof(lock->minlockdays)); + len = txind777_txbuf(txbuf,len,lock->maxlockdays,sizeof(lock->maxlockdays)); + len = txind777_txbuf(txbuf,len,lock->clonesmear,sizeof(lock->clonesmear)); + len = txind777_txbuf(txbuf,len,lock->redemptiongapdays,sizeof(lock->redemptiongapdays)); + len = txind777_txbuf(txbuf,len,lock->extralockdays,sizeof(lock->extralockdays)); + len = txind777_txbuf(txbuf,len,lock->margin,sizeof(lock->margin)); + } + return(len); +} + +int64_t peggy_txind_bets(uint8_t *txbuf,int32_t len,struct accts777_info *accts,uint32_t blocknum,uint32_t blocktimestamp,int32_t actionflag,struct peggy_tx *Ptx,uint64_t value,char *voutcoinaddr,struct peggy_txbet *bets,int32_t numbets) +{ + uint64_t nxt64bits; int32_t i; int64_t txind=0,txinds[256]; + if ( Ptx->numoutputs != 0 || Ptx->numinputs != 0 || (nxt64bits= peggy_onesigner(Ptx)) == 0 ) + return(-1); + if ( actionflag != 0 ) + { + for (i=0; itxinds,blocknum,blocktimestamp,txbuf,len); + } + txind = txind777_bundle(accts->txinds,blocknum,blocktimestamp,txinds,numbets); + } + return(0); +} + +int32_t peggy_univ2addr(char *coinaddr,struct peggy_univaddr *ua) +{ + return(btc_convrmd160(coinaddr,ua->addrtype,ua->rmd160)); +} + +int32_t peggy_addr2univ(struct peggy_univaddr *ua,char *coinaddr,char *coin) +{ + char hexstr[512]; uint8_t hex[21]; + if ( btc_convaddr(hexstr,coinaddr) == 0 ) + { + decode_hex(hex,21,hexstr); + memset(ua,0,sizeof(*ua)); + ua->addrtype = hex[0]; + memcpy(ua->rmd160,hex+1,20); + strncpy(ua->coin,coin,sizeof(ua->coin)-1); + return(0); + } + return(-1); +} + +int64_t peggy_txind_send(uint8_t *txbuf,int32_t len,struct peggy_info *PEGS,uint32_t blocknum,uint32_t blocktimestamp,uint64_t signer64bits,uint64_t signer64bitsB,int64_t fundedvalue,struct peggy_input *in,uint32_t ratio,struct peggy_output *out) +{ + struct acct777 *acct; struct ramkv777 *kv; struct ramkv777_item *item; + int64_t value = 0; int32_t i,chainlen,polarity,peg; uint32_t rawind; uint64_t satoshis,amount=0,marginamount = 0; + struct peggy_unit readU; struct accts777_info *accts; struct peggy_time T; union peggy_addr *addr = &out->dest; + if ( (accts= PEGS->accts) == 0 ) + return(-1); + acct = accts777_find(0,accts,addr,out->type); + if ( acct == 0 ) + acct = accts777_create(accts,addr,out->type,blocknum,blocktimestamp); + if ( acct == 0 ) + return(-1); + T.blocknum = blocknum, T.blocktimestamp = blocktimestamp; + if ( in == 0 && fundedvalue != 0 ) + value = fundedvalue; + else if ( in != 0 ) + { + if ( (in->type == PEGGY_ADDRNXT || in->type == PEGGY_ADDR777) && acct777_balance(accts,blocknum,blocktimestamp,&in->src,in->type) >= in->amount ) + value = in->amount; + else if ( in->type == PEGGY_ADDRPUBKEY ) + { + if ( in->src.newunit.newlock.minlockdays != 0 ) + { + if ( ratio != PRICE_RESOLUTION ) + return(-1); + chainlen = 1; + if ( (peg= in->src.newunit.newlock.peg) < 0 ) + peg = -peg, polarity = -1; + else polarity = 1; + value = peggy_redeem(PEGS,T,amount == 0,PEGS->contracts[peg]->name.name,polarity,signer64bits,in->src.sha256,in->src.newunit.newlock.minlockdays,chainlen); + } + else if ( acct777_balance(accts,blocknum,blocktimestamp,&in->src,in->type) >= in->amount ) + value = in->amount; + } + else if ( in->type == PEGGY_ADDRUNIT ) + { + if ( ratio != PRICE_RESOLUTION || (out->type != PEGGY_ADDRCREATE && out->type != PEGGY_ADDRUNIT) ) // rollover or swap only + return(-1); + } else return(-1); + } + if ( (kv= accts777_getaddrkv(accts,out->type)) != 0 && (item= ramkv777_itemptr(kv,acct)) != 0 ) + rawind = item->rawind; + else rawind = 0; + len = txind777_txbuf(txbuf,len,rawind,sizeof(uint32_t)); + if ( out->type == PEGGY_ADDRBTCD ) + { + char coinaddr[64]; + if ( peggy_univ2addr(coinaddr,&addr->coinaddr) < 0 || acct == 0 || opreturns_queue_payment(&accts->PaymentsQ,blocktimestamp,coinaddr,value) < 0 ) + return(-1); + } + else if ( out->type == PEGGY_ADDRCREATE ) + { + if ( value > 0 ) + { + if ( addr->newunit.newlock.margin == 0 ) + amount = value; + else marginamount = value; + satoshis = peggy_createunit(PEGS,T,0,accts->peggyhash.txid,0,signer64bits,addr->newunit.sha256,&addr->newunit.newlock,amount,marginamount); + len = txind777_txbuf_lock(txbuf,len,&addr->newunit.newlock); + if ( in != 0 && in->type == PEGGY_ADDRUNIT ) + { + for (i=0; isrc.sha256.bytes[i]; + if ( peggy_swap(accts,signer64bits,signer64bitsB,in->src.sha256,addr->newunit.sha256) < 0 ) + return(-1); + } + } else return((int32_t)peggy_createunit(PEGS,T,&readU,accts->peggyhash.txid,0,signer64bits,addr->newunit.sha256,&addr->newunit.newlock,amount,marginamount)); + } + else if ( acct != 0 ) + { + if ( in != 0 && in->type == PEGGY_ADDRUNIT ) + { + for (i=0; isrc.sha256.bytes[i]; + if ( peggy_swap(accts,signer64bits,signer64bitsB,in->src.sha256,addr->sha256) < 0 ) + return(-1); + } + else if ( acct777_pay(accts,0,acct,value,blocknum,blocktimestamp) < 0 ) + return(-1); + } + return(txind777_create(accts->txinds,blocknum,blocktimestamp,txbuf,len)); +} + +int32_t peggy_checktx(struct price_resolution vinsums[PEGGY_MAXINPUTS],struct accts777_info *accts,int32_t actionflag,struct peggy_tx *Ptx,uint32_t blocknum,uint32_t blocktimestamp) +{ + int32_t i; + if ( Ptx->numoutputs == 0 && Ptx->numinputs == 0 ) + return(0); + else if ( Ptx->numoutputs != 0 && Ptx->numinputs == 0 ) + return(-1); + memset(vinsums,0,sizeof(*vinsums) * PEGGY_MAXINPUTS); + if ( Ptx->numoutputs > 0 ) + { + for (i=0; inumoutputs; i++) + { + if ( Ptx->outputs[i].vin < 0 || Ptx->outputs[i].vin >= Ptx->numinputs || Ptx->outputs[i].ratio > PRICE_RESOLUTION ) + return(-1); + vinsums[Ptx->outputs[i].vin].Pval += Ptx->outputs[i].ratio; + //if ( acct777_balance(&PEGS->accts,blocktimestamp,&Ptx->outputs[i].dest,Ptx->outputs[i].type) < 0 ) + // return(-1); + } + } + for (i=0; inuminputs; i++) + if ( vinsums[i].Pval != PRICE_RESOLUTION ) + { + printf("mismatched vinsum[%d] %.6f\n",i,Pval(&vinsums[i])); + return(-1); + } + if ( Ptx->numinputs > 0 ) + { + for (i=0; inuminputs; i++) + { + if ( acct777_balance(accts,blocknum,blocktimestamp,&Ptx->inputs[i].src,Ptx->inputs[i].type) < 0 ) + return(-1); + } + } + return(0); +} + +int64_t peggy_txind(int64_t *tipvaluep,struct peggy_info *PEGS,uint32_t blocknum,uint32_t blocktimestamp,int32_t actionflag,struct peggy_tx *Ptx,int32_t stakedblock) +{ + int32_t i,len = 0; uint64_t signer64bits,both[2]; int64_t txind=0,txinds[PEGGY_MAXOUTPUTS*2]; uint8_t txbuf[65536]; + struct price_resolution vinsums[PEGGY_MAXINPUTS]; struct accts777_info *accts; + if ( (accts= PEGS->accts) == 0 ) + { + printf("no PEGS->accts\n"); + return(-1); + } + if ( actionflag < 0 ) + { + printf("undo not supported, rewind and redo\n"); + return(-1); + } + txbuf[len++] = Ptx->txtype, txbuf[len++] = Ptx->txtype, txbuf[len++] = Ptx->numinputs, txbuf[len++] = Ptx->numoutputs; + len = txind777_txbuf(txbuf,len,blocknum,sizeof(blocknum)); + len = txind777_txbuf(txbuf,len,blocktimestamp,sizeof(blocktimestamp)); + if ( Ptx->txtype == PEGGY_TXNORMAL ) + { + if ( (signer64bits= peggy_onesigner(Ptx)) != 0 ) + { + txbuf[len++] = 1; + len = txind777_txbuf(txbuf,len,signer64bits,sizeof(signer64bits)); + printf("peggy_onesigner\n"); + if ( Ptx->numinputs == 0 ) + { + if ( Ptx->numoutputs == 1 ) + { + len = txind777_txbuf(txbuf,len,Ptx->funding.amount,sizeof(Ptx->funding.amount)); + memcpy(txbuf,&Ptx->funding.src.coinaddr,sizeof(Ptx->funding.src.coinaddr)), len += sizeof(Ptx->funding.src.coinaddr); + if ( (txind= peggy_txind_send(txbuf,len,PEGS,blocknum,blocktimestamp,signer64bits,0,actionflag*Ptx->funding.amount,0,PRICE_RESOLUTION,&Ptx->outputs[0])) > 0 ) + *tipvaluep = 0; + } + else return(-2); + } + else if ( Ptx->numinputs == 1 ) + { + if ( Ptx->numoutputs >= 1 ) + { + if ( peggy_checktx(vinsums,accts,actionflag,Ptx,blocknum,blocktimestamp) < 0 ) + return(-3); + if ( actionflag != 0 ) + { + for (i=0; inumoutputs; i++) + if ( (txinds[i] = peggy_txind_send(txbuf,len,PEGS,blocknum,blocktimestamp,signer64bits,0,0,Ptx->inputs,(uint32_t)vinsums[i].Pval,&Ptx->outputs[i])) < 0 ) + return(-1); + txind = txind777_bundle(accts->txinds,blocknum,blocktimestamp,txinds,Ptx->numoutputs); + } + return(txind); + } + } + else if ( Ptx->numoutputs == 1 ) + { + if ( Ptx->outputs[0].ratio == PRICE_RESOLUTION ) + { + if ( actionflag != 0 ) + { + for (i=0; inumoutputs; i++) + if ( (txinds[i]= peggy_txind_send(txbuf,len,PEGS,blocknum,blocktimestamp,signer64bits,0,0,&Ptx->inputs[i],Ptx->outputs[0].ratio,Ptx->outputs)) < 0 ) + return(-1); + txind = txind777_bundle(accts->txinds,blocknum,blocktimestamp,txinds,Ptx->numinputs); + } + return(txind); + } else printf("error non unit ratio\n"); + } + return(-1); + } + else if ( peggy_twosigners(both,Ptx) > 0 ) + { + txbuf[len++] = 2; + len = txind777_txbuf(txbuf,len,both[0],sizeof(both[0])); + len = txind777_txbuf(txbuf,len,both[1],sizeof(both[1])); + printf("peggy_twosigners\n"); + if ( Ptx->numoutputs != 1 || Ptx->numinputs != 1 || both[0] != Ptx->sigs[0].signer64bits || both[1] != Ptx->sigs[1].signer64bits ) + return(-1); + if ( actionflag != 0 ) + { + if ( (txind= peggy_txind_send(txbuf,len,PEGS,blocknum,blocktimestamp,both[0],both[1],0,&Ptx->inputs[0],PRICE_RESOLUTION,&Ptx->outputs[0])) < 0 ) + return(-1); + } + return(txind); + } else printf("neither one or two signers\n"); + return(-1); + } + else if ( Ptx->txtype == PEGGY_TXPRICES ) + return(peggy_txind_prices(txbuf,len,accts,blocknum,blocktimestamp,actionflag,Ptx,&Ptx->details.price,stakedblock)); + else + { + printf("details tx\n"); + if ( peggy_checktx(vinsums,accts,actionflag,Ptx,blocknum,blocktimestamp) < 0 ) + return(-1); + else if ( Ptx->txtype == PEGGY_TXBET ) + { + char coinaddr[64]; + len = txind777_txbuf(txbuf,len,Ptx->funding.amount,sizeof(Ptx->funding.amount)); + memcpy(txbuf,&Ptx->funding.src.coinaddr,sizeof(Ptx->funding.src.coinaddr)), len += sizeof(Ptx->funding.src.coinaddr); + //for (i=0; ifunding.src.coinaddr[i]; + if ( peggy_univ2addr(coinaddr,&Ptx->funding.src.coinaddr) < 0 ) + { + printf("illegal coinaddr\n"); + return(-1); + } + if ( (txind= peggy_txind_bets(txbuf,len,accts,blocknum,blocktimestamp,actionflag,Ptx,Ptx->funding.amount,coinaddr,Ptx->details.bets,Ptx->numdetails)) > 0 ) + *tipvaluep = 0; + } + else if ( Ptx->txtype == PEGGY_TXMICROPAY ) + return(peggy_txind_micropay(txbuf,len,accts,blocknum,blocktimestamp,actionflag,Ptx,Ptx->details.micropays,Ptx->numdetails)); + } + return(txind); +} + +int64_t peggy_process(void *_PEGS,int32_t flags,void *fca,uint64_t fundedvalue,uint8_t *data,int32_t datalen,uint32_t blocknum,uint32_t blocktimestamp,uint32_t stakedblock) +{ + struct peggy_tx Ptx; int32_t len,signedcount; int64_t txind = -1,tipvalue; struct peggy_info *PEGS = _PEGS; + tipvalue = fundedvalue; + if ( (len= serdes777_deserialize(&signedcount,&Ptx,blocktimestamp,data,datalen)) < 0 ) + { + printf("peggy_process peggy_deserialize error datalen.%d (%d %d %d)\n",datalen,stakedblock,blocknum,blocktimestamp); + txind = -1; + } + else if ( Ptx.expiration != 0 && Ptx.expiration < blocktimestamp ) + { + printf("peggy_process peggytx already expired at %u vs %u\n",Ptx.expiration,blocktimestamp); + txind = -1; + } + else if ( Ptx.txtype == PEGGY_TXTUNE ) + txind = peggy_txind_tune(PEGS,blocknum,blocktimestamp,flags,&Ptx,Ptx.details.tune,Ptx.numdetails); + else txind = peggy_txind(&tipvalue,PEGS,blocknum,blocktimestamp,flags,&Ptx,stakedblock); + if ( txind < 0 ) + tipvalue = fundedvalue; + if ( tipvalue != 0 ) + peggy_thanks_you(PEGS,tipvalue); + if ( stakedblock != 0 ) + { + uint64_t sums[PEGGY_MAXPRICEDPEGS]; struct price_resolution price,aveprice; struct peggy_time T; + uint32_t key[2],nonz[PEGGY_MAXPRICEDPEGS],i,j,block,numprices=0,n,*feed; double startmilli; + struct peggy_vote vote;//{ struct price_resolution price,tolerance; uint64_t nxt64bits,weight; }; + price.Pval = 0; + memset(sums,0,sizeof(sums)), memset(nonz,0,sizeof(nonz)); + if ( blocknum <= PEGGY_NUMCOEFFS ) + block = 1; + else block = blocknum - PEGGY_NUMCOEFFS + 1; + startmilli = OS_milliseconds(); + for (n=i=0; block<=blocknum&&iaccts->pricefeeds,key)) != 0 ) + { + numprices = (uint32_t)(len / sizeof(len)); + for (j=0; jcontracts[j]->name.baseid <= 8 ) + // den *= 5; + memset(&vote,0,sizeof(vote)); + vote.pval = feed[j], vote.tolerance = (uint32_t)(((uint64_t)3 * PEGS->default_spread.Pval * feed[j])/PRICE_RESOLUTION); + PEGS->votes[j][nonz[j]++] = vote; + sums[j] += feed[j]; + } + } + n++; + } + } + for (j=0; jcontracts[j]->peggymils); + if ( j > 0 ) + { + T.blocknum = PEGS->numopreturns-1, T.blocktimestamp = blocktimestamp; + price = peggy_priceconsensus(PEGS,T,PEGS->accts->pricefeeds->sha256.txid,j,PEGS->votes[j],nonz[j],0,0); + price = peggy_scaleprice(price,PEGS->contracts[j]->peggymils); + if ( Debuglevel > 2 ) + fprintf(stderr,"%d %10s.{%14.6f} %7.4f%%\n",T.blocknum,PEGS->contracts[j]->name.name,Pval(&price),(fabs(Pval(&price)/Pval(&aveprice))-1)*100); + } + } + if ( Debuglevel > 2 || blocktimestamp+600 > time(NULL) ) + printf("staked.%u n.%d i.%d blocknum.%d t%u | processed in %.3f microseconds | pricehash.%llx\n",stakedblock,n,i,blocknum,blocktimestamp,1000*(OS_milliseconds() - startmilli),(long long)PEGS->accts->pricefeeds->sha256.txid); + } + return(txind); +} + +int64_t peggy_covercost(int32_t *nump,int64_t *posinterests,int64_t *neginterests,struct peggy_info *PEGS,struct peggy *PEG,struct price_resolution price,struct price_resolution shortprice) +{ + int32_t i,id; struct peggy_entry entry; struct peggy_unit *U; int64_t satoshis,covercost = 0; + id = PEG->name.id; + *posinterests = *neginterests = *nump = 0; + for (i=0; iaccts->numunits; i++) + { + U = &PEGS->accts->units[i]; + if ( (U->lock.peg == id || U->lock.peg == -id) && (PEG= peggy_findpeg(&entry,PEGS,U->lock.peg)) != 0 ) + { + if ( U->estimated_interest > 0 ) + (*posinterests) += U->estimated_interest, (*nump)++; + else if ( U->estimated_interest < 0 ) + (*neginterests) += U->estimated_interest, (*nump)++; + if ( entry.polarity < 0 && U->lock.peg == -id ) + { + satoshis = peggy_poolmainunits(&entry,-1,entry.polarity,price,shortprice,PEG->spread,PEG->pool.mainunitsize,U->lock.denom); + covercost += satoshis; + //printf("covercost price %.6f shortprice %.6f (%.8f - costbasis %.8f) %.8f -> %.8f price %.6f -> %.6f change %.8f est %.8f\n",Pval(&price),Pval(&shortprice),dstr(satoshis),dstr(U->costbasis),dstr(satoshis)-dstr(U->costbasis),dstr(covercost),dstr(U->costbasis)/Pval(&U->denomination),Pval(&shortprice),Pval(&shortprice)/(dstr(U->costbasis)/Pval(&U->denomination)),Pval(&price)*Pval(&price)*Pval(&U->denomination)*(Pval(&shortprice)/(dstr(U->costbasis)/Pval(&U->denomination)))); + } + } + } + return(covercost); +} + +double peggy_status(char **jsonstrp,struct peggy_info *PEGS,double *rates,uint32_t timestamp,char *name) +{ + int32_t j,rate,num,count,opporate,datenum,seconds,n = 0; struct price_resolution liability,liabilities,price,shortprice; + int64_t pos,neg,possum,negsum,netbalance; struct tai t; + double aprsum,depositsum,covercost,covercosts; struct peggy_entry entry; char numstr[64]; + struct peggy *PEG; cJSON *item,*array,*json = cJSON_CreateObject(); + array = cJSON_CreateArray(); + rates[0] = rates[1] = 0; + for (pos=possum=neg=negsum=liabilities.Pval=liability.Pval=covercost=covercosts=depositsum=aprsum=count=0,j=1; jnumpegs; j++) + { + item = cJSON_CreateObject(); + if ( (PEG= PEGS->contracts[j]) == 0 ) + continue; + if ( (name != 0 && strcmp(PEG->name.name,name) != 0) || (PEG= peggy_find(&entry,PEGS,PEG->name.name,1)) == 0 ) + continue; + rate = peggy_aprpercs(peggy_lockrate(&entry,PEGS,PEG,1,1)); + if ( (PEG= peggy_find(&entry,PEGS,PEG->name.name,-1)) == 0 ) + continue; + opporate = peggy_aprpercs(peggy_lockrate(&entry,PEGS,PEG,1,1)); + rates[j*2] = (double)rate / 100.; + rates[j*2+1] = (double)opporate / 100.; + if ( rate != 0 ) + n++; + if ( opporate != 0 ) + n++; + aprsum += (rate + opporate); + price = peggy_price(PEG,(timestamp - PEG->genesistime) / PEGGY_MINUTE); + shortprice = peggy_shortprice(PEG,PEG->price); + liability.Pval = (PEG->pool.liability.num * price.Pval); + liabilities.Pval += liability.Pval; + covercost = peggy_covercost(&num,&pos,&neg,PEGS,PEG,price,shortprice); + covercosts += covercost, possum += pos, negsum += neg, count += num; + jaddstr(item,"base",PEG->name.name); + jaddnum(item,"maxsupply",dstr(PEG->maxsupply)); + jaddnum(item,"maxnetbalance",dstr(PEG->maxnetbalance)); + jaddnum(item,"numunits",num); + jaddnum(item,"pendinginterests",dstr(pos)); + jaddnum(item,"pendinginterest_fees",dstr(neg)); + + price = peggy_scaleprice(price,PEG->peggymils); + jaddnum(item,"price",Pval(&price)); + price = peggy_scaleprice(PEG->dayprice,PEG->peggymils); + jaddnum(item,"dayprice",Pval(&price)); + jaddnum(item,"longunits",PEG->pool.liability.num); + price = peggy_scaleprice(liability,PEG->peggymils); + jaddnum(item,"liability",Pval(&price)); + + jaddnum(item,"antiprice",Pval(&shortprice)); + jaddnum(item,"shortunits",PEG->pool.liability.numoppo); + jaddnum(item,"covercost",dstr(covercost)); + + jaddnum(item,"deposits",dstr(PEG->pool.funds.deposits)); + jaddnum(item,"margindeposits",dstr(PEG->pool.funds.margindeposits)); + jaddnum(item,"marginvalue",dstr(PEG->pool.funds.marginvalue)); + jaddnum(item,"basereserve",dstr(PEGS->basereserves[PEG->name.baseid].funds.deposits)); + + sprintf(numstr,"%.2f%%",(double)rate/100.), jaddstr(item,"buy",numstr); + sprintf(numstr,"%.2f%%",(double)opporate/100.), jaddstr(item,"sell",numstr); + jaddi(array,item); + depositsum += PEG->pool.funds.deposits; + } + jadd(json,"rates",array); + datenum = OS_conv_unixtime(&t,&seconds,PEGS->genesistime); + jaddnum(json,"start",(uint64_t)datenum*1000000 + (seconds/3600)*10000 + ((seconds%3600)/60)*100 + (seconds%60)); + datenum = OS_conv_unixtime(&t,&seconds,timestamp); + jaddnum(json,"timestamp",(uint64_t)datenum*1000000 + (seconds/3600)*10000 + ((seconds%3600)/60)*100 + (seconds%60)); + jaddnum(json,"default_interest",(dailyrates[PEGS->interesttenths])); + jaddnum(json,"posboost",PEGS->posboost); + jaddnum(json,"negpenalty",PEGS->negpenalty); + jaddnum(json,"numunits",PEGS->accts->numunits); + jaddnum(json,"sumunits",count); + jaddnum(json,"unitinterests",dstr(possum)); + jaddnum(json,"unitinterestfees",dstr(negsum)); + jaddnum(json,"netunitinterest",dstr(possum + negsum)); + jaddnum(json,"APR_reserves",dstr(PEGS->bank.APRfund_reserved)); + jaddnum(json,"APRfund",dstr(PEGS->bank.APRfund)); + jaddnum(json,"liabilities",Pval(&liabilities)); + jaddnum(json,"covercosts",dstr(covercosts)); + jaddnum(json,"depositsum",dstr(depositsum)); + jaddnum(json,"deposits",dstr(PEGS->bank.funds.deposits)); + jaddnum(json,"margindeposits",dstr(PEGS->bank.funds.margindeposits)); + jaddnum(json,"marginvalue",dstr(PEGS->bank.funds.marginvalue)); + jaddnum(json,"royalties",dstr(PEGS->bank.crypto777_royalty)); + jaddnum(json,"fees",dstr(PEGS->bank.privatebetfees)); + netbalance = (depositsum) + (PEGS->bank.funds.margindeposits) + (PEGS->bank.APRfund) - (PEGS->bank.APRfund_reserved) - SATOSHIDEN*(liabilities.Pval/PRICE_RESOLUTION) - (covercosts); + jaddnum(json,"cashbalance",dstr(netbalance)); + netbalance = (depositsum) + (PEGS->bank.funds.marginvalue) + (PEGS->bank.APRfund) - (PEGS->bank.APRfund_reserved) - SATOSHIDEN*(liabilities.Pval/PRICE_RESOLUTION) - (covercosts); + jaddnum(json,"netbalance",dstr(netbalance)); + if ( netbalance > PEGS->hwmbalance ) + PEGS->hwmbalance = netbalance; + if ( netbalance < PEGS->worstbalance ) + PEGS->worstbalance = netbalance; + if ( -(PEGS->hwmbalance - netbalance) < PEGS->maxdrawdown ) + PEGS->maxdrawdown = -(PEGS->hwmbalance - netbalance); + jaddnum(json,"hwmbalance",dstr(PEGS->hwmbalance)); + jaddnum(json,"maxdrawdown",dstr(PEGS->maxdrawdown)); + jaddnum(json,"worstbalance",dstr(PEGS->worstbalance)); + if ( jsonstrp != 0 ) + *jsonstrp = jprint(json,1); + if ( n != 0 ) + aprsum /= n; + return(aprsum/100.); +} + +char *peggyrates(uint32_t timestamp,char *name) +{ + char *jsonstr = 0; double rates[2 * PEGGY_MAXPEGS]; struct peggy_info *PEGS = opreturns_context("peggy",0); + if ( timestamp == 0 ) + timestamp = (uint32_t)time(NULL); + if ( PEGS != 0 ) + peggy_status(&jsonstr,PEGS,rates,timestamp,name); + return(jsonstr); +} + +void peggy_test() +{ + opreturns_init(0,(uint32_t)time(NULL),"PEGS"); + peggy_tx("{\"txtype\":0,\"outputs\":[{\"lockhash\":\"1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b\",\"type\":1,\"denom\":10,\"margin\":0,\"minlockdays\":7,\"maxlockdays\":20,\"peg\":\"USD\"}],\"privkey\":\"1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b\"}"); + getchar(); +} diff --git a/iguana/peggy_txind.c b/iguana/peggy_txind.c new file mode 100755 index 000000000..b05d307a8 --- /dev/null +++ b/iguana/peggy_txind.c @@ -0,0 +1,474 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "peggy.h" + +struct opreturn_protocol +{ + uint8_t id[3]; char name[16]; + int64_t (*process)(void *context,int32_t flags,void *fundedcoinaddr,uint64_t fundedvalue,uint8_t *data,int32_t datalen,uint32_t currentblocknum,uint32_t blocktimestamp,uint32_t isstaked); + int32_t (*emit)(void *context,uint8_t opreturndata[MAX_OPRETURNSIZE],struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp); + int32_t (*flush)(void *context,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp); + int32_t (*init)(struct txinds777_info *opreturns,uint32_t blocknum,uint32_t blocktimestamp,char *path,void *globals[OPRETURNS_CONTEXTS],int32_t lookbacks[OPRETURNS_CONTEXTS],int32_t max); + uint32_t (*clone)(char *path,void *dest,void *src); + uint32_t (*currentblock)(void *globals); + void *(*replay)(char *path,struct txinds777_info *opreturns,void *_PEGS,uint32_t blocknum,char *opreturnstr,uint8_t *data,int32_t datalen); + void *globals[OPRETURNS_CONTEXTS]; int32_t lookbacks[OPRETURNS_CONTEXTS],numcontexts; uint32_t pastblocknums[OPRETURNS_CONTEXTS]; + struct txinds777_info *opreturns; +} OPRETURN_PROTOCOLS[8] = { { { 'P', 'A', 'X' }, "peggy", peggy_process, peggy_emit, peggy_flush, peggy_init_contexts, peggy_clone, peggy_currentblock, peggy_replay } }; + +int32_t opreturns_init(uint32_t blocknum,uint32_t blocktimestamp,char *path) +{ + int32_t i; + for (i=0; iglobals[context]); + return(0); +} + +int32_t opreturns_process(int32_t flags,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp,struct opreturn_entry *list,int32_t num,uint8_t *peggyopreturn,int32_t peggylen) +{ + static uint32_t prevblocknum; struct opreturn_entry stakedblock; + int32_t i,iter,size,isstaked,lookback,numvalid = 0; uint64_t len; uint32_t pastblocknum; uint8_t buf[16384]; long offset = 1; + struct opreturn_protocol *protocol; struct opreturn_entry *opreturn = list; + if ( prevblocknum != 0 && currentblocknum != prevblocknum+1 ) + { + if ( currentblocknum > prevblocknum+1 ) + printf("skipped block? currentblocknum %u > %u prevblocknum\n",currentblocknum,prevblocknum); + else + { + for (i=0; iclone)("opreturns_PERM",protocol->globals[0],protocol->globals[1]); + while ( (blocknum= (*protocol->currentblock)(protocol->globals[0])) < currentblocknum ) + (*protocol->replay)("opreturns",protocol->opreturns,protocol->globals[0],blocknum,0,0,0); + } + } + } + prevblocknum = blocknum = currentblocknum; + for (i=0; inumcontexts; iter++) + { + lookback = protocol->lookbacks[iter]; + if ( blocknum > lookback ) + { + pastblocknum = blocknum - lookback; + while ( protocol->pastblocknums[iter] <= pastblocknum ) + { + txinds777_seek(protocol->opreturns,pastblocknum); + while ( (opreturn= txinds777_read(&size,buf,protocol->opreturns)) != 0 ) + { + if ( opreturn->blocknum != pastblocknum ) + break; + if ( opreturn->data[0] == OP_RETURN_OPCODE ) + { + offset = hdecode_varint(&len,opreturn->data,offset,sizeof(opreturn->data)); + if ( len == (opreturn->datalen + offset) && protocol->id[0] == opreturn->data[offset] && protocol->id[1] == opreturn->data[offset+1] && protocol->id[2] == opreturn->data[offset+2] ) + { + if ( (*protocol->process)(protocol->globals[1],flags,opreturn->vout.coinaddr,opreturn->vout.value,&opreturn->data[offset+3],(int32_t)len-3,pastblocknum,opreturn->timestamp,opreturn->isstaked) < 0 ) + { + printf("process_opreturns[%d]: protocol.%s rejects entry\n",i,protocol->name); + } + } + } + } + protocol->pastblocknums[iter] = pastblocknum++; + } + } + } + } + for (i=0; i<=num; i++) + { + isstaked = 0; + if ( i == 0 ) + { + if ( peggyopreturn != 0 ) + { + opreturn = &stakedblock; + memset(&stakedblock,0,sizeof(stakedblock)); + memcpy(stakedblock.data,peggyopreturn,peggylen); + stakedblock.datalen = peggylen; + isstaked = 1; + } else continue; + } + else opreturn = &list[i-1]; + opreturn->isstaked = isstaked; + if ( opreturn->data[0] == OP_RETURN_OPCODE ) + { + offset = hdecode_varint(&len,opreturn->data,offset,sizeof(opreturn->data)); + if ( (len + offset) == opreturn->datalen ) + { + if ( (protocol= opreturns_find(&opreturn->data[offset],0)) != 0 ) + { + txind777_create(OPRETURN_PROTOCOLS[i].opreturns,currentblocknum,blocktimestamp,opreturn,(int32_t)(sizeof(*opreturn)-sizeof(opreturn->data) + opreturn->datalen + 8)); + if ( (*protocol->process)(protocol->globals[0],flags,opreturn->vout.coinaddr,opreturn->vout.value,&opreturn->data[offset+3],(int32_t)len-3,currentblocknum,blocktimestamp,isstaked) < 0 ) + { + printf("process_opreturns[%d]: protocol.%s rejects entry\n",i,protocol->name); + } + numvalid++; + } + } else printf("process_opreturns[%d]: unexpected datalen.%d vs x.%llu at offset.%ld\n",i,opreturn->datalen,(long long)len,offset); + } else printf("process_opreturns[%d]: unexpected opcode.%d != OP_RETURN %d\n",i,opreturn->data[0],OP_RETURN_OPCODE); + } + return(numvalid); +} + +int32_t opreturns_emit(char *name,uint8_t opreturndata[MAX_OPRETURNSIZE],struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp) +{ + struct opreturn_protocol *protocol; + if ( (protocol= opreturns_find(0,name)) != 0 ) + { + if ( payments != 0 && max != 0 ) + memset(payments,0,sizeof(*payments) * max); + return((*protocol->emit)(protocol->globals[0],opreturndata,payments,max,currentblocknum,blocknum,blocktimestamp)); + } + printf("opreturns_emit: couldnt find opreturn protocol.(%s)\n",name); + return(-1); +} + +void opreturns_emitloop(char *protocols[],int32_t numprotocols,uint8_t opreturndata[MAX_OPRETURNSIZE],struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp) +{ + static int lastopreturni; + int32_t i,j,opreturnlen; + for (j=0; j 0 ) + { + lastopreturni = i; + opreturndata = 0; + } + while ( payments != 0 && max > 0 && payments[0].value != 0 ) + payments++, max--; + if ( max <= 0 ) + max = 0, payments = 0; + } +} + +int32_t opreturns_queue_payment(queue_t *PaymentsQ,uint32_t blocktimestamp,char *coinaddr,int64_t value) +{ + int32_t len = 0; struct opreturn_payment *item=0,*payment = calloc(1,sizeof(*payment)); + payment->value = value; + strcpy(payment->coinaddr,coinaddr); + if ( value < 0 ) + { + payment->value = -value; + if ( (item= queue_delete(PaymentsQ,&payment->DL,sizeof(*payment),1)) != 0 ) + free(item); + else printf("couldnt find queued payment %.8f -> %s t%u\n",dstr(value),coinaddr,blocktimestamp); + free(payment); + return(item == 0 ? -1 : 0); + } + else queue_enqueue("PaymentsQ",PaymentsQ,&payment->DL,0); + return(len); +} + +void txinds777_purge(struct txinds777_info *txinds) +{ + if ( txinds->fp != 0 ) + fclose(txinds->fp); + if ( txinds->txlogfp != 0 ) + fclose(txinds->txlogfp); + if ( txinds->indexfp != 0 ) + fclose(txinds->indexfp); + if ( txinds->blockitems != 0 ) + free(txinds->blockitems); + memset(txinds,0,sizeof(*txinds)); +} + +int64_t txinds777_seek(struct txinds777_info *txinds,uint32_t blocknum) +{ + if ( txinds->blockitems != 0 && blocknum >= txinds->H.firstblocknum && blocknum <= txinds->H.lastblocknum ) + txinds->curitem = txinds->blockitems[blocknum - txinds->H.firstblocknum]; + else txinds->curitem = 0; + return(txinds->curitem); +} + +void *txinds777_read(int32_t *lenp,uint8_t *buf,struct txinds777_info *txinds) +{ + int64_t txind,fpos; int32_t len; uint32_t triplet[3]; + *lenp = 0; + if ( txinds->indexfp == 0 || txinds->txlogfp == 0 ) + return(0); + fseek(txinds->indexfp,txinds->curitem * sizeof(int64_t),SEEK_SET); + if ( fread(&txind,1,sizeof(txind),txinds->indexfp) != sizeof(txind) ) + { + printf("error reading txindex.%lld file at pos %lld\n",(long long)txinds->curitem,(long long)(txinds->curitem * sizeof(txind))); + return(0); + } + len = txind & 0xffff; + fpos = (txind >> 16); + if ( fpos+len <= txinds->H.nextpos ) + { + printf("load %ld for item.%d log.%ld\n",ftell(txinds->indexfp),(int32_t)txinds->curitem,(long)fpos); + fseek(txinds->txlogfp,fpos,SEEK_SET); + if ( len >= sizeof(triplet) && fread(triplet,1,sizeof(triplet),txinds->txlogfp) == sizeof(triplet) && len > sizeof(triplet) ) + { + len -= sizeof(triplet); + if ( fread(buf,1,len,txinds->txlogfp) == len ) + { + *lenp = len; + return(buf); + } + } + } + return(0); +} + +void txinds777_ensure(struct txinds777_info *txinds,uint32_t blocknum,uint64_t curitem) +{ + int32_t offset,oldrange,newrange; + if ( txinds->blockitems == 0 ) + { + txinds->blockitems = realloc(txinds->blockitems,sizeof(*txinds->blockitems)); + txinds->H.firstblocknum = txinds->H.lastblocknum = blocknum; + } + else if ( blocknum > txinds->H.lastblocknum ) + { + oldrange = (txinds->H.lastblocknum - txinds->H.firstblocknum + 1); + newrange = (blocknum - txinds->H.firstblocknum + 1); + txinds->blockitems = realloc(txinds->blockitems,sizeof(*txinds->blockitems) * newrange); + if ( newrange > oldrange+1 ) + memset(&txinds->blockitems[oldrange],0,(newrange - oldrange)); + txinds->H.lastblocknum = blocknum; + } + offset = (blocknum - txinds->H.firstblocknum); + txinds->blockitems[offset] = curitem; +} + +int64_t txind777_create(struct txinds777_info *txinds,uint32_t blocknum,uint32_t timestamp,void *txdata,uint16_t len) +{ + int64_t txind = -1; uint32_t triplet[3]; + if ( txdata == 0 || txinds == 0 ) + return(0); + if ( len != 0 ) + { + txind = (txinds->H.nextpos << 16) | (len + sizeof(triplet)); + if ( txinds->txlogfp != 0 ) + { + triplet[0] = len, triplet[1] = blocknum, triplet[2] = timestamp; + //printf("triplet.(%d %d %d)\n",len,blocknum,timestamp); + fseek(txinds->txlogfp,txinds->H.nextpos,SEEK_SET); + if ( fwrite(triplet,1,sizeof(triplet),txinds->txlogfp) != sizeof(triplet) || fwrite(txdata,1,len,txinds->txlogfp) != len ) + { + printf("error updating txlog file at pos %lld\n",(long long)txinds->H.nextpos); + return(-1); + } + } + if ( txinds->indexfp != 0 ) + { + txinds777_ensure(txinds,blocknum,txinds->H.num); + fseek(txinds->indexfp,txinds->H.num * sizeof(txind),SEEK_SET); + if ( fwrite(&txind,1,sizeof(txind),txinds->indexfp) != sizeof(txind) ) + { + printf("error updating txindex file at pos %lld\n",(long long)(txinds->H.num * sizeof(txind))); + return(-1); + } + txinds->H.num++; + // printf("H.num %d: indexfp %ld\n",(int32_t)txinds->H.num,ftell(txinds->indexfp)); + } + vupdate_sha256(txinds->H.sha256.bytes,&txinds->H.state,txdata,len); + txinds->H.nextpos += len + sizeof(triplet); + //printf("H.num %d, nextpos %ld (len %ld) indexfp %ld logfp %ld\n",(int32_t)txinds->H.num,(long)txinds->H.nextpos,len + sizeof(triplet),ftell(txinds->indexfp),ftell(txinds->txlogfp)); + } else printf("cant txlog no data\n"); + return(txind); +} + +int64_t txind777_bundle(struct txinds777_info *txinds,uint32_t blocknum,uint32_t timestamp,int64_t *bundle,int32_t numtx) +{ + if ( bundle != 0 ) + return(txind777_create(txinds,blocknum,timestamp,bundle,numtx * sizeof(*txinds))); + else return(0); +} + +FILE *txinds777_initfile(long *fposp,char *path,char *name,char *suffix,uint64_t expected) +{ + FILE *fp; char fname[512]; long fpos = 0; + sprintf(fname,"%s/%s%s",path,name,suffix), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) + { + fseek(fp,0,SEEK_END); + if ( (fpos= ftell(fp)) != expected ) + { + printf("txinds777_init: warning mismatched position %ld vs %lld\n",fpos,(long long)expected); + fseek(fp,expected,SEEK_SET); + if ( (fpos= ftell(fp)) != expected ) + printf("txinds777_init: error mismatched position %ld vs %lld after set fpos\n",fpos,(long long)expected); + } + } + else fp = fopen(fname,"wb+"); + *fposp = fpos; + return(fp); +} + +struct txinds777_info *txinds777_init(char *path,char *name) +{ + FILE *fp; char fname[512]; int64_t txind,checktxind; long logfpos,indexfpos; struct txinds777_hdr H,goodH; uint32_t triplet[3]; + struct txinds777_info *txinds = calloc(1,sizeof(*txinds)); + strcpy(txinds->path,path), strcpy(txinds->name,name); + sprintf(fname,"%s/%s",path,name), OS_compatible_path(fname); + printf("txinds777_init(%s,%s)\n",path,name); + if ( (fp= fopen(fname,"rb+")) != 0 ) + { + if ( fread(&txinds->H,1,sizeof(txinds->H),fp) == sizeof(txinds->H) ) + { + txinds->txlogfp = txinds777_initfile(&logfpos,path,name,".log",txinds->H.nextpos); + txinds->indexfp = txinds777_initfile(&indexfpos,path,name,".index",sizeof(uint64_t) * txinds->H.num); + if ( txinds->txlogfp != 0 && txinds->indexfp != 0 ) + { + memset(&goodH,0,sizeof(goodH)); + while ( fread(&H,1,sizeof(H),fp) == sizeof(H) ) + { + if ( H.num*sizeof(uint64_t) > indexfpos || H.nextpos > logfpos ) + break; + goodH = H; + //printf("loaded H nextpos %d num.%d\n",(int32_t)H.nextpos,(int32_t)H.num); + } + txinds->H = goodH; + if ( txinds->H.nextpos > 0 ) + { + txinds->curitem = 0; + rewind(txinds->txlogfp); + rewind(txinds->indexfp); + while ( txinds->curitem < txinds->H.num ) + { + if ( fread(&txind,1,sizeof(txind),txinds->indexfp) != sizeof(txind) ) + break; + logfpos = ftell(txinds->txlogfp); + if ( fread(triplet,1,sizeof(triplet),txinds->txlogfp) == sizeof(triplet) ) + { + //printf("triplet.(%d %d %d)\n",triplet[0],triplet[1],triplet[2]); + if ( (triplet[0] + logfpos) > txinds->H.nextpos ) + break; + checktxind = (logfpos << 16) | (triplet[0] + sizeof(triplet)); + if ( checktxind != txind ) + { + printf("checktxind error item.%lld %llx != %llx\n",(long long)txinds->curitem,(long long)checktxind,(long long)txind); + txinds->H.num = txinds->curitem; + txinds->H.nextpos = logfpos; + break; + } + txinds777_ensure(txinds,triplet[1],txinds->curitem++); + fseek(txinds->txlogfp,logfpos + (triplet[0] + sizeof(triplet)),SEEK_SET); + } + } + printf("verified %lld items, curpos %ld %ld\n",(long long)txinds->curitem,ftell(txinds->indexfp),ftell(txinds->txlogfp)); + } + } + else + { + if ( txinds->txlogfp != 0 ) + fclose(txinds->txlogfp), txinds->txlogfp = 0; + if ( txinds->indexfp != 0 ) + fclose(txinds->indexfp), txinds->indexfp = 0; + } + } + txinds->fp = fp; + } + else if ( (txinds->fp= fopen(fname,"wb+")) != 0 ) + fwrite(&txinds->H,1,sizeof(txinds->H),txinds->fp); + if ( txinds->txlogfp == 0 || txinds->indexfp == 0 ) + vupdate_sha256(txinds->H.sha256.bytes,&txinds->H.state,0,0); + if ( txinds->txlogfp == 0 ) + txinds->txlogfp = txinds777_initfile(&logfpos,path,name,".log",0); + if ( txinds->indexfp == 0 ) + txinds->indexfp = txinds777_initfile(&indexfpos,path,name,".index",0); + //printf("fps %p %p %p\n",txinds->fp,txinds->txlogfp,txinds->indexfp); + return(txinds); +} + +int32_t txind777_txbuf(uint8_t *txbuf,int32_t len,uint64_t val,int32_t size) +{ + int32_t i; + if ( txbuf != 0 ) + for (i=0; i>=8) + txbuf[len++] = (val & 0xff); + return(len); +} + +int32_t txinds777_flush(struct txinds777_info *txinds,uint32_t blocknum,uint32_t blocktimestamp) +{ + long fpos; + if ( txinds != 0 ) + { + if ( txinds->txlogfp != 0 ) + fflush(txinds->txlogfp); + if ( txinds->indexfp != 0 ) + fflush(txinds->indexfp); + txinds->H.blocknum = blocknum, txinds->H.timestamp = blocktimestamp; + if ( txinds->fp != 0 ) + { + fwrite(&txinds->H,1,sizeof(txinds->H),txinds->fp); + fpos = ftell(txinds->fp); + rewind(txinds->fp); + fwrite(&txinds->H,1,sizeof(txinds->H),txinds->fp); + fseek(txinds->fp,fpos,SEEK_SET); + fflush(txinds->fp); + } + //printf("txinds777_flush.(%s)\n",txinds->name); + } + else + { + printf("txinds777_flush null ptr\n"); + //getchar(); + } + return(0); +} + + + diff --git a/iguana/peggy_update.c b/iguana/peggy_update.c new file mode 100755 index 000000000..dcf342ec3 --- /dev/null +++ b/iguana/peggy_update.c @@ -0,0 +1,767 @@ +/****************************************************************************** + * 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 "peggy.h" +#include "exchanges777.h" + +short Baserel_contractnum[NUM_CURRENCIES+1][NUM_CURRENCIES+1] = +{ + { 28, 18, 25, 22, 27, 9, 13, 0, 36 }, + { 18, 29, 20, 21, 19, 10, 15, 5, 37 }, + { 25, 20, 30, 23, 26, 7, 14, 3, -1 }, + { 22, 21, 23, 31, 24, 11, 16, 4, 38 }, + { 27, 19, 26, 24, 32, 12, 17, 6, 39 }, + { 9, 10, 7, 11, 12, 33, 8, 2, -1 }, + { 13, 15, 14, 16, 17, 8, 34, 1, 40 }, + { 0, 5, 3, 4, 6, 2, 1, 35, -1 }, + { 36, 37, -1, 38, 39, -1, 40, -1, 74 }, +}; + +short Currency_contractdirs[NUM_CURRENCIES+1][NUM_CURRENCIES] = +{ + { -1, 1, 1, -1, -1, 1, -1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { -1, -1, -1, -1, -1, -1, -1, 1 }, + { 1, 1, 1, -1, 1, 1, 1, 1 }, + { 1, 1, 1, -1, -1, 1, 1, 1 }, + { -1, 1, 1, -1, -1, -1, -1, 1 }, + { -1, -1, -1, 1, -1, -1, -1, 1 }, + { 1, 1, 1, 1, -1, -1, -1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1 }, +}; + +static char *Yahoo_metals[] = { YAHOO_METALS }; + +char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies + "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", // end of currencies + "XAU", "XAG", "XPT", "XPD", // metals, gold must be first + "BTCD", "BTC", "NXT", "LTC", "ETH", "DOGE", "BTS", "MAID", "XCP", "XMR" // cryptos +}; + +char CONTRACTS[][16] = { "NZDUSD", "NZDCHF", "NZDCAD", "NZDJPY", "GBPNZD", "EURNZD", "AUDNZD", "CADJPY", "CADCHF", "USDCAD", "EURCAD", "GBPCAD", "AUDCAD", "USDCHF", "CHFJPY", "EURCHF", "GBPCHF", "AUDCHF", "EURUSD", "EURAUD", "EURJPY", "EURGBP", "GBPUSD", "GBPJPY", "GBPAUD", "USDJPY", "AUDJPY", "AUDUSD", "USDCNY", "USDHKD", "USDMXN", "USDZAR", "USDTRY", "EURTRY", "TRYJPY", "USDSGD", "EURNOK", "USDNOK","USDSEK","USDDKK","EURSEK","EURDKK","NOKJPY","SEKJPY","USDPLN","EURPLN","USDILS", // no more currencies + "XAUUSD", "XAGUSD", "XPTUSD", "XPDUSD", "COPPER", "NGAS", "UKOIL", "USOIL", // commodities + // cryptos + "NAS100", "SPX500", "US30", "BUND", "EUSTX50", "UK100", "JPN225", "GER30", "SUI30", "AUS200", "HKG33", "FRA40", "ESP35", "ITA40", "USDOLLAR", // indices + "SuperNET" // assets +}; + +int32_t PAX_ispair(char *base,char *rel,char *contract) +{ + int32_t i,j; + base[0] = rel[0] = 0; + for (i=0; i 0.655564 + USDCNY 6.204146 -> 0.652686 + USDHKD 7.753400 -> 0.749321 + USDHKD 7.746396 -> 0.746445 + USDZAR 12.694000 -> 1.101688 + USDZAR 12.682408 -> 1.098811 + USDTRY 2.779700 -> 0.341327 + EURTRY 3.048500 -> 0.386351 + TRYJPY 44.724000 -> 0.690171 + TRYJPY 44.679966 -> 0.687290 + USDSGD 1.375200 -> 0.239415*/ + //if ( strcmp(contract,"USDCNY") == 0 || strcmp(contract,"TRYJPY") == 0 || strcmp(contract,"USDZAR") == 0 ) + // printf("i.%d j.%d base.%s rel.%s\n",i,j,base,rel); + return((i<<8) | j); + } + break; + } + } + return(-1); +} + +int32_t PAX_basenum(char *base) +{ + int32_t i,j; + if ( 1 ) + { + for (i=0; i (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +cJSON *url_json2(char *url) +{ + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= issue_curl(url)) != 0 ) + { + //printf("(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +double PAX_yahoo(char *metal) +{ + // http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json + // http://finance.yahoo.com/webservice/v1/symbols/XAU=X/quote?format=json + // http://finance.yahoo.com/webservice/v1/symbols/XAG=X/quote?format=json + // http://finance.yahoo.com/webservice/v1/symbols/XPT=X/quote?format=json + // http://finance.yahoo.com/webservice/v1/symbols/XPD=X/quote?format=json + char url[1024],*jsonstr; cJSON *json,*obj,*robj,*item,*field; double price = 0.; + sprintf(url,"http://finance.yahoo.com/webservice/v1/symbols/%s=X/quote?format=json",metal); + if ( (jsonstr= issue_curl(url)) != 0 ) + { + //printf("(%s)\n",jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( (obj= jobj(json,"list")) != 0 && (robj= jobj(obj,"resources")) != 0 && (item= jitem(robj,0)) != 0 ) + { + if ( (robj= jobj(item,"resource")) != 0 && (field= jobj(robj,"fields")) != 0 && (price= jdouble(field,"price")) != 0 ) + price = 1. / price; + } + free_json(json); + } + free(jsonstr); + } + //if ( Debuglevel > 2 ) + printf("(%s %f) ",metal,price); + return(price); +} + +void PAX_btcprices(struct peggy_info *PEGS,int32_t enddatenum,int32_t numdates) +{ + int32_t i,n,year,month,day,seconds,datenum; char url[1024],date[64],*dstr,*str; + uint32_t timestamp,utc32[MAX_SPLINES]; struct tai t; + cJSON *coindesk,*quandl,*btcdhist,*bpi,*array,*item; + double btcddaily[MAX_SPLINES],cdaily[MAX_SPLINES],qdaily[MAX_SPLINES],ask,high,low,bid,close,vol,quotevol,open,price = 0.; + coindesk = url_json("http://api.coindesk.com/v1/bpi/historical/close.json"); + sprintf(url,"https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-numdates*3600*24)); + if ( (bpi= jobj(coindesk,"bpi")) != 0 ) + { + datenum = enddatenum; + memset(utc32,0,sizeof(utc32)); + memset(cdaily,0,sizeof(cdaily)); + if ( datenum == 0 ) + { + datenum = OS_conv_unixtime(&t,&seconds,(uint32_t)time(NULL)); + printf("got datenum.%d %d %d %d\n",datenum,seconds/3600,(seconds/60)%24,seconds%60); + } + for (i=0; isplines[MAX_CURRENCIES],MAX_CURRENCIES,"coindesk",utc32,cdaily,numdates,cdaily); + + } else printf("no bpi\n"); + quandl = url_json("https://www.quandl.com/api/v1/datasets/BAVERAGE/USD.json?rows=64"); + if ( (str= jstr(quandl,"updated_at")) != 0 && (datenum= conv_date(&seconds,str)) > 0 && (array= jarray(&n,quandl,"data")) != 0 ) + { + printf("datenum.%d data.%d %d\n",datenum,n,cJSON_GetArraySize(array)); + memset(utc32,0,sizeof(utc32)), memset(qdaily,0,sizeof(qdaily)); + for (i=0; i 2 ) + printf("(%s) ",cJSON_Print(item)); + if ( (dstr= jstr(jitem(item,0),0)) != 0 && (datenum= conv_date(&seconds,dstr)) > 0 ) + { + price = jdouble(jitem(item,1),0), ask = jdouble(jitem(item,2),0), bid = jdouble(jitem(item,3),0); + close = jdouble(jitem(item,4),0), vol = jdouble(jitem(item,5),0); + //if ( Debuglevel > 2 ) + fprintf(stderr,"%d.[%d %f %f %f %f %f].%d ",i,datenum,price,ask,bid,close,vol,n); + utc32[numdates - 1 - i] = OS_conv_datenum(datenum,12,0,0), qdaily[numdates - 1 - i] = price * .001; + } + } + PAX_genspline(&PEGS->splines[MAX_CURRENCIES+1],MAX_CURRENCIES+1,"quandl",utc32,qdaily,n 2 ) + printf("[%u %d %f]",timestamp,OS_conv_unixtime(&t,&seconds,timestamp),price); + utc32[i] = timestamp - 12*3600, btcddaily[i] = price * 100.; + } + //if ( Debuglevel > 2 ) + printf("poloniex.%d\n",n); + PAX_genspline(&PEGS->splines[MAX_CURRENCIES+2],MAX_CURRENCIES+2,"btcdhist",utc32,btcddaily,n 2 ) + printf("(%s)\n",jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + copy_cJSON(&tmp,jobj(json,"date")), safecopy(date,tmp.buf,64); + if ( (basestr= jstr(json,"base")) != 0 && strcmp(basestr,CURRENCIES[basenum]) == 0 && (ratesobj= jobj(json,"rates")) != 0 && (item= ratesobj->child) != 0 ) + { + while ( item != 0 ) + { + if ( (relstr= get_cJSON_fieldname(item)) != 0 && (relnum= PAX_basenum(relstr)) >= 0 ) + { + i = basenum*MAX_CURRENCIES + relnum; + prices[i] = item->valuedouble; + //if ( basenum == JPYNUM ) + // prices[i] *= 100.; + // else if ( relnum == JPYNUM ) + // prices[i] /= 100.; + count++; + //if ( Debuglevel > 2 ) + printf("(%02d:%02d %f) ",basenum,relnum,prices[i]); + } else printf("cant find.(%s)\n",relstr);//, getchar(); + item = item->next; + } + } + free_json(json); + } + free(jsonstr); + } + return(count); +} + +int32_t PAX_ecbprices(char *date,double *prices,int32_t year,int32_t month,int32_t day) +{ + // http://api.fixer.io/latest?base=CNH + // http://api.fixer.io/2000-01-03?base=USD + // "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD" + char baseurl[512],tmpdate[64],url[512],checkdate[16]; int32_t basenum,count,i,iter,nonz; + checkdate[0] = 0; + if ( year == 0 ) + strcpy(baseurl,"http://api.fixer.io/latest?base="); + else + { + sprintf(checkdate,"%d-%02d-%02d",year,month,day); + sprintf(baseurl,"http://api.fixer.io/%s?base=",checkdate); + } + count = 0; + for (iter=0; iter<2; iter++) + { + for (basenum=0; basenum 2 ) + printf("%8.5f ",prices[MAX_CURRENCIES*basenum + i]); + } + //if ( Debuglevel > 2 ) + printf("%s.%d %d\n",CURRENCIES[basenum],basenum,nonz); + } + } + } + return(count); +} + +int32_t ecb_matrix(double matrix[32][32],char *date) +{ + FILE *fp=0; int32_t n=0,datenum,year=0,seconds,month=0,day=0,loaded = 0; char fname[64],_date[64]; + if ( date == 0 ) + date = _date, memset(_date,0,sizeof(_date)); + sprintf(fname,"DB/ECB/%s",date), OS_compatible_path(fname); + if ( date[0] != 0 && (fp= fopen(fname,"rb")) != 0 ) + { + if ( fread(matrix,1,sizeof(matrix[0][0])*32*32,fp) == sizeof(matrix[0][0])*32*32 ) + loaded = 1; + else printf("fread error\n"); + fclose(fp); + } else printf("ecb_matrix.(%s) load error fp.%p\n",fname,fp); + if ( loaded == 0 ) + { + datenum = conv_date(&seconds,date); + year = datenum / 10000, month = (datenum / 100) % 100, day = (datenum % 100); + if ( (n= PAX_ecbprices(date,&matrix[0][0],year,month,day)) > 0 ) + { + sprintf(fname,"DB/ECB/%s",date), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( fwrite(matrix,1,sizeof(matrix[0][0])*32*32,fp) == sizeof(matrix[0][0])*32*32 ) + loaded = 1; + fclose(fp); + } + } else printf("peggy_matrix error loading %d.%d.%d\n",year,month,day); + } + if ( loaded == 0 && n == 0 ) + { + printf("peggy_matrix couldnt process loaded.%d n.%d\n",loaded,n); + return(-1); + } + //"2000-01-03" + if ( (datenum= conv_date(&seconds,date)) < 0 ) + return(-1); + printf("loaded.(%s) nonz.%d (%d %d %d) datenum.%d\n",date,n,year,month,day,datenum); + return(datenum); +} + +void PAX_update(struct peggy_info *PEGS,double *btcusdp,double *btcdbtcp) +{ + int32_t i,n,seconds,datenum; uint32_t timestamp; char url[1024],*dstr,*str; + double btcddaily=0.,btcusd=0.,ask,high,low,bid,close,vol,quotevol,open,price = 0.; + //cJSON *btcdtrades,*btcdtrades2,*,*bitcoincharts,; + cJSON *quandl,*btcdhist,*array,*item,*bitcoinave,*blockchaininfo,*coindesk=0; + //btcdtrades = url_json("https://poloniex.com/public?command=returnTradeHistory¤cyPair=BTC_BTCD"); + //btcdtrades2 = url_json("https://bittrex.com/api/v1.1/public/getmarkethistory?market=BTC-BTCD&count=50"); + bitcoinave = url_json("https://api.bitcoinaverage.com/ticker/USD/"); + //bitcoincharts = url_json("http://api.bitcoincharts.com/v1/weighted_prices.json"); + blockchaininfo = url_json("https://blockchain.info/ticker"); + coindesk = url_json("http://api.coindesk.com/v1/bpi/historical/close.json"); + sprintf(url,"https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-2*3600*24)); + quandl = url_json("https://www.quandl.com/api/v1/datasets/BAVERAGE/USD.json?rows=1"); + if ( quandl != 0 && (str= jstr(quandl,"updated_at")) != 0 && (datenum= conv_date(&seconds,str)) > 0 && (array= jarray(&n,quandl,"data")) != 0 ) + { + //printf("datenum.%d data.%d %d\n",datenum,n,cJSON_GetArraySize(array)); + for (i=0; i<1; i++) + { + // ["Date","24h Average","Ask","Bid","Last","Total Volume"] + // ["2015-07-25",289.27,288.84,288.68,288.87,44978.61] + item = jitem(array,i); + if ( (dstr= jstr(jitem(item,0),0)) != 0 && (datenum= conv_date(&seconds,dstr)) > 0 ) + { + btcusd = price = jdouble(jitem(item,1),0), ask = jdouble(jitem(item,2),0), bid = jdouble(jitem(item,3),0); + close = jdouble(jitem(item,4),0), vol = jdouble(jitem(item,5),0); + //fprintf(stderr,"%d.[%d %f %f %f %f %f].%d ",i,datenum,price,ask,bid,close,vol,n); + } + } + } + { + double avebid,aveask,bidvol,askvol; struct exchange_quote sortbuf[512]; + struct supernet_info *myinfo = SuperNET_MYINFO(0); cJSON *argjson = cJSON_Parse("{}"); + aveask = instantdex_aveprice(myinfo,sortbuf,(int32_t)(sizeof(sortbuf)/sizeof(*sortbuf)),&askvol,"BTCD","BTC",1,argjson); + avebid = instantdex_aveprice(myinfo,sortbuf,(int32_t)(sizeof(sortbuf)/sizeof(*sortbuf)),&bidvol,"BTCD","BTC",-1,argjson); + if ( avebid > SMALLVAL && aveask > SMALLVAL ) + { + price = (avebid*bidvol + aveask*askvol) / (bidvol + askvol); + *btcdbtcp = price; + printf("set BTCD price %f\n",price); + PEGS->btcdbtc = price; + } + else + { + btcdhist = url_json(url); + //{"date":1406160000,"high":0.01,"low":0.00125,"open":0.01,"close":0.001375,"volume":1.50179994,"quoteVolume":903.58818412,"weightedAverage":0.00166204}, + if ( btcdhist != 0 && (array= jarray(&n,btcdhist,0)) != 0 ) + { + //printf("GOT.(%s)\n",cJSON_Print(array)); + for (i=0; i<1; i++) + { + item = jitem(array,i); + timestamp = juint(item,"date"), high = jdouble(item,"high"), low = jdouble(item,"low"), open = jdouble(item,"open"); + close = jdouble(item,"close"), vol = jdouble(item,"volume"), quotevol = jdouble(item,"quoteVolume"), price = jdouble(item,"weightedAverage"); + //printf("[%u %f %f %f %f %f %f %f]",timestamp,high,low,open,close,vol,quotevol,price); + //printf("[%u %d %f]",timestamp,OS_conv_unixtime(&seconds,timestamp),price); + btcddaily = price; + if ( btcddaily != 0 ) + PEGS->btcdbtc = *btcdbtcp = btcddaily; + } + //printf("poloniex.%d\n",n); + } + if ( btcdhist != 0 ) + free_json(btcdhist); + } + } + if ( bitcoinave != 0 ) + { + if ( (price= jdouble(bitcoinave,"24h_avg")) > SMALLVAL ) + { + //printf("bitcoinave %f %f\n",btcusd,price); + dxblend(&btcusd,price,0.5); + } + free_json(bitcoinave); + } + if ( quandl != 0 ) + free_json(quandl); + if ( coindesk != 0 ) + free_json(coindesk); + if ( blockchaininfo != 0 ) + { + if ( (item= jobj(blockchaininfo,"USD")) != 0 && item != 0 && (price= jdouble(item,"15m")) > SMALLVAL ) + { + //printf("blockchaininfo %f %f\n",btcusd,price); + dxblend(&btcusd,price,0.5); + } + free_json(blockchaininfo); + } + if ( btcusd != 0 ) + PEGS->btcusd = *btcusdp = btcusd; +} + +double blend_price(double *volp,double wtA,cJSON *jsonA,double wtB,cJSON *jsonB) +{ + //A.{"ticker":{"base":"BTS","target":"CNY","price":"0.02958291","volume":"3128008.39295500","change":"0.00019513","markets":[{"market":"BTC38","price":"0.02960000","volume":3051650.682955},{"market":"Bter","price":"0.02890000","volume":76357.71}]},"timestamp":1438490881,"success":true,"error":""} + // B.{"id":"bts\/cny","price":"0.02940000","price_before_24h":"0.02990000","volume_first":"3048457.6857147217","volume_second":"90629.45859575272","volume_btc":"52.74","best_market":"btc38","latest_trade":"2015-08-02 03:57:38","coin1":"BitShares","coin2":"CNY","markets":[{"market":"btc38","price":"0.02940000","volume":"3048457.6857147217","volume_btc":"52.738317962865"},{"market":"bter","price":"0.04350000","volume":"0","volume_btc":"0"}]} + double priceA,priceB,priceB24,price,volA,volB; cJSON *obj; + priceA = priceB = priceB24= price = volA = volB = 0.; + if ( jsonA != 0 && (obj= jobj(jsonA,"ticker")) != 0 ) + { + priceA = jdouble(obj,"price"); + volA = jdouble(obj,"volume"); + } + if ( jsonB != 0 ) + { + priceB = jdouble(jsonB,"price"); + priceB24 = jdouble(jsonB,"price_before_24h"); + volB = jdouble(jsonB,"volume_first"); + } + //printf("priceA %f volA %f, priceB %f %f volB %f\n",priceA,volA,priceB,priceB24,volB); + if ( priceB > SMALLVAL && priceB24 > SMALLVAL ) + priceB = (priceB * .1) + (priceB24 * .9); + else if ( priceB < SMALLVAL ) + priceB = priceB24; + if ( priceA*volA < SMALLVAL ) + price = priceB; + else if ( priceB*volB < SMALLVAL ) + price = priceA; + else price = (wtA * priceA) + (wtB * priceB); + *volp = (volA + volB); + return(price); +} + +void _crypto_update(struct peggy_info *PEGS,double cryptovols[2][8][2],struct PAX_data *dp,int32_t selector,int32_t peggyflag) +{ + char *cryptonatorA = "https://www.cryptonator.com/api/full/%s-%s"; //unity-btc + char *cryptocoinchartsB = "http://api.cryptocoincharts.info/tradingPair/%s_%s"; //bts_btc + char *cryptostrs[9] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp", "etc" }; + int32_t iter,i,j; double btcusd,btcdbtc,cnyusd,prices[8][2],volumes[8][2]; + char base[16],rel[16],url[512],*str; cJSON *jsonA,*jsonB; + if ( peggyflag != 0 ) + { + cnyusd = PEGS->cnyusd; + btcusd = PEGS->btcusd; + btcdbtc = PEGS->btcdbtc; + //printf("update with btcusd %f btcd %f cnyusd %f cnybtc %f\n",btcusd,btcdbtc,cnyusd,cnyusd/btcusd); + if ( btcusd < SMALLVAL || btcdbtc < SMALLVAL ) + { + PAX_update(PEGS,&btcusd,&btcdbtc); + printf("PAX_update with btcusd %f btcd %f\n",btcusd,btcdbtc); + } + memset(prices,0,sizeof(prices)); + memset(volumes,0,sizeof(volumes)); + for (j=0; j SMALLVAL ) + break; + i = 3; + } else i = j; + for (iter=0; iter<1; iter++) + { + if ( i == 0 && iter == 0 ) + strcpy(base,"btcd"), strcpy(rel,"btc"); + else strcpy(base,str), strcpy(rel,iter==0?"btc":"cny"); + //if ( selector == 0 ) + { + sprintf(url,cryptonatorA,base,rel); + jsonA = url_json(url); + } + //else + { + sprintf(url,cryptocoinchartsB,base,rel); + jsonB = url_json(url); + } + prices[i][iter] = blend_price(&volumes[i][iter],0.4,jsonA,0.6,jsonB); + if ( iter == 1 ) + { + if ( btcusd > SMALLVAL ) + { + prices[i][iter] *= cnyusd / btcusd; + volumes[i][iter] *= cnyusd / btcusd; + } else prices[i][iter] = volumes[i][iter] = 0.; + } + cryptovols[0][i][iter] = _pairaved(cryptovols[0][i][iter],prices[i][iter]); + cryptovols[1][i][iter] = _pairaved(cryptovols[1][i][iter],volumes[i][iter]); + //if ( Debuglevel > 2 ) + printf("(%f %f).%d:%d ",cryptovols[0][i][iter],cryptovols[1][i][iter],i,iter); + //if ( cnyusd < SMALLVAL || btcusd < SMALLVAL ) + // break; + } + } + } +} + +void PAX_RTupdate(struct peggy_info *PEGS,double cryptovols[2][8][2],double RTmetals[4],double *RTprices,struct PAX_data *dp) +{ + char *cryptostrs[8] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp" }; + int32_t iter,i,c,baserel,basenum,relnum; double cnyusd,btcusd,btcdbtc,bid,ask,price,vol,prices[8][2],volumes[8][2]; + char base[16],rel[16]; + PAX_update(PEGS,&btcusd,&btcdbtc); + memset(prices,0,sizeof(prices)); + memset(volumes,0,sizeof(volumes)); + for (i=0; i SMALLVAL ) + dxblend(&btcdbtc,prices[0][0],.9); + dxblend(&dp->btcdbtc,btcdbtc,.995); + if ( PEGS->btcdbtc < SMALLVAL ) + PEGS->btcdbtc = dp->btcdbtc; + if ( (cnyusd= PEGS->cnyusd) > SMALLVAL ) + { + if ( prices[0][1] > SMALLVAL ) + { + //printf("cnyusd %f, btccny %f -> btcusd %f %f\n",cnyusd,prices[0][1],prices[0][1]*cnyusd,btcusd); + btcusd = prices[0][1] * cnyusd; + if ( dp->btcusd < SMALLVAL ) + dp->btcusd = btcusd; + else dxblend(&dp->btcusd,btcusd,.995); + if ( PEGS->btcusd < SMALLVAL ) + PEGS->btcusd = dp->btcusd; + if ( PEGS->data.btcusd < SMALLVAL ) + PEGS->data.btcusd = dp->btcusd; + printf("cnyusd %f, btccny %f -> btcusd %f %f -> %f %f %f\n",cnyusd,prices[0][1],prices[0][1]*cnyusd,btcusd,dp->btcusd,PEGS->btcusd,PEGS->data.btcusd); + } + } + for (i=1; i SMALLVAL ) + { + price = ((prices[i][0] * volumes[i][0]) + (prices[i][1] * volumes[i][1])) / vol; + //if ( Debuglevel > 2 ) + printf("%s %f v%f + %f v%f -> %f %f\n",cryptostrs[i],prices[i][0],volumes[i][0],prices[i][1],volumes[i][1],price,dp->cryptos[i]); + dxblend(&dp->cryptos[i],price,.995); + } + } + btcusd = PEGS->btcusd; + btcdbtc = PEGS->btcdbtc; + //if ( Debuglevel > 2 ) + printf(" update with btcusd %f btcd %f\n",btcusd,btcdbtc); + if ( btcusd < SMALLVAL || btcdbtc < SMALLVAL ) + { + PAX_update(PEGS,&btcusd,&btcdbtc); + //if ( Debuglevel > 2 ) + printf(" price777_update with btcusd %f btcd %f\n",btcusd,btcdbtc); + } else PEGS->btcusd = btcusd, PEGS->btcdbtc = btcdbtc; + for (c=0; ctbids[c], ask = dp->tasks[c]; break; + case 1: bid = dp->fbids[c], ask = dp->fasks[c]; break; + case 2: bid = dp->ibids[c], ask = dp->iasks[c]; break; + } + if ( (price= _pairaved(bid,ask)) > SMALLVAL ) + { + //if ( Debuglevel > 2 ) + printf("%.6f ",price); + dxblend(&RTprices[c],price,.995); + if ( 0 && (baserel= PAX_ispair(base,rel,CONTRACTS[c])) >= 0 ) + { + basenum = (baserel >> 8) & 0xff, relnum = baserel & 0xff; + if ( basenum < 32 && relnum < 32 ) + { + //printf("%s.%d %f <- %f\n",CONTRACTS[c],c,RTmatrix[basenum][relnum],RTprices[c]); + //dxblend(&RTmatrix[basenum][relnum],RTprices[c],.999); + } + } + if ( strcmp(CONTRACTS[c],"XAUUSD") == 0 ) + dxblend(&RTmetals[0],price,.995); + } + } + } + for (i=0; idata.metals[i] != 0 ) + dxblend(&RTmetals[i],PEGS->data.metals[i],.995); +} + +void PAX_bidask(struct exchange_info *exchange,uint32_t *timestamps,double *bids,double *asks,int32_t baseid,int32_t relid) +{ + int32_t contractnum; struct exchange_quote bidasks[2]; + contractnum = Baserel_contractnum[baseid][relid]; + (*exchange->issue.price)(exchange,CURRENCIES[baseid],CURRENCIES[relid],bidasks,1,0.,0,0); + bids[contractnum] = bidasks[0].price; + asks[contractnum] = bidasks[1].price; + timestamps[contractnum] = bidasks[0].timestamp; + printf("%.6f ",_pairaved(bids[contractnum],asks[contractnum])); +} + +struct exchange_info *PAX_bidasks(char *exchangestr,uint32_t *timestamps,double *bids,double *asks) +{ + int32_t baseid,relid; struct exchange_info *exchange; + if ( (exchange= exchanges777_find(exchangestr)) != 0 ) + { + for (baseid=0; baseid<8; baseid++) + { + for (relid=0; relid<8; relid++) + { + if ( Currency_contractdirs[baseid][relid] > 0 ) + PAX_bidask(exchange,timestamps,bids,asks,baseid,relid); + } + } + } else printf("cant find (%s) exchange\n",exchangestr); + printf("%s\n",exchangestr); + return(exchange); +} + +int32_t PAX_idle(struct peggy_info *PEGS,int32_t peggyflag,int32_t idlegap) +{ + static double lastupdate,lastdayupdate; static int32_t didinit; static portable_mutex_t mutex; + struct exchange_info *exchange; struct exchange_quote bidasks[2]; double btcdbtc,btcusd; + int32_t i,datenum,contractnum; struct PAX_data *dp = &PEGS->tmp; + *dp = PEGS->data; + if ( didinit == 0 ) + { + portable_mutex_init(&mutex); + //prices777_init(BUNDLE.jsonstr,peggyflag); + didinit = 1; + if ( peggyflag != 0 ) + { + //int32_t opreturns_init(uint32_t blocknum,uint32_t blocktimestamp,char *path); + //opreturns_init(0,(uint32_t)time(NULL),"peggy"); + } + } + if ( peggyflag != 0 && OS_milliseconds() > lastupdate + (1000*idlegap) ) + { + lastupdate = OS_milliseconds(); + if ( OS_milliseconds() > lastdayupdate + 60000*60 ) + { + lastdayupdate = OS_milliseconds(); + if ( (datenum= ecb_matrix(dp->ecbmatrix,dp->edate)) > 0 ) + { + dp->ecbdatenum = datenum; + dp->ecbyear = dp->ecbdatenum / 10000, dp->ecbmonth = (dp->ecbdatenum / 100) % 100, dp->ecbday = (dp->ecbdatenum % 100); + expand_datenum(dp->edate,datenum); + memcpy(dp->RTmatrix,dp->ecbmatrix,sizeof(dp->RTmatrix)); + } + } + for (i=0; imetals[i] = PAX_yahoo(Yahoo_metals[i]); + PAX_bidasks("truefx",dp->ttimestamps,dp->tbids,dp->tasks); + PAX_bidasks("fxcm",dp->ftimestamps,dp->fbids,dp->fasks); + if ( (exchange= PAX_bidasks("instaforex",dp->itimestamps,dp->ibids,dp->iasks)) != 0 ) + { + if ( (contractnum= PAX_contractnum("XAU","USD")) >= 0 ) + { + (*exchange->issue.price)(exchange,"XAU","USD",bidasks,1,0.,0,0); + dp->ibids[contractnum] = bidasks[0].price; + dp->iasks[contractnum] = bidasks[1].price; + dp->itimestamps[contractnum] = bidasks[0].timestamp; + } + } + PAX_update(PEGS,&btcusd,&btcdbtc); + if ( btcusd > SMALLVAL ) + dxblend(&dp->btcusd,btcusd,0.99); + if ( btcdbtc > SMALLVAL ) + dxblend(&dp->btcdbtc,btcdbtc,0.99); + if ( dp->btcusd == 0 ) + dp->btcusd = dp->btcusd; + if ( dp->btcdbtc == 0 ) + dp->btcdbtc = dp->btcdbtc; + if ( dp->ecbmatrix[USD][USD] > SMALLVAL && dp->ecbmatrix[CNY][CNY] > SMALLVAL ) + PEGS->cnyusd = (dp->ecbmatrix[CNY][CNY] / dp->ecbmatrix[USD][USD]); + portable_mutex_lock(&mutex); + PEGS->data = *dp; + portable_mutex_unlock(&mutex); + //kv777_write(PEGS->kv,"data",5,&PEGS->data,sizeof(BUNDLE.data)); + PAX_RTupdate(PEGS,PEGS->cryptovols,dp->RTmetals,dp->RTprices,dp); + //printf("update finished\n"); + void peggy(); + peggy(); + didinit = 1; + } + return(0); +} diff --git a/iguana/pnacl/Release/iguana.pexe b/iguana/pnacl/Release/iguana.pexe index e19f23bad..c4e05468a 100644 Binary files a/iguana/pnacl/Release/iguana.pexe and b/iguana/pnacl/Release/iguana.pexe differ diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 38d150a54..5cbcf209a 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -20,8 +20,11 @@ HASH_AND_INT(ramchain,getrawtransaction,txid,verbose); HASH_ARG(ramchain,gettransaction,txid); STRING_ARG(ramchain,decoderawtransaction,rawtx); -THREE_STRINGS(InstantDEX,encryptjson,passphrase,permanentfile,anything); -TWO_STRINGS(InstantDEX,decryptjson,passphrase,permanentfile); +FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); +ZERO_ARGS(SuperNET,logout); +ZERO_ARGS(SuperNET,activehandle); +THREE_STRINGS(SuperNET,encryptjson,password,permanentfile,anything); +TWO_STRINGS(SuperNET,decryptjson,password,permanentfile); THREE_STRINGS_AND_THREE_INTS(InstantDEX,orderbook,exchange,base,rel,depth,allfields,invert); THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,buy,exchange,base,rel,price,volume,dotrade); @@ -41,11 +44,11 @@ STRING_ARG(InstantDEX,allpairs,exchange); THREE_STRINGS_AND_DOUBLE(InstantDEX,request,reference,base,rel,volume); TWOSTRINGS_AND_TWOHASHES_AND_TWOINTS(InstantDEX,proposal,reference,message,basetxid,reltxid,duration,flags); - TWOSTRINGS_AND_TWOHASHES_AND_TWOINTS(InstantDEX,accept,reference,message,basetxid,reltxid,duration,flags); TWOSTRINGS_AND_TWOHASHES_AND_TWOINTS(InstantDEX,confirm,reference,message,basetxid,reltxid,baseheight,relheight); 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,price,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price,volume,duration); @@ -55,15 +58,21 @@ TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); -/*HASH_AND_ARRAY(pangea,userturn,tablehash,params); - HASH_AND_ARRAY(pangea,status,tableid,params); - HASH_AND_ARRAY(pangea,mode,tableid,params); - HASH_AND_ARRAY(pangea,buyin,tableid,params); - HASH_AND_ARRAY(pangea,history,tableid,params);*/ +HASH_ARG(pangea,call,tablehash); +HASH_AND_INT(pangea,raise,tablehash,numchips); +HASH_AND_INT(pangea,bet,tablehash,numchips); +HASH_ARG(pangea,check,tablehash); +HASH_ARG(pangea,fold,tablehash); +HASH_ARG(pangea,allin,tablehash); +HASH_ARG(pangea,status,tablehash); +HASH_AND_STRING(pangea,mode,tablehash,params); +HASH_ARG(pangea,history,tablehash); +HASH_AND_INT(pangea,handhistory,tablehash,hand); INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); -HASH_AND_ARRAY(pangea,start,tablehash,params); +HASH_AND_INT(pangea,buyin,tablehash,numchips); +HASH_ARG(pangea,start,tablehash); ZERO_ARGS(SuperNET,help); STRING_ARG(SuperNET,utime2utc,utime); diff --git a/includes/iguana_apidefs.h b/includes/iguana_apidefs.h index b6fc2b4f0..33082c212 100755 --- a/includes/iguana_apidefs.h +++ b/includes/iguana_apidefs.h @@ -5,6 +5,7 @@ #define IGUANA_CFUNC_S(agent,name,str) char *agent ## _ ## name(IGUANA_ARGS,char *str) #define IGUANA_CFUNC_I(agent,name,val) char *agent ## _ ## name(IGUANA_ARGS,int32_t val) #define IGUANA_CFUNC_SA(agent,name,str,array) char *agent ## _ ## name(IGUANA_ARGS,char *str,cJSON *array) +#define IGUANA_CFUNC_SD(agent,name,str,val) char *agent ## _ ## name(IGUANA_ARGS,char *str,double val) #define IGUANA_CFUNC_AA(agent,name,array,array2) char *agent ## _ ## name(IGUANA_ARGS,cJSON *array,cJSON *array2) #define IGUANA_CFUNC_SAA(agent,name,str,array,array2) char *agent ## _ ## name(IGUANA_ARGS,char *str,cJSON *array,cJSON *array2) @@ -24,6 +25,7 @@ #define IGUANA_CFUNC_SSHII(agent,name,str,str2,hash,val,val2) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,bits256 hash,int32_t val,int32_t val2) #define IGUANA_CFUNC_SSHHII(agent,name,str,str2,hash,hash2,val,val2) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,bits256 hash,bits256 hash2,int32_t val,int32_t val2) #define IGUANA_CFUNC_SSS(agent,name,str,str2,str3) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3) +#define IGUANA_CFUNC_SSSS(agent,name,str,str2,str3,str4) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,char *str4) #define IGUANA_CFUNC_SSSD(agent,name,str,str2,str3,val) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,double val) #define IGUANA_CFUNC_SSSDDD(agent,name,str,str2,str3,val,val2,val3) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,double val,double val2,double val3) #define IGUANA_CFUNC_SSSIII(agent,name,str,str2,str3,val,val2,val3) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,int32_t val,int32_t val2,int32_t val3) @@ -51,7 +53,9 @@ #define STRING_ARG IGUANA_CFUNC_S #define TWO_STRINGS IGUANA_CFUNC_SS #define THREE_STRINGS IGUANA_CFUNC_SSS +#define FOUR_STRINGS IGUANA_CFUNC_SSSS #define STRING_AND_INT IGUANA_CFUNC_SI +#define STRING_AND_DOUBLE IGUANA_CFUNC_SD #define STRING_AND_TWOINTS IGUANA_CFUNC_SII #define HASH_AND_INT IGUANA_CFUNC_HI #define HASH_AND_STRING IGUANA_CFUNC_HS diff --git a/includes/iguana_apiundefs.h b/includes/iguana_apiundefs.h index f7615746a..54b986e04 100755 --- a/includes/iguana_apiundefs.h +++ b/includes/iguana_apiundefs.h @@ -36,6 +36,8 @@ #undef THREE_STRINGS_AND_THREE_INTS #undef THREE_STRINGS_AND_THREE_DOUBLES #undef THREE_STRINGS_AND_DOUBLE +#undef STRING_AND_DOUBLE +#undef FOUR_STRINGS #undef IGUANA_ARGS #undef IGUANA_CALLARGS diff --git a/prices/prices777.c b/prices/prices777.c index 5d65d706d..4e430f77b 100755 --- a/prices/prices777.c +++ b/prices/prices777.c @@ -1068,7 +1068,7 @@ cJSON *url_json2(char *url) return(json); } -void prices777_btcprices(int32_t enddatenum,int32_t numdates) +void PAX_btcprices(int32_t enddatenum,int32_t numdates) { int32_t i,n,year,month,day,seconds,datenum; char url[1024],date[64],*dstr,*str; uint32_t timestamp,utc32[MAX_SPLINES]; cJSON *coindesk,*quandl,*btcdhist,*bpi,*array,*item; @@ -1145,7 +1145,7 @@ void prices777_btcprices(int32_t enddatenum,int32_t numdates) // https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400 } -int32_t prices777_calcmatrix(double matrix[32][32]) +int32_t PAX_calcmatrix(double matrix[32][32]) { int32_t basenum,relnum,nonz,vnum,iter,numbase,numerrs = 0; double sum,vsum,price,price2,basevals[32],errsum=0; memset(basevals,0,sizeof(basevals)); @@ -1210,6 +1210,92 @@ int32_t prices777_calcmatrix(double matrix[32][32]) return(errsum); } +int32_t prices777_ecbparse(char *date,double *prices,char *url,int32_t basenum) +{ + char *jsonstr,*relstr,*basestr; int32_t count=0,i,relnum; cJSON *json,*ratesobj,*item; struct destbuf tmp; + if ( (jsonstr= issue_curl(url)) != 0 ) + { + //if ( Debuglevel > 2 ) + printf("(%s)\n",jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + copy_cJSON(&tmp,jobj(json,"date")), safecopy(date,tmp.buf,64); + if ( (basestr= jstr(json,"base")) != 0 && strcmp(basestr,CURRENCIES[basenum]) == 0 && (ratesobj= jobj(json,"rates")) != 0 && (item= ratesobj->child) != 0 ) + { + while ( item != 0 ) + { + if ( (relstr= get_cJSON_fieldname(item)) != 0 && (relnum= prices777_basenum(relstr)) >= 0 ) + { + i = basenum*MAX_CURRENCIES + relnum; + prices[i] = item->valuedouble; + //if ( basenum == JPYNUM ) + // prices[i] *= 100.; + // else if ( relnum == JPYNUM ) + // prices[i] /= 100.; + count++; + //if ( Debuglevel > 2 ) + printf("(%02d:%02d %f) ",basenum,relnum,prices[i]); + } else printf("cant find.(%s)\n",relstr);//, getchar(); + item = item->next; + } + } + free_json(json); + } + free(jsonstr); + } + return(count); +} + +int32_t prices777_ecb(char *date,double *prices,int32_t year,int32_t month,int32_t day) +{ + // http://api.fixer.io/latest?base=CNH + // http://api.fixer.io/2000-01-03?base=USD + // "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD" + char baseurl[512],tmpdate[64],url[512],checkdate[16]; int32_t basenum,count,i,iter,nonz; + checkdate[0] = 0; + if ( year == 0 ) + strcpy(baseurl,"http://api.fixer.io/latest?base="); + else + { + sprintf(checkdate,"%d-%02d-%02d",year,month,day); + sprintf(baseurl,"http://api.fixer.io/%s?base=",checkdate); + } + count = 0; + for (iter=0; iter<2; iter++) + { + for (basenum=0; basenum 2 ) + printf("%8.5f ",prices[MAX_CURRENCIES*basenum + i]); + } + //if ( Debuglevel > 2 ) + printf("%s.%d %d\n",CURRENCIES[basenum],basenum,nonz); + } + } + } + return(count); +} + int32_t ecb_matrix(double matrix[32][32],char *date) { FILE *fp=0; int32_t n=0,datenum,year=0,seconds,month=0,day=0,loaded = 0; char fname[64],_date[64];