/****************************************************************************** * 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); }