@ -20,16 +20,38 @@
# define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos)
# define N_CCMARKER 1
# define NVOUT_CCMARKER 1
# define NVOUT_NORMALMARKER 3
typedef struct BetInfo {
int64_t amount ;
typedef struct OneBetData {
int64_t positionsize ;
int32_t firstheight ;
int64_t costbasis ;
int64_t profits ;
BetInfo ( ) { amount = 0 ; firstheight = 0 ; costbasis = 0 ; profits = 0 ; } // it is important to clear costbasis as it will be calculated as minmax from inital value 0
} betinfo ;
OneBetData ( ) { positionsize = 0 ; firstheight = 0 ; costbasis = 0 ; profits = 0 ; } // it is important to clear costbasis as it will be calculated as minmax from inital value 0
} onebetdata ;
typedef struct BetInfo {
int64_t averageCostbasis , firstprice , lastprice , liquidationprice , equity ;
int64_t rektfee ;
int32_t lastheight ;
int16_t leverage ;
bool isOpen , isRekt ;
uint256 tokenid ;
std : : vector < uint16_t > parsed ;
std : : vector < onebetdata > bets ;
CPubKey pk ;
BetInfo ( ) {
averageCostbasis = firstprice = lastprice = liquidationprice = equity = 0 ;
lastheight = 0 ;
leverage = 0 ;
rektfee = 0 ;
isOpen = isRekt = false ;
}
} BetInfo ;
/*
CBOPRET creates trustless oracles , which can be used for making a synthetic cash settlement system based on real world prices ;
@ -145,7 +167,7 @@ uint8_t prices_finalopretdecode(CScript scriptPubKey,uint256 &bettxid,int64_t &p
}
// price opret basic validation and retrieval
static uint8_t Check PricesOpret( const CTransaction & tx , vscript_t & opret )
static uint8_t PricesCheck Opret ( const CTransaction & tx , vscript_t & opret )
{
if ( tx . vout . size ( ) > 0 & & GetOpReturnData ( tx . vout . back ( ) . scriptPubKey , opret ) & & opret . size ( ) > 2 & & opret . begin ( ) [ 0 ] = = EVAL_PRICES & & IS_CHARINSTR ( opret . begin ( ) [ 1 ] , " BACF " ) )
return opret . begin ( ) [ 1 ] ;
@ -217,7 +239,7 @@ static bool ValidateAddFundingTx(struct CCcontract_info *cp, Eval *eval, const C
return eval - > Invalid ( " cannot decode opreturn for add funding tx " ) ;
pricespk = GetUnspendable ( cp , 0 ) ;
uint8_t vintxFuncId = Check PricesOpret( vintx , vintxOpret ) ;
uint8_t vintxFuncId = PricesCheck Opret ( vintx , vintxOpret ) ;
if ( vintxFuncId ! = ' A ' & & vintxFuncId ! = ' B ' ) { // if vintx is bettx
return eval - > Invalid ( " incorrect vintx funcid " ) ;
}
@ -352,7 +374,7 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
if ( strcmp ( ASSETCHAINS_SYMBOL , " REKT0 " ) = = 0 & & chainActive . Height ( ) < 2965 )
return true ;
// check basic opret rules:
if ( Check PricesOpret( tx , vopret ) = = 0 )
if ( PricesCheck Opret ( tx , vopret ) = = 0 )
return eval - > Invalid ( " tx has no prices opreturn " ) ;
uint8_t funcId = vopret . begin ( ) [ 1 ] ;
@ -375,7 +397,7 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
if ( ! myGetTransaction ( vin . prevout . hash , vintx , hashBlock ) )
return eval - > Invalid ( " cannot load vintx " ) ;
if ( Check PricesOpret( vintx , vintxOpret ) = = 0 ) {
if ( PricesCheck Opret ( vintx , vintxOpret ) = = 0 ) {
//return eval->Invalid("cannot find prices opret in vintx");
std : : cerr < < " PricesValidate() " < < " cannot find prices opret in vintx " < < std : : endl ;
}
@ -486,7 +508,7 @@ int64_t AddPricesInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, ch
if ( GetTransaction ( txid , vintx , hashBlock , false ) ! = 0 & & vout < vintx . vout . size ( ) )
{
vscript_t vopret ;
uint8_t funcId = Check PricesOpret( vintx , vopret ) ;
uint8_t funcId = PricesCheck Opret ( vintx , vopret ) ;
if ( funcId = = ' B ' & & vout = = 1 ) // skip cc marker
continue ;
@ -1215,7 +1237,7 @@ int32_t prices_syntheticprofits(int64_t &costbasis, int32_t firstheight, int32_t
}
// makes result json object
void prices_betjson ( UniValue & result , std : : vector < BetInfo > bets , int16_t leverage , int32_t endheight , int64_t lastprice )
void prices_betjson ( UniValue & result , std : : vector < OneBetData > bets , int16_t leverage , int32_t endheight , int64_t lastprice )
{
UniValue resultbets ( UniValue : : VARR ) ;
@ -1224,12 +1246,12 @@ void prices_betjson(UniValue &result, std::vector<BetInfo> bets, int16_t leverag
for ( auto b : bets ) {
UniValue entry ( UniValue : : VOBJ ) ;
entry . push_back ( Pair ( " positionsize " , ValueFromAmount ( b . amount ) ) ) ;
entry . push_back ( Pair ( " positionsize " , ValueFromAmount ( b . positionsize ) ) ) ;
entry . push_back ( Pair ( " profits " , ValueFromAmount ( b . profits ) ) ) ;
entry . push_back ( Pair ( " costbasis " , ValueFromAmount ( b . costbasis ) ) ) ;
entry . push_back ( Pair ( " firstheight " , b . firstheight ) ) ;
resultbets . push_back ( entry ) ;
totalbets + = b . amount ;
totalbets + = b . positionsize ;
totalprofits + = b . profits ;
}
int64_t equity = totalbets + totalprofits ;
@ -1277,7 +1299,7 @@ int64_t prices_costbasis(CTransaction bettx, uint256 &txidCostbasis)
}
// enumerates and retrieves added bets, returns the last baton txid
int64_t prices_enumaddedbets ( uint256 & batontxid , std : : vector < BetInfo > & bets , uint256 bettxid )
int64_t prices_enumaddedbets ( uint256 & batontxid , std : : vector < OneBetData > & bets , uint256 bettxid )
{
int64_t addedBetsTotal = 0 ;
int32_t vini ;
@ -1304,10 +1326,10 @@ int64_t prices_enumaddedbets(uint256 &batontxid, std::vector<BetInfo> &bets, uin
txBaton . vout . size ( ) > 0 & &
( funcId = prices_addopretdecode ( txBaton . vout . back ( ) . scriptPubKey , bettxidInOpret , pk , amount ) ) ! = 0 )
{
BetInfo added ;
OneBetData added ;
addedBetsTotal + = amount ;
added . amount = amount ;
added . positionsize = amount ;
added . firstheight = blockIdx . GetHeight ( ) ;
bets . push_back ( added ) ;
std : : cerr < < " prices_batontxid() added amount= " < < amount < < std : : endl ;
@ -1357,9 +1379,9 @@ UniValue PricesBet(int64_t txfee, int64_t amount, int16_t leverage, std::vector<
betamount = ( amount * 199 ) / 200 ;
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , txfee , mypk ) ) ; // vout0 baton for total funding
// mtx.vout.push_back(MakeCC1vout(cp->evalcode, (amount - betamount) + 2 * txfee, pricespk)); // vout1, when spent, costbasis is set
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , txfee , pricespk ) ) ; // vout1 cc marker (N_CCMARKER)
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , txfee , pricespk ) ) ; // vout1 cc marker (NVOUT _CCMARKER)
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , betamount , pricespk ) ) ; // vout2 betamount
mtx . vout . push_back ( CTxOut ( txfee , CScript ( ) < < ParseHex ( HexStr ( pricespk ) ) < < OP_CHECKSIG ) ) ; // vout3 normal marker - TODO: remove it as we have cc marker now, when move to the new chain
mtx . vout . push_back ( CTxOut ( txfee , CScript ( ) < < ParseHex ( HexStr ( pricespk ) ) < < OP_CHECKSIG ) ) ; // vout3 normal marker NVOUT_NORMALMARKER - TODO: remove it as we have cc marker now, when move to the new chain
rawtx = FinalizeCCTx ( 0 , cp , mtx , mypk , txfee , prices_betopret ( mypk , nextheight - 1 , amount , leverage , firstprice , vec , zeroid ) ) ;
return ( prices_rawtxresult ( result , rawtx , 0 ) ) ;
}
@ -1389,7 +1411,7 @@ UniValue PricesAddFunding(int64_t txfee, uint256 bettxid, int64_t amount)
//GetCCaddress(cp, myaddr, mypk);
if ( AddNormalinputs ( mtx , mypk , amount + 2 * txfee , 64 ) > = amount + 2 * txfee )
{
std : : vector < BetInfo > bets ;
std : : vector < OneBetData > bets ;
if ( prices_enumaddedbets ( batontxid , bets , bettxid ) > = 0 )
{
mtx . vin . push_back ( CTxIn ( batontxid , 0 , CScript ( ) ) ) ;
@ -1411,7 +1433,7 @@ UniValue PricesAddFunding(int64_t txfee, uint256 bettxid, int64_t amount)
}
// scan chain from the initial bet's first position upto the chain tip and calculate bet's costbasises and profits, breaks if rekt detected
int32_t prices_scanchain ( std : : vector < BetInfo > & bets , int16_t leverage , std : : vector < uint16_t > vec , int64_t & lastprice , int32_t & endheight ) {
int32_t prices_scanchain ( std : : vector < OneBetData > & bets , int16_t leverage , std : : vector < uint16_t > vec , int64_t & lastprice , int32_t & endheight ) {
if ( bets . size ( ) = = 0 )
return - 1 ;
@ -1427,13 +1449,13 @@ int32_t prices_scanchain(std::vector<BetInfo> &bets, int16_t leverage, std::vect
if ( height > bets [ i ] . firstheight ) {
int32_t retcode = prices_syntheticprofits ( bets [ i ] . costbasis , bets [ i ] . firstheight , height , leverage , vec , bets [ i ] . amount , bets [ i ] . profits , lastprice ) ;
int32_t retcode = prices_syntheticprofits ( bets [ i ] . costbasis , bets [ i ] . firstheight , height , leverage , vec , bets [ i ] . positionsize , bets [ i ] . profits , lastprice ) ;
if ( retcode < 0 ) {
std : : cerr < < " prices_scanchain() prices_syntheticprofits returned -1, breaking " < < std : : endl ;
stop = true ;
break ;
}
totalbets + = bets [ i ] . amount ;
totalbets + = bets [ i ] . positionsize ;
totalprofits + = bets [ i ] . profits ;
}
}
@ -1523,117 +1545,222 @@ UniValue PricesSetcostbasis(int64_t txfee, uint256 bettxid)
return ( result ) ;
}
// pricesrekt rpc: anyone can rekt a bet at some block where losses reached limit, collecting fee
UniValue PricesRekt ( int64_t txfee , uint256 bettxid , int32_t rektheight )
{
int32_t nextheight = komodo_nextheight ( ) ;
CMutableTransaction mtx = CreateNewContextualCMutableTransaction ( Params ( ) . GetConsensus ( ) , nextheight ) ; UniValue result ( UniValue : : VOBJ ) ;
struct CCcontract_info * cp , C ;
CTransaction bettx ;
uint256 hashBlock , tokenid , batontxid ;
int64_t myfee = 0 , firstprice , lastprice = 0 , positionsize ;
int32_t firstheight ;
int16_t leverage ;
std : : vector < uint16_t > vec ;
CPubKey pk , mypk , pricespk ;
std : : string rawtx ;
char destaddr [ 64 ] ;
cp = CCinit ( & C , EVAL_PRICES ) ;
if ( txfee = = 0 )
txfee = PRICES_TXFEE ;
mypk = pubkey2pk ( Mypubkey ( ) ) ;
pricespk = GetUnspendable ( cp , 0 ) ;
GetCCaddress ( cp , destaddr , pricespk ) ;
int32_t prices_getbetinfo ( uint256 bettxid , BetInfo & betinfo )
{
CTransaction bettx ;
uint256 hashBlock , batontxid , tokenid ;
if ( myGetTransaction ( bettxid , bettx , hashBlock ) ! = 0 & & bettx . vout . size ( ) > 3 )
if ( myGetTransaction ( bettxid , bettx , hashBlock ) & & bettx . vout . size ( ) > 3 )
{
if ( prices_betopretdecode ( bettx . vout . back ( ) . scriptPubKey , pk , firstheight , positionsize , leverage , firstprice , vec , tokenid ) = = ' B ' )
if ( hashBlock . IsNull ( ) )
return - 2 ;
OneBetData bet1 ;
if ( prices_betopretdecode ( bettx . vout . back ( ) . scriptPubKey , betinfo . pk , bet1 . firstheight , bet1 . positionsize , betinfo . leverage , betinfo . firstprice , betinfo . parsed , betinfo . tokenid ) = = ' B ' )
{
uint256 finaltxid ;
int32_t vini ;
int32_t finalheight , endheight ;
std : : vector < BetInfo > bets ;
BetInfo bet1 ;
int32_t finaltxheight ; //, endheight;
//std::vector<OneBetData> bets;
if ( CCgetspenttxid ( finaltxid , vini , finalheight , bettxid , N_CCMARKER ) = = 0 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position closed " ) ) ;
return result ;
}
bet1 . amount = positionsize ;
bet1 . firstheight = firstheight ;
bets . push_back ( bet1 ) ;
if ( CCgetspenttxid ( finaltxid , vini , finaltxheight , bettxid , NVOUT_CCMARKER ) = = 0 )
betinfo . isOpen = false ;
else
betinfo . isOpen = true ;
prices_enumaddedbets ( batontxid , bets , bettxid ) ;
//bet1.amount = betinfo.positionsize;
//bet1.firstheight = firstheight;
betinfo . bets . push_back ( bet1 ) ;
if ( prices_scanchain ( bets , leverage , vec , lastprice , endheight ) < 0 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " error scanning chain " ) ) ;
return ( result ) ;
prices_enumaddedbets ( batontxid , betinfo . bets , bettxid ) ;
if ( prices_scanchain ( betinfo . bets , betinfo . leverage , betinfo . parsed , betinfo . lastprice , betinfo . lastheight ) < 0 ) {
return - 4 ;
}
mpz_t mpzTotalbets ;
mpz_t mpzTotalprofits ;
mpz_t mpzTotalcostbasis ;
mpz_init ( mpzTotalbets ) ;
mpz_init ( mpzTotalprofits ) ;
mpz_init ( mpzTotalcostbasis ) ;
int64_t totalbets = 0 ;
int64_t totalprofits = 0 ;
for ( auto b : bets ) {
totalbets + = b . amount ;
for ( auto b : betinfo . bets ) {
mpz_t mpzProduct ;
mpz_t mpzProfits ;
mpz_init ( mpzProduct ) ;
mpz_init ( mpzProfits ) ;
//totalprofits += b.profits;
//dcostbasis += b.amount * (double)b.costbasis;
// costbasis += b.amount * (b.costbasis / PRICES_POINTFACTOR); // prevent int64 overflow (but we have underflow for 1/BTC)
// std::cerr << "PricesInfo() acc dcostbasis=" << dcostbasis << " b.amount=" << b.amount << " b.costbasis/PRICES_POINTFACTOR=" << (b.costbasis / PRICES_POINTFACTOR) << std::endl;
//std::cerr << "PricesInfo() acc dcostbasis=" << dcostbasis << " b.amount=" << b.amount << " b.costbasis/PRICES_POINTFACTOR=" << (b.costbasis / PRICES_POINTFACTOR) << std::endl;
mpz_set_ui ( mpzProduct , b . costbasis ) ;
mpz_mul_ui ( mpzProduct , mpzProduct , ( uint64_t ) b . positionsize ) ; // b.costbasis * b.amount
mpz_add ( mpzTotalcostbasis , mpzTotalcostbasis , mpzProduct ) ; //averageCostbasis += b.costbasis * b.amount;
mpz_add_ui ( mpzTotalbets , mpzTotalbets , ( uint64_t ) b . positionsize ) ; //totalbets += b.amount;
mpz_add ( mpzTotalprofits , mpzTotalprofits , mpzProfits ) ; //totalprofits += b.profits;
totalbets + = b . positionsize ;
totalprofits + = b . profits ;
mpz_clear ( mpzProduct ) ;
mpz_clear ( mpzProfits ) ;
}
prices_betjson ( result , bets , leverage , endheight , lastprice ) ; // fill output json
betinfo . equity = totalbets + totalprofits ;
//int64_t averageCostbasis = 0;
int64_t equity = totalbets + totalprofits ;
if ( equity < 0 )
{
myfee = totalbets / 500 ; // consolation fee for loss
}
if ( myfee ! = 0 )
{
int64_t CCchange = 0 , inputsum ;
if ( mpz_get_ui ( mpzTotalbets ) ! = 0 ) { //prevent zero div
mpz_t mpzAverageCostbasis ;
mpz_init ( mpzAverageCostbasis ) ;
mtx . vin . push_back ( CTxIn ( bettxid , N_CCMARKER , CScript ( ) ) ) ; // spend cc marker
if ( ( inputsum = AddPricesInputs ( cp , mtx , destaddr , myfee + txfee , 64 ) ) > myfee + txfee ) // TODO: why do we take txfee from global addr and not from user's addr?
CCchange = ( inputsum - myfee ) ;
mtx . vout . push_back ( CTxOut ( myfee , CScript ( ) < < ParseHex ( HexStr ( mypk ) ) < < OP_CHECKSIG ) ) ;
if ( CCchange > = txfee )
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , CCchange , pricespk ) ) ;
//averageCostbasis = totalcostbasis / totalbets;
mpz_mul_ui ( mpzTotalcostbasis , mpzTotalcostbasis , SATOSHIDEN ) ; // profits *= SATOSHIDEN normalization to prevent loss of significance while division
mpz_tdiv_q ( mpzAverageCostbasis , mpzTotalcostbasis , mpzTotalbets ) ;
/// mtx.vout.push_back(MakeCC1vout(cp->evalcode, bettx.vout[2].nValue - myfee - txfee, pricespk)); // change
rawtx = FinalizeCCTx ( 0 , cp , mtx , mypk , txfee , prices_finalopret ( bettxid , totalprofits , rektheight , mypk , firstprice , 0 , totalbets - positionsize , positionsize , leverage ) ) ;
return ( prices_rawtxresult ( result , rawtx , 0 ) ) ;
mpz_tdiv_q_ui ( mpzAverageCostbasis , mpzAverageCostbasis , SATOSHIDEN ) ; // profits /= SATOSHIDEN de-normalization
betinfo . averageCostbasis = mpz_get_ui ( mpzAverageCostbasis ) ;
mpz_clear ( mpzAverageCostbasis ) ;
}
betinfo . liquidationprice = 0 ;
if ( betinfo . leverage ! = 0 ) { // prevent zero div
betinfo . liquidationprice = betinfo . averageCostbasis - betinfo . averageCostbasis / betinfo . leverage ;
}
if ( betinfo . equity > = 0 )
betinfo . isRekt = true ;
else
{
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position not rekt " ) ) ;
return ( result ) ;
betinfo . isRekt = false ;
betinfo . rektfee = totalbets / 500 ;
}
mpz_clear ( mpzTotalbets ) ;
mpz_clear ( mpzTotalprofits ) ;
mpz_clear ( mpzTotalcostbasis ) ;
return 0 ;
}
else
return - 3 ;
}
return ( - 1 ) ;
}
// pricesrekt rpc: anyone can rekt a bet at some block where losses reached limit, collecting fee
UniValue PricesRekt ( int64_t txfee , uint256 bettxid , int32_t rektheight )
{
int32_t nextheight = komodo_nextheight ( ) ;
CMutableTransaction mtx = CreateNewContextualCMutableTransaction ( Params ( ) . GetConsensus ( ) , nextheight ) ; UniValue result ( UniValue : : VOBJ ) ;
struct CCcontract_info * cp , C ;
CTransaction bettx ;
/* uint256 hashBlock, tokenid, batontxid;
int64_t firstprice , lastprice = 0 , positionsize ;
int32_t firstheight ;
int16_t leverage ;
std : : vector < uint16_t > vec ; */
int64_t myfee = 0 ;
CPubKey pk , mypk , pricespk ;
std : : string rawtx ;
char destaddr [ 64 ] ;
cp = CCinit ( & C , EVAL_PRICES ) ;
if ( txfee = = 0 ) // TODO: what did we want tot do with txfee in prices?
txfee = PRICES_TXFEE ;
mypk = pubkey2pk ( Mypubkey ( ) ) ;
pricespk = GetUnspendable ( cp , 0 ) ;
GetCCaddress ( cp , destaddr , pricespk ) ;
BetInfo betinfo ;
int32_t retcode = prices_getbetinfo ( bettxid , betinfo ) ;
if ( retcode < 0 ) {
if ( retcode = = - 1 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant find bettxid or incorrect " ) ) ;
}
else if ( retcode = = - 2 ) {
throw std : : runtime_error ( " tx still in mempool " ) ;
}
else if ( retcode = = - 3 )
{
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant decode opret " ) ) ;
return ( result ) ;
}
else if ( retcode = = - 4 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " error scanning chain " ) ) ;
}
return ( result ) ;
}
int64_t totalbets = 0 ;
int64_t totalprofits = 0 ;
for ( auto b : betinfo . bets ) {
totalbets + = b . positionsize ;
totalprofits + = b . profits ;
}
if ( ! betinfo . isOpen ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position closed " ) ) ;
return result ;
}
prices_betjson ( result , betinfo . bets , betinfo . leverage , betinfo . lastheight , betinfo . lastprice ) ; // fill output
if ( betinfo . isRekt )
{
myfee = betinfo . rektfee ; // consolation fee for loss
}
if ( myfee ! = 0 )
{
int64_t CCchange = 0 , inputsum ;
mtx . vin . push_back ( CTxIn ( bettxid , NVOUT_CCMARKER , CScript ( ) ) ) ; // spend cc marker
if ( ( inputsum = AddPricesInputs ( cp , mtx , destaddr , myfee + txfee , 64 ) ) > myfee + txfee ) // TODO: why do we take txfee from global addr and not from user's addr?
CCchange = ( inputsum - myfee ) ;
mtx . vout . push_back ( CTxOut ( myfee , CScript ( ) < < ParseHex ( HexStr ( mypk ) ) < < OP_CHECKSIG ) ) ;
if ( CCchange > = txfee )
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , CCchange , pricespk ) ) ;
/// mtx.vout.push_back(MakeCC1vout(cp->evalcode, bettx.vout[2].nValue - myfee - txfee, pricespk)); // change
rawtx = FinalizeCCTx ( 0 , cp , mtx , mypk , txfee , prices_finalopret ( bettxid , totalprofits , rektheight , mypk , betinfo . firstprice , 0 , totalbets /*- positionsize*/ , 0 /*positionsize*/ , betinfo . leverage ) ) ;
return ( prices_rawtxresult ( result , rawtx , 0 ) ) ;
}
else
{
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position not rekt " ) ) ;
return ( result ) ;
}
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant load or incorrect bettx " ) ) ;
return ( result ) ;
}
// pricescashout rpc impl: bettor can cashout hit bet if it is not rekt
UniValue PricesCashout ( int64_t txfee , uint256 bettxid )
{
int32_t nextheight = komodo_nextheight ( ) ;
CMutableTransaction mtx = CreateNewContextualCMutableTransaction ( Params ( ) . GetConsensus ( ) , nextheight ) ; UniValue result ( UniValue : : VOBJ ) ;
CMutableTransaction mtx = CreateNewContextualCMutableTransaction ( Params ( ) . GetConsensus ( ) , nextheight ) ;
UniValue result ( UniValue : : VOBJ ) ;
struct CCcontract_info * cp , C ; char destaddr [ 64 ] ;
CTransaction bettx ;
/* CTransaction bettx;
uint256 hashBlock , batontxid , tokenid ;
int64_t CCchange = 0 , positionsize , inputsum , firstprice , lastprice = 0 ;
int64_t positionsize , firstprice , lastprice = 0 ;
int32_t firstheight ;
int16_t leverage ;
std : : vector < uint16_t > vec ;
std : : vector < uint16_t > vec ; */
int64_t CCchange = 0 , inputsum ;
CPubKey pk , mypk , pricespk ;
std : : string rawtx ;
@ -1644,204 +1771,127 @@ UniValue PricesCashout(int64_t txfee, uint256 bettxid)
mypk = pubkey2pk ( Mypubkey ( ) ) ;
pricespk = GetUnspendable ( cp , 0 ) ;
GetCCaddress ( cp , destaddr , pricespk ) ;
if ( myGetTransaction ( bettxid , bettx , hashBlock ) ! = 0 & & bettx . vout . size ( ) > 3 )
{
if ( prices_betopretdecode ( bettx . vout . back ( ) . scriptPubKey , pk , firstheight , positionsize , leverage , firstprice , vec , tokenid ) = = ' B ' )
{
uint256 finaltxid ;
int32_t vini ;
int32_t finalheight , endheight ;
std : : vector < BetInfo > bets ;
BetInfo bet1 ;
if ( CCgetspenttxid ( finaltxid , vini , finalheight , bettxid , N_CCMARKER ) = = 0 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position closed " ) ) ;
return result ;
}
bet1 . amount = positionsize ;
bet1 . firstheight = firstheight ;
bets . push_back ( bet1 ) ;
prices_enumaddedbets ( batontxid , bets , bettxid ) ;
if ( prices_scanchain ( bets , leverage , vec , lastprice , endheight ) < 0 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " error scanning chain " ) ) ;
return ( result ) ;
}
int64_t totalbets = 0 ;
int64_t totalprofits = 0 ;
for ( auto b : bets ) {
totalbets + = b . amount ;
totalprofits + = b . profits ;
}
prices_betjson ( result , bets , leverage , endheight , lastprice ) ; // fill output json
int64_t equity = totalbets + totalprofits ;
if ( equity < 0 )
{
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position rekt " ) ) ;
return ( result ) ;
}
mtx . vin . push_back ( CTxIn ( bettxid , N_CCMARKER , CScript ( ) ) ) ; // spend cc marker
if ( ( inputsum = AddPricesInputs ( cp , mtx , destaddr , equity + txfee , 64 ) ) > equity + txfee )
CCchange = ( inputsum - equity ) ;
mtx . vout . push_back ( CTxOut ( equity , CScript ( ) < < ParseHex ( HexStr ( mypk ) ) < < OP_CHECKSIG ) ) ;
if ( CCchange > = txfee )
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , CCchange , pricespk ) ) ;
rawtx = FinalizeCCTx ( 0 , cp , mtx , mypk , txfee , prices_finalopret ( bettxid , totalprofits , nextheight - 1 , mypk , firstprice , 0 , totalbets - positionsize , positionsize , leverage ) ) ;
return ( prices_rawtxresult ( result , rawtx , 0 ) ) ;
BetInfo betinfo ;
int32_t retcode = prices_getbetinfo ( bettxid , betinfo ) ;
if ( retcode < 0 ) {
if ( retcode = = - 1 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant find bettxid or incorrect " ) ) ;
}
else
else if ( retcode = = - 2 ) {
throw std : : runtime_error ( " tx still in mempool " ) ;
}
else if ( retcode = = - 3 )
{
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant decode opret " ) ) ;
return ( result ) ;
}
else if ( retcode = = - 4 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " error scanning chain " ) ) ;
}
return ( result ) ;
}
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant load or incorrect bettx " ) ) ;
return ( result ) ;
int64_t totalbets = 0 ;
int64_t totalprofits = 0 ;
for ( auto b : betinfo . bets ) {
totalbets + = b . positionsize ;
totalprofits + = b . profits ;
}
if ( ! betinfo . isOpen ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position closed " ) ) ;
return result ;
}
prices_betjson ( result , betinfo . bets , betinfo . leverage , betinfo . lastheight , betinfo . lastprice ) ; // fill output json
if ( betinfo . isRekt )
{
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " position rekt " ) ) ;
return ( result ) ;
}
mtx . vin . push_back ( CTxIn ( bettxid , NVOUT_CCMARKER , CScript ( ) ) ) ; // spend cc marker
if ( ( inputsum = AddPricesInputs ( cp , mtx , destaddr , betinfo . equity + txfee , 64 ) ) > betinfo . equity + txfee )
CCchange = ( inputsum - betinfo . equity ) ;
mtx . vout . push_back ( CTxOut ( betinfo . equity , CScript ( ) < < ParseHex ( HexStr ( mypk ) ) < < OP_CHECKSIG ) ) ;
if ( CCchange > = txfee )
mtx . vout . push_back ( MakeCC1vout ( cp - > evalcode , CCchange , pricespk ) ) ;
// TODO: what should the opret param be:
rawtx = FinalizeCCTx ( 0 , cp , mtx , mypk , txfee , prices_finalopret ( bettxid , totalprofits , nextheight - 1 , mypk , betinfo . firstprice , 0 , totalbets /*- betinfo.positionsize*/ , 0 /*betinfo.positionsize*/ , betinfo . leverage ) ) ;
return ( prices_rawtxresult ( result , rawtx , 0 ) ) ;
}
// pricesinfo rpc impl
UniValue PricesInfo ( uint256 bettxid , int32_t refheight )
{
UniValue result ( UniValue : : VOBJ ) ;
CTransaction bettx ;
/* CTransaction bettx;
uint256 hashBlock , batontxid , tokenid ;
int64_t positionsize = 0 , firstprice = 0 , lastprice = 0 ;
int32_t firstheight = 0 , endheight ;
int16_t leverage = 0 ;
std : : vector < uint16_t > vec ;
CPubKey pk , mypk , pricespk ;
std : : string rawtx ;
//uint256 costbasistxid;
std : : string rawtx ; */
if ( myGetTransaction ( bettxid , bettx , hashBlock ) & & bettx . vout . size ( ) > 3 )
{
if ( hashBlock . IsNull ( ) )
BetInfo betinfo ;
int32_t retcode = prices_getbetinfo ( bettxid , betinfo ) ;
if ( retcode < 0 ) {
if ( retcode = = - 1 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant find bettxid or incorrect " ) ) ;
}
else if ( retcode = = - 2 ) {
throw std : : runtime_error ( " tx still in mempool " ) ;
if ( prices_betopretdecode ( bettx . vout . back ( ) . scriptPubKey , pk , firstheight , positionsize , leverage , firstprice , vec , tokenid ) = = ' B ' )
}
else if ( retcode = = - 3 )
{
uint256 finaltxid ;
int32_t vini ;
int32_t finalheight , endheight ;
std : : vector < BetInfo > bets ;
BetInfo bet1 ;
if ( CCgetspenttxid ( finaltxid , vini , finalheight , bettxid , N_CCMARKER ) = = 0 )
result . push_back ( Pair ( " status " , " closed " ) ) ;
else
result . push_back ( Pair ( " status " , " open " ) ) ;
bet1 . amount = positionsize ;
bet1 . firstheight = firstheight ;
bets . push_back ( bet1 ) ;
prices_enumaddedbets ( batontxid , bets , bettxid ) ;
if ( prices_scanchain ( bets , leverage , vec , lastprice , endheight ) < 0 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " error scanning chain " ) ) ;
return ( result ) ;
}
mpz_t mpzTotalbets ;
mpz_t mpzTotalprofits ;
mpz_t mpzTotalcostbasis ;
mpz_init ( mpzTotalbets ) ;
mpz_init ( mpzTotalprofits ) ;
mpz_init ( mpzTotalcostbasis ) ;
int64_t totalbets = 0 ;
int64_t totalprofits = 0 ;
for ( auto b : bets ) {
mpz_t mpzProduct ;
mpz_t mpzProfits ;
mpz_init ( mpzProduct ) ;
mpz_init ( mpzProfits ) ;
//totalprofits += b.profits;
//dcostbasis += b.amount * (double)b.costbasis;
// costbasis += b.amount * (b.costbasis / PRICES_POINTFACTOR); // prevent int64 overflow (but we have underflow for 1/BTC)
// std::cerr << "PricesInfo() acc dcostbasis=" << dcostbasis << " b.amount=" << b.amount << " b.costbasis/PRICES_POINTFACTOR=" << (b.costbasis / PRICES_POINTFACTOR) << std::endl;
//std::cerr << "PricesInfo() acc dcostbasis=" << dcostbasis << " b.amount=" << b.amount << " b.costbasis/PRICES_POINTFACTOR=" << (b.costbasis / PRICES_POINTFACTOR) << std::endl;
mpz_set_ui ( mpzProduct , b . costbasis ) ;
mpz_mul_ui ( mpzProduct , mpzProduct , ( uint64_t ) b . amount ) ; // b.costbasis * b.amount
mpz_add ( mpzTotalcostbasis , mpzTotalcostbasis , mpzProduct ) ; //averageCostbasis += b.costbasis * b.amount;
mpz_add_ui ( mpzTotalbets , mpzTotalbets , ( uint64_t ) b . amount ) ; //totalbets += b.amount;
mpz_add ( mpzTotalprofits , mpzTotalprofits , mpzProfits ) ; //totalprofits += b.profits;
totalbets + = b . amount ;
totalprofits + = b . profits ;
mpz_clear ( mpzProduct ) ;
mpz_clear ( mpzProfits ) ;
}
int64_t equity = totalbets + totalprofits ;
int64_t averageCostbasis = 0 ;
if ( mpz_get_ui ( mpzTotalbets ) ! = 0 ) { //prevent zero div
mpz_t mpzAverageCostbasis ;
mpz_init ( mpzAverageCostbasis ) ;
//averageCostbasis = totalcostbasis / totalbets;
mpz_mul_ui ( mpzTotalcostbasis , mpzTotalcostbasis , SATOSHIDEN ) ; // profits *= SATOSHIDEN normalization to prevent loss of significance while division
mpz_tdiv_q ( mpzAverageCostbasis , mpzTotalcostbasis , mpzTotalbets ) ;
mpz_tdiv_q_ui ( mpzAverageCostbasis , mpzAverageCostbasis , SATOSHIDEN ) ; // profits /= SATOSHIDEN de-normalization
averageCostbasis = mpz_get_ui ( mpzAverageCostbasis ) ;
mpz_clear ( mpzAverageCostbasis ) ;
}
int64_t liqprice = 0 ;
if ( leverage ! = 0 ) { // prevent zero div
liqprice = averageCostbasis - averageCostbasis / leverage ;
}
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant decode opret " ) ) ;
return ( result ) ;
}
else if ( retcode = = - 4 ) {
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " error scanning chain " ) ) ;
}
return ( result ) ;
}
if ( equity > = 0 )
result . push_back ( Pair ( " rekt " , 0 ) ) ;
else
{
result . push_back ( Pair ( " rekt " , ( int64_t ) 1 ) ) ;
result . push_back ( Pair ( " rektfee " , totalbets / 500 ) ) ;
result . push_back ( Pair ( " rektheight " , ( int64_t ) end height) ) ;
}
if ( ! betinfo . isRekt )
result . push_back ( Pair ( " rekt " , 0 ) ) ;
else
{
result . push_back ( Pair ( " rekt " , ( int64_t ) 1 ) ) ;
result . push_back ( Pair ( " rektfee " , betinfo . rektfee ) ) ;
result . push_back ( Pair ( " rektheight " , betinfo . lastheight ) ) ;
}
std : : string expr = prices_getsourceexpression ( vec ) ;
result . push_back ( Pair ( " expression " , expr ) ) ;
result . push_back ( Pair ( " reduced " , prices_getreducedexpr ( expr ) ) ) ;
result . push_back ( Pair ( " batontxid " , batontxid . GetHex ( ) ) ) ;
result . push_back ( Pair ( " costbasis " , ValueFromAmount ( averageCostbasis ) ) ) ;
std : : string expr = prices_getsourceexpression ( betinfo . parsed ) ;
result . push_back ( Pair ( " expression " , expr ) ) ;
result . push_back ( Pair ( " reduced " , prices_getreducedexpr ( expr ) ) ) ;
// result.push_back(Pair("batontxid", batontxid.GetHex()));
result . push_back ( Pair ( " costbasis " , ValueFromAmount ( betinfo . averageCostbasis ) ) ) ;
# ifdef TESTMODE
result . push_back ( Pair ( " costbasis_test_period " , 7 ) ) ;
result . push_back ( Pair ( " costbasis_test_period " , 7 ) ) ;
# endif
prices_betjson ( result , bets , leverage , endheight , lastprice ) ;
prices_betjson ( result , betinfo . bets , betinfo . leverage , betinfo . lastheight , betinfo . lastprice ) ;
result . push_back ( Pair ( " LiquidationPrice " , ValueFromAmount ( liqprice ) ) ) ;
result . push_back ( Pair ( " LiquidationPrice " , ValueFromAmount ( betinfo . liquidationprice ) ) ) ;
mpz_clear ( mpzTotalbets ) ;
mpz_clear ( mpzTotalprofits ) ;
mpz_clear ( mpzTotalcostbasis ) ;
return ( result ) ;
}
}
result . push_back ( Pair ( " result " , " error " ) ) ;
result . push_back ( Pair ( " error " , " cant find bettxid or incorrect " ) ) ;
return ( result ) ;
}
@ -1852,25 +1902,20 @@ UniValue PricesList(uint32_t filter, CPubKey mypk)
std : : vector < std : : pair < CAddressIndexKey , CAmount > > addressIndex , addressIndexCC ;
struct CCcontract_info * cp , C ;
cp = CCinit ( & C , EVAL_PRICES ) ;
//pricespk = GetUnspendable(cp, 0);
// filters and outputs prices bet txid
auto pricesl ist = [ & ] ( std : : vector < std : : pair < CAddressIndexKey , CAmount > > : : const_iterator it , int32_t nvout )
auto AddBetToL ist = [ & ] ( uint256 txid )
{
int64_t amount , firstprice ;
int32_t height ;
int16_t leverage ;
uint256 txid , hashBlock , tokenid ;
uint256 hashBlock , tokenid ;
CPubKey pk , pricespk ;
std : : vector < uint16_t > vec ;
CTransaction vintx ;
txid = it - > first . txhash ;
if ( nvout ! = it - > first . index ) // our marker vout
return ;
if ( GetTransaction ( txid , vintx , hashBlock , false ) ! = 0 )
{
bool bAppend = false ;
@ -1884,7 +1929,7 @@ UniValue PricesList(uint32_t filter, CPubKey mypk)
int32_t height ;
uint256 finaltxid ;
int32_t spent = CCgetspenttxid ( finaltxid , vini , height , txid , N_CCMARKER ) ;
int32_t spent = CCgetspenttxid ( finaltxid , vini , height , txid , NVOUT _CCMARKER ) ;
if ( filter = = 1 & & spent < 0 | | // open positions
filter = = 2 & & spent = = 0 ) // closed positions
bAppend = true ;
@ -1892,7 +1937,7 @@ UniValue PricesList(uint32_t filter, CPubKey mypk)
if ( bAppend )
result . push_back ( txid . GetHex ( ) ) ;
}
std : : cerr < < " PricesList() " < < " bettxid= " < < txid . GetHex ( ) < < " mypk= " < < HexStr ( mypk ) < < " opretpk= " < < HexStr ( pk ) < < " filter= " < < filter < < " bAppend= " < < bAppend < < " index= " < < it - > first . index < < " txindex= " < < it - > first . txindex < < std : : endl ;
std : : cerr < < " PricesList() " < < " bettxid= " < < txid . GetHex ( ) < < " mypk= " < < HexStr ( mypk ) < < " opretpk= " < < HexStr ( pk ) < < " filter= " < < filter < < " bAppend= " < < bAppend < < std : : endl ;
}
} ;
@ -1900,7 +1945,8 @@ UniValue PricesList(uint32_t filter, CPubKey mypk)
SetCCtxids ( addressIndex , cp - > normaladdr , false ) ; // old normal marker
for ( std : : vector < std : : pair < CAddressIndexKey , CAmount > > : : const_iterator it = addressIndex . begin ( ) ; it ! = addressIndex . end ( ) ; it + + )
{
priceslist ( it , 3 ) ;
if ( it - > first . txindex = = NVOUT_NORMALMARKER )
AddBetToList ( it - > first . txhash ) ;
}
/* for future when switch to cc marker only
@ -1911,4 +1957,33 @@ UniValue PricesList(uint32_t filter, CPubKey mypk)
}
*/
return ( result ) ;
}
void prices_addbookentry ( uint256 txid )
{
BetInfo betinfo ;
//if( prices_getbetinfo(txid, betinfo) == 0 )
}
// walk through uxtos on the global address
// calculate the balance:
// + rekt positions
// = opposite positions
// - unbalanced positions
UniValue PricesGetOrderbook ( )
{
UniValue result ( UniValue : : VARR ) ;
std : : vector < std : : pair < CAddressIndexKey , CAmount > > addressIndex , addressIndexCC ;
struct CCcontract_info * cp , C ;
cp = CCinit ( & C , EVAL_PRICES ) ;
SetCCtxids ( addressIndex , cp - > normaladdr , false ) ; // old normal marker
for ( std : : vector < std : : pair < CAddressIndexKey , CAmount > > : : const_iterator it = addressIndex . begin ( ) ; it ! = addressIndex . end ( ) ; it + + )
{
if ( it - > first . txindex = = NVOUT_NORMALMARKER )
prices_addbookentry ( it - > first . txhash ) ;
}
return result ;
}