Hush Full Node software. We were censored from Github, this is where all development happens now. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1259 lines
52 KiB

/******************************************************************************
* Copyright © 2014-2019 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. *
* *
******************************************************************************/
5 years ago
#include "CCassets.h"
#include "CCPrices.h"
#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos)
5 years ago
/*
5 years ago
CBOPRET creates trustless oracles, which can be used for making a synthetic cash settlement system based on real world prices;
5 years ago
5 years ago
0.5% fee based on betamount, NOT leveraged betamount!!
0.1% collected by price basis determinant
0.2% collected by rekt tx
PricesBet -> +/-leverage, amount, synthetic -> opreturn includes current price
funds are locked into 1of2 global CC address
for first day, long basis is MAX(correlated,smoothed), short is MIN()
reference price is the smoothed of the previous block
if synthetic value + amount goes negative, then anybody can rekt it to collect a rektfee, proof of rekt must be included to show cost basis, rekt price
original creator can liquidate at anytime and collect (synthetic value + amount) from globalfund
0.5% of bet -> globalfund
PricesStatus -> bettxid maxsamples returns initial params, cost basis, amount left, rekt:true/false, rektheight, initial synthetic price, current synthetic price, net gain
PricesRekt -> bettxid height -> 0.1% to miner, rest to global CC
PricesClose -> bettxid returns (synthetic value + amount)
PricesList -> all bettxid -> list [bettxid, netgain]
*/
5 years ago
int32_t prices_syntheticprofits(int64_t &costbasis, int32_t firstheight, int32_t height, int16_t leverage, std::vector<uint16_t> vec, int64_t positionsize, int64_t addedbets, int64_t &profits, int64_t &outprice);
5 years ago
// helpers:
5 years ago
// returns true if there are only digits and no alphas or slashes in 's'
inline bool is_weight_str(std::string s) {
5 years ago
return
std::count_if(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c); } ) > 0 &&
5 years ago
std::count_if(s.begin(), s.end(), [](unsigned char c) { return std::isalpha(c) || c == '/'; } ) == 0;
5 years ago
}
5 years ago
// start of consensus code
5 years ago
CScript prices_betopret(CPubKey mypk,int32_t height,int64_t amount,int16_t leverage,int64_t firstprice,std::vector<uint16_t> vec,uint256 tokenid)
{
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << EVAL_PRICES << 'B' << mypk << height << amount << leverage << firstprice << vec << tokenid);
return(opret);
}
uint8_t prices_betopretdecode(CScript scriptPubKey,CPubKey &pk,int32_t &height,int64_t &amount,int16_t &leverage,int64_t &firstprice,std::vector<uint16_t> &vec,uint256 &tokenid)
{
5 years ago
std::vector<uint8_t> vopret; uint8_t e,f;
5 years ago
GetOpReturnData(scriptPubKey,vopret);
if (vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> pk; ss >> height; ss >> amount; ss >> leverage; ss >> firstprice; ss >> vec; ss >> tokenid) != 0 && e == EVAL_PRICES && f == 'B')
5 years ago
{
return(f);
}
return(0);
}
5 years ago
CScript prices_addopret(uint256 bettxid,CPubKey mypk,int64_t amount)
{
5 years ago
CScript opret;
5 years ago
opret << OP_RETURN << E_MARSHAL(ss << EVAL_PRICES << 'A' << bettxid << mypk << amount);
5 years ago
return(opret);
6 years ago
}
5 years ago
uint8_t prices_addopretdecode(CScript scriptPubKey,uint256 &bettxid,CPubKey &pk,int64_t &amount)
6 years ago
{
5 years ago
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> bettxid; ss >> pk; ss >> amount) != 0 && e == EVAL_PRICES && f == 'A' )
{
return(f);
}
5 years ago
return(0);
}
5 years ago
CScript prices_costbasisopret(uint256 bettxid,CPubKey mypk,int32_t height,int64_t costbasis)
{
5 years ago
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << EVAL_PRICES << 'C' << bettxid << mypk << height << costbasis);
return(opret);
}
5 years ago
5 years ago
uint8_t prices_costbasisopretdecode(CScript scriptPubKey,uint256 &bettxid,CPubKey &pk,int32_t &height,int64_t &costbasis)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> bettxid; ss >> pk; ss >> height; ss >> costbasis) != 0 && e == EVAL_PRICES && f == 'C' )
{
return(f);
}
return(0);
}
5 years ago
5 years ago
CScript prices_finalopret(uint256 bettxid,int64_t profits,int32_t height,CPubKey mypk,int64_t firstprice,int64_t costbasis,int64_t addedbets,int64_t positionsize,int16_t leverage)
{
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << EVAL_PRICES << 'F' << bettxid << profits << height << mypk << firstprice << costbasis << addedbets << positionsize << leverage);
return(opret);
}
uint8_t prices_finalopretdecode(CScript scriptPubKey,uint256 &bettxid,int64_t &profits,int32_t &height,CPubKey &pk,int64_t &firstprice,int64_t &costbasis,int64_t &addedbets,int64_t &positionsize,int16_t &leverage)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> bettxid; ss >> profits; ss >> height; ss >> pk; ss >> firstprice; ss >> costbasis; ss >> addedbets; ss >> positionsize; ss >> leverage) != 0 && e == EVAL_PRICES && f == 'F' )
5 years ago
{
5 years ago
return(f);
5 years ago
}
5 years ago
return(0);
}
// price opret basic validation and retrieval
static bool CheckPricesOpret(const CTransaction & tx, vscript_t &opret)
{
return tx.vout.size() > 0 && GetOpReturnData(tx.vout.back().scriptPubKey, opret) && opret.size() > 2 && opret.begin()[0] == EVAL_PRICES && IS_CHARINSTR(opret.begin()[1], "BACF");
}
// validate bet tx helper
static bool ValidateBetTx(struct CCcontract_info *cp, Eval *eval, const CTransaction & bettx)
{
uint256 tokenid;
int64_t positionsize, firstprice;
int32_t firstheight;
int16_t leverage;
CPubKey pk, pricespk;
std::vector<uint16_t> vec;
if (bettx.vout.size() < 5 || bettx.vout.size() > 6)
return eval->Invalid("incorrect vout number for bet tx");
vscript_t opret;
if( prices_betopretdecode(bettx.vout.back().scriptPubKey, pk, firstheight, positionsize, leverage, firstprice, vec, tokenid) != 'B')
return eval->Invalid("cannot decode opreturn for bet tx");
pricespk = GetUnspendable(cp, 0);
if (MakeCC1vout(cp->evalcode, bettx.vout[0].nValue, pk) != bettx.vout[0])
return eval->Invalid("cannot validate vout0 in bet tx with pk from opreturn");
if (MakeCC1vout(cp->evalcode, bettx.vout[1].nValue, pricespk) != bettx.vout[1])
return eval->Invalid("cannot validate vout1 in bet tx with global pk");
if( MakeCC1vout(cp->evalcode, bettx.vout[2].nValue, pricespk) != bettx.vout[2] )
return eval->Invalid("cannot validate vout2 in bet tx with pk from opreturn");
int64_t betamount = bettx.vout[2].nValue;
if( betamount != (positionsize * 199) / 200 )
return eval->Invalid("invalid position size in the opreturn");
// validate if normal inputs are really signed by originator pubkey (someone not cheating with originator pubkey)
CAmount ccOutputs = 0;
for (auto vout : bettx.vout)
if (vout.scriptPubKey.IsPayToCryptoCondition())
ccOutputs += vout.nValue;
CAmount normalInputs = TotalPubkeyNormalInputs(bettx, pk);
if (normalInputs < ccOutputs)
return eval->Invalid("bettx normal input signed with not pubkey in opret");
if (leverage > PRICES_MAXLEVERAGE || leverage < -PRICES_MAXLEVERAGE)
return eval->Invalid("invalid leverage");
return true;
}
// validate add funding tx helper
static bool ValidateAddFundingTx(struct CCcontract_info *cp, Eval *eval, const CTransaction & addfundingtx, const CTransaction & vintx)
{
uint256 bettxid;
int64_t amount;
CPubKey pk, pricespk;
vscript_t vintxOpret;
if (addfundingtx.vout.size() < 3 || addfundingtx.vout.size() > 4)
return eval->Invalid("incorrect vout number for add funding tx");
vscript_t opret;
if (prices_addopretdecode(addfundingtx.vout.back().scriptPubKey, bettxid, pk, amount) != 'A')
return eval->Invalid("cannot decode opreturn for add funding tx");
pricespk = GetUnspendable(cp, 0);
if (CheckPricesOpret(vintx, vintxOpret) && vintxOpret.begin()[1] == 'B' && vintx.GetHash() != bettxid) // if vintx is bettx
return eval->Invalid("incorrect bettx id");
if (MakeCC1vout(cp->evalcode, addfundingtx.vout[0].nValue, pk) != addfundingtx.vout[0])
return eval->Invalid("cannot validate vout0 in add funding tx with pk from opreturn");
if (MakeCC1vout(cp->evalcode, addfundingtx.vout[1].nValue, pricespk) != addfundingtx.vout[1])
return eval->Invalid("cannot validate vout1 in add funding tx with global pk");
return true;
}
// validate costbasis tx helper
static bool ValidateCostbasisTx(struct CCcontract_info *cp, Eval *eval, const CTransaction & costbasistx, const CTransaction & bettx)
{
uint256 bettxid;
int64_t costbasisInOpret;
CPubKey pk, pricespk;
int32_t height;
// check basic structure:
if (costbasistx.vout.size() < 3 || costbasistx.vout.size() > 4)
return eval->Invalid("incorrect vout count for costbasis tx");
vscript_t opret;
if (prices_costbasisopretdecode(costbasistx.vout.back().scriptPubKey, bettxid, pk, height, costbasisInOpret) != 'C')
return eval->Invalid("cannot decode opreturn for costbasis tx");
pricespk = GetUnspendable(cp, 0);
if (CTxOut(costbasistx.vout[0].nValue, CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG) != costbasistx.vout[0]) //might go to any pk who calculated costbasis
return eval->Invalid("cannot validate vout0 in costbasis tx with pk from opreturn");
if (MakeCC1vout(cp->evalcode, costbasistx.vout[1].nValue, pricespk) != costbasistx.vout[1])
return eval->Invalid("cannot validate vout1 in costbasis tx with global pk");
if (bettx.GetHash() != bettxid)
return eval->Invalid("incorrect bettx id");
if (bettx.vout.size() < 1) // for safety and for check encapsulation
return eval->Invalid("incorrect bettx no vouts");
// check costbasis rules:
if (costbasistx.vout[0].nValue > bettx.vout[1].nValue / 10)
return eval->Invalid("costbasis myfee too big");
uint256 tokenid;
int64_t positionsize, firstprice;
int32_t firstheight;
int16_t leverage;
CPubKey betpk;
std::vector<uint16_t> vec;
if (prices_betopretdecode(bettx.vout.back().scriptPubKey, betpk, firstheight, positionsize, leverage, firstprice, vec, tokenid) != 'B')
return eval->Invalid("cannot decode opreturn for bet tx");
if( firstheight + PRICES_DAYWINDOW + PRICES_SMOOTHWIDTH > chainActive.Height() )
return eval->Invalid("cannot calculate costbasis yet");
int64_t costbasis = 0, profits, lastprice;
int32_t retcode = prices_syntheticprofits(costbasis, firstheight, firstheight + PRICES_DAYWINDOW, leverage, vec, positionsize, 0, profits, lastprice);
if (retcode < 0)
return eval->Invalid("cannot calculate costbasis yet");
std::cerr << "ValidateCostbasisTx() costbasis=" << costbasis << " costbasisInOpret=" << costbasisInOpret << std::endl;
if( 0 && costbasis != costbasisInOpret )
return eval->Invalid("incorrect costbasis value");
return true;
}
// validate final tx helper
static bool ValidateFinalTx(struct CCcontract_info *cp, Eval *eval, const CTransaction & finaltx, const CTransaction & bettx)
{
uint256 bettxid;
int64_t amount;
CPubKey pk, pricespk;
int64_t profits;
int32_t height;
int64_t firstprice, costbasis, addedbets, positionsize;
int16_t leverage;
if (finaltx.vout.size() < 2 || finaltx.vout.size() > 3)
return eval->Invalid("incorrect vout number for final tx");
vscript_t opret;
if (prices_finalopretdecode(finaltx.vout.back().scriptPubKey, bettxid, profits, height, pk, firstprice, costbasis, addedbets, positionsize, leverage) != 'F')
return eval->Invalid("cannot decode opreturn for final tx");
if (bettx.GetHash() != bettxid)
return eval->Invalid("incorrect bettx id");
pricespk = GetUnspendable(cp, 0);
if (CTxOut(finaltx.vout[0].nValue, CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG) != finaltx.vout[0])
return eval->Invalid("cannot validate vout0 in final tx with pk from opreturn");
if( finaltx.vout.size() == 3 && MakeCC1vout(cp->evalcode, finaltx.vout[1].nValue, pricespk) != finaltx.vout[1] )
return eval->Invalid("cannot validate vout1 in final tx with global pk");
return true;
}
// validate prices tx function
// performed checks:
// basic tx structure (vout num)
// basic tx opret structure
// reference to the bet tx vout
// referenced bet txid in tx opret
// referenced bet tx structure
// non-final tx has only 1 cc vin
// cc vouts to self with mypubkey from opret
// cc vouts to global pk with global pk
// for bet tx that normal inputs digned with my pubkey from the opret >= cc outputs - disable betting for other pubkeys (Do we need this rule?)
// TODO:
// opret params (firstprice,positionsize...)
// costbasis calculation
// cashout balance (PricesExactAmounts)
// use the special address for 50% fees
5 years ago
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
vscript_t vopret;
if (strcmp(ASSETCHAINS_SYMBOL, "REKT0") == 0 && chainActive.Height() < 2965)
5 years ago
return true;
// check basic opret rules:
if (!CheckPricesOpret(tx, vopret))
return eval->Invalid("tx has no prices opreturn");
uint8_t funcId = vopret.begin()[1];
CTransaction firstVinTx;
vscript_t firstVinTxOpret;
bool foundFirst = false;
int32_t ccVinCount = 0;
uint32_t prevoutN = 0;
// check basic rules:
// find first cc vin and load vintx (might be either bet or add funding tx):
for (auto vin : tx.vin)
if (cp->ismyvin(vin.scriptSig)) {
CTransaction vintx;
uint256 hashBlock;
vscript_t vintxOpret;
5 years ago
if (!myGetTransaction(vin.prevout.hash, vintx, hashBlock))
return eval->Invalid("cannot load vintx");
if (!CheckPricesOpret(vintx, vintxOpret))
return eval->Invalid("cannot find prices opret in vintx");
if (vintxOpret.begin()[1] == 'B' && prevoutN == 3) {
return eval->Invalid("cannot spend bet marker");
}
if (!foundFirst) {
prevoutN = vin.prevout.n;
firstVinTx = vintx;
firstVinTxOpret = vintxOpret;
foundFirst = true;
}
ccVinCount++;
}
if (!foundFirst)
return eval->Invalid("prices cc vin not found");
if (funcId != 'F' && ccVinCount > 1) // for all prices tx except final tx only one cc vin is allowed
return eval->Invalid("only one prices cc vin allowed for this tx");
switch (funcId) {
case 'B': // bet
return eval->Invalid("unexpected validate for bet funcid");
case 'A': // add funding
// check tx structure:
if (!ValidateAddFundingTx(cp, eval, tx, firstVinTx))
return false; // invalid state is already set in the func
if (firstVinTxOpret.begin()[1] == 'B') {
if (!ValidateBetTx(cp, eval, firstVinTx)) // check tx structure
return false;
}
else if (firstVinTxOpret.begin()[1] == 'A') {
// no need to validate the previous addfunding tx (it was validated when added)
}
if (prevoutN != 0) { // check spending rules
return eval->Invalid("incorrect vintx vout to spend");
}
break;
case 'C': // set costbasis
if (!ValidateCostbasisTx(cp, eval, tx, firstVinTx))
return false;
if (!ValidateBetTx(cp, eval, firstVinTx))
return false;
if (prevoutN != 1) { // check spending rules
return eval->Invalid("incorrect vout to spend");
}
//return eval->Invalid("test: costbasis is good");
break;
case 'F': // final tx
if (!ValidateFinalTx(cp, eval, tx, firstVinTx))
return false;
if (!ValidateBetTx(cp, eval, firstVinTx))
return false;
if (prevoutN != 2) { // check spending rules
return eval->Invalid("incorrect vout to spend");
}
break;
default:
return eval->Invalid("invalid funcid");
}
5 years ago
return true;
5 years ago
}
// end of consensus code
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddPricesInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, char *destaddr, int64_t total, int32_t maxinputs, uint256 vintxid, int32_t vinvout)
5 years ago
{
int64_t nValue, price, totalinputs = 0; uint256 txid, hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout, n = 0;
5 years ago
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs, destaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++)
5 years ago
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if (vout == vinvout && txid == vintxid)
5 years ago
continue;
if (GetTransaction(txid, vintx, hashBlock, false) != 0 && vout < vintx.vout.size())
5 years ago
{
if ((nValue = vintx.vout[vout].nValue) >= total / maxinputs && myIsutxo_spentinmempool(ignoretxid, ignorevin, txid, vout) == 0)
5 years ago
{
if (total != 0 && maxinputs != 0)
mtx.vin.push_back(CTxIn(txid, vout, CScript()));
5 years ago
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs))
5 years ago
break;
}
}
}
return(totalinputs);
}
UniValue prices_rawtxresult(UniValue &result, std::string rawtx, int32_t broadcastflag)
5 years ago
{
CTransaction tx;
if (rawtx.size() > 0)
5 years ago
{
result.push_back(Pair("hex", rawtx));
if (DecodeHexTx(tx, rawtx) != 0)
5 years ago
{
if (broadcastflag != 0 && myAddtomempool(tx) != 0)
5 years ago
RelayTransaction(tx);
result.push_back(Pair("txid", tx.GetHash().ToString()));
result.push_back(Pair("result", "success"));
}
else
result.push_back(Pair("error", "decode hex"));
}
else
result.push_back(Pair("error", "couldnt finalize CCtx"));
5 years ago
return(result);
}
int32_t prices_syntheticvec(std::vector<uint16_t> &vec, std::vector<std::string> synthetic)
5 years ago
{
int32_t i, need, ind, depth = 0; std::string opstr; uint16_t opcode, weight;
5 years ago
if (synthetic.size() == 0) {
5 years ago
std::cerr << "prices_syntheticvec() expression is empty" << std::endl;
5 years ago
return(-1);
5 years ago
}
for (i = 0; i < synthetic.size(); i++)
5 years ago
{
5 years ago
need = 0;
opstr = synthetic[i];
if (opstr == "*")
5 years ago
opcode = PRICES_MULT, need = 2;
else if (opstr == "/")
5 years ago
opcode = PRICES_DIV, need = 2;
else if (opstr == "!")
5 years ago
opcode = PRICES_INV, need = 1;
else if (opstr == "**/")
5 years ago
opcode = PRICES_MMD, need = 3;
else if (opstr == "*//")
5 years ago
opcode = PRICES_MDD, need = 3;
else if (opstr == "***")
5 years ago
opcode = PRICES_MMM, need = 3;
else if (opstr == "///")
5 years ago
opcode = PRICES_DDD, need = 3;
else if (!is_weight_str(opstr) && (ind = komodo_priceind(opstr.c_str())) >= 0)
5 years ago
opcode = ind, need = 0;
else if ((weight = atoi(opstr.c_str())) > 0 && weight < KOMODO_MAXPRICES)
5 years ago
{
opcode = PRICES_WEIGHT | weight;
need = 1;
5 years ago
}
else {
5 years ago
std::cerr << "prices_syntheticvec() incorrect opcode=" << opstr << std::endl;
5 years ago
return(-2);
}
if (depth < need) {
5 years ago
std::cerr << "prices_syntheticvec() incorrect not enough operands for opcode=" << opstr << std::endl;
5 years ago
return(-3);
5 years ago
}
5 years ago
depth -= need;
std::cerr << "opcode=" << opcode << " opstr=" << opstr << " need=" << need << " depth=" << depth << std::endl;
5 years ago
if ((opcode & KOMODO_PRICEMASK) != PRICES_WEIGHT) { // skip weight
depth++; // increase operands count
std::cerr << "depth++=" << depth << std::endl;
}
5 years ago
if (depth > 3) {
5 years ago
std::cerr << "prices_syntheticvec() to many operands, last=" << opstr << std::endl;
5 years ago
return(-4);
5 years ago
}
5 years ago
vec.push_back(opcode);
5 years ago
}
if (depth != 0)
5 years ago
{
fprintf(stderr, "prices_syntheticvec() depth.%d not empty\n", depth);
5 years ago
return(-5);
5 years ago
}
5 years ago
return(0);
}
// calculates price for synthetic expression
5 years ago
int64_t prices_syntheticprice(std::vector<uint16_t> vec, int32_t height, int32_t minmax, int16_t leverage)
5 years ago
{
5 years ago
int32_t i, value, errcode, depth, retval = -1;
uint16_t opcode;
int64_t *pricedata, pricestack[4], price, den, a, b, c;
5 years ago
5 years ago
pricedata = (int64_t *)calloc(sizeof(*pricedata) * 3, 1 + PRICES_DAYWINDOW * 2 + PRICES_SMOOTHWIDTH);
5 years ago
price = den = depth = errcode = 0;
5 years ago
5 years ago
for (i = 0; i < vec.size(); i++)
5 years ago
{
5 years ago
opcode = vec[i];
5 years ago
value = (opcode & (KOMODO_MAXPRICES - 1)); // index or weight
5 years ago
std::cerr << "prices_syntheticprice" << " i=" << i << " price=" << price << " value=" << value << " depth=" << depth << std::endl;
5 years ago
switch (opcode & KOMODO_PRICEMASK)
5 years ago
{
5 years ago
case 0: // indices
pricestack[depth] = 0;
if (komodo_priceget(pricedata, value, height, 1) >= 0)
5 years ago
{
std::cerr << "prices_syntheticprice" << " pricedata[0]=" << pricedata[0] << " pricedata[1]=" << pricedata[1] << " pricedata[2]=" << pricedata[2] << std::endl;
5 years ago
// push price to the prices stack
if (!minmax)
pricestack[depth] = pricedata[2]; // use smoothed value if we are over 24h
else
5 years ago
{
5 years ago
// if we are within 24h use min or max price
if (leverage > 0)
pricestack[depth] = (pricedata[1] > pricedata[2]) ? pricedata[1] : pricedata[2]; // MAX
5 years ago
else
5 years ago
pricestack[depth] = (pricedata[1] < pricedata[2]) ? pricedata[1] : pricedata[2]; // MIN
5 years ago
}
5 years ago
}
if (pricestack[depth] == 0)
errcode = -1;
depth++;
break;
case PRICES_WEIGHT: // multiply by weight and consume top of stack by updating price
if (depth == 1) {
depth--;
price += pricestack[0] * value;
den += value; // acc weight value
}
else
errcode = -2;
break;
case PRICES_MULT:
if (depth >= 2) {
b = pricestack[--depth];
a = pricestack[--depth];
pricestack[depth++] = (a * b) / SATOSHIDEN;
}
else
errcode = -3;
break;
case PRICES_DIV:
if (depth >= 2) {
b = pricestack[--depth];
a = pricestack[--depth];
pricestack[depth++] = (a * SATOSHIDEN) / b;
}
else
errcode = -4;
break;
case PRICES_INV:
if (depth >= 1) {
a = pricestack[--depth];
pricestack[depth++] = (SATOSHIDEN * SATOSHIDEN) / a;
}
else
errcode = -5;
break;
case PRICES_MDD:
if (depth >= 3) {
c = pricestack[--depth];
b = pricestack[--depth];
a = pricestack[--depth];
pricestack[depth++] = (((a * SATOSHIDEN) / b) * SATOSHIDEN) / c;
}
else
errcode = -6;
break;
case PRICES_MMD:
if (depth >= 3) {
c = pricestack[--depth];
b = pricestack[--depth];
a = pricestack[--depth];
pricestack[depth++] = (a * b) / c;
}
else
errcode = -7;
break;
case PRICES_MMM:
if (depth >= 3) {
c = pricestack[--depth];
b = pricestack[--depth];
a = pricestack[--depth];
pricestack[depth++] = ((a * b) / SATOSHIDEN) * c;
}
else
errcode = -8;
break;
case PRICES_DDD:
if (depth >= 3) {
c = pricestack[--depth];
b = pricestack[--depth];
a = pricestack[--depth];
pricestack[depth++] = (((((SATOSHIDEN * SATOSHIDEN) / a) * SATOSHIDEN) / b) * SATOSHIDEN) / c;
}
else
errcode = -9;
break;
default:
errcode = -10;
break;
5 years ago
}
5 years ago
if (errcode != 0)
5 years ago
break;
5 years ago
5 years ago
std::cerr << "pricestack[depth=" << depth << "]=" << pricestack[depth] << std::endl;
5 years ago
5 years ago
}
5 years ago
free(pricedata);
5 years ago
if (errcode != 0)
5 years ago
std::cerr << "prices_syntheticprice warning: errcode in switch=" << errcode << std::endl;
5 years ago
5 years ago
if (den == 0) {
std::cerr << "prices_syntheticprice den==0 return err=-11" << std::endl;
5 years ago
return(-11);
5 years ago
}
else if (depth != 0) {
std::cerr << "prices_syntheticprice depth!=0 err=-12" << std::endl;
5 years ago
return(-12);
5 years ago
}
else if (errcode != 0) {
std::cerr << "prices_syntheticprice err=" << errcode << std::endl;
5 years ago
return(errcode);
5 years ago
}
5 years ago
std::cerr << "prices_syntheticprice price=" << price << " den=" << den << std::endl;
5 years ago
return(price / den);
}
// calculates profit/loss for the bet
int32_t prices_syntheticprofits(int64_t &costbasis, int32_t firstheight, int32_t height, int16_t leverage, std::vector<uint16_t> vec, int64_t positionsize, int64_t addedbets, int64_t &profits, int64_t &outprice)
5 years ago
{
5 years ago
int64_t price;
if (height < firstheight) {
fprintf(stderr, "requested height is lower than bet firstheight.%d\n", height);
return -1;
}
int32_t minmax = (height < firstheight + PRICES_DAYWINDOW); // if we are within 24h then use min or max value
if ((price = prices_syntheticprice(vec, height, minmax, leverage)) < 0)
{
fprintf(stderr, "error getting synthetic price at height.%d\n", height);
return -1;
}
// clear lowest positions:
price /= PRICES_NORMFACTOR;
price *= PRICES_NORMFACTOR;
5 years ago
outprice = price;
if (minmax) { // if we are within day window, set temp costbasis to max (or min) price value
if (leverage > 0 && price > costbasis) {
costbasis = price; // set temp costbasis
std::cerr << "prices_syntheticprofits() minmax costbasis=" << costbasis << " price=" << price << std::endl;
}
else if (leverage < 0 && (costbasis == 0 || price < costbasis)) {
costbasis = price;
std::cerr << "prices_syntheticprofits() minmax costbasis=" << costbasis << " price=" << price << std::endl;
}
else { //-> use the previous value
std::cerr << "prices_syntheticprofits() unchanged costbasis=" << costbasis << " price=" << price << " leverage=" << leverage << std::endl;
}
}
else {
if (costbasis == 0) {
// if costbasis not set, just set it
costbasis = price;
std::cerr << "prices_syntheticprofits() set costbasis=" << costbasis << std::endl;
}
else {
// use provided costbasis
std::cerr << "prices_syntheticprofits() provided costbasis=" << costbasis << " price=" << price << std::endl;
}
5 years ago
}
profits = costbasis > 0 ? (((price / PRICES_NORMFACTOR * SATOSHIDEN) / costbasis) - SATOSHIDEN / PRICES_NORMFACTOR) * PRICES_NORMFACTOR : 0;
std::cerr << "prices_syntheticprofits() test value1 (price/PRICES_NORMFACTOR * SATOSHIDEN)=" << (price / PRICES_NORMFACTOR * SATOSHIDEN) << std::endl;
std::cerr << "prices_syntheticprofits() test value2 (price/PRICES_NORMFACTOR * SATOSHIDEN)/costbasis=" << (costbasis != 0 ? (price / PRICES_NORMFACTOR * SATOSHIDEN)/costbasis : 0) << std::endl;
std::cerr << "prices_syntheticprofits() fractional profits=" << profits << std::endl;
//std::cerr << "prices_syntheticprofits() profits double=" << (double)price / (double)costbasis -1.0 << std::endl;
//double dprofits = (double)price / (double)costbasis - 1.0;
profits *= ((int64_t)leverage * (int64_t)positionsize);
profits /= (int64_t)SATOSHIDEN;
//dprofits *= leverage * positionsize;
std::cerr << "prices_syntheticprofits() value of profits=" << profits << std::endl;
//std::cerr << "prices_syntheticprofits() dprofits=" << dprofits << std::endl;
return 0; // (positionsize + addedbets + profits);
5 years ago
}
void prices_betjson(UniValue &result,int64_t profits,int64_t costbasis,int64_t positionsize,int64_t addedbets,int16_t leverage,int32_t firstheight,int64_t firstprice, int64_t lastprice, int64_t equity)
5 years ago
{
result.push_back(Pair("profits",ValueFromAmount(profits)));
result.push_back(Pair("costbasis",ValueFromAmount(costbasis)));
result.push_back(Pair("positionsize",ValueFromAmount(positionsize)));
result.push_back(Pair("equity", ValueFromAmount(equity)));
5 years ago
result.push_back(Pair("addedbets",ValueFromAmount(addedbets)));
result.push_back(Pair("leverage",(int64_t)leverage));
result.push_back(Pair("firstheight",(int64_t)firstheight));
result.push_back(Pair("firstprice",ValueFromAmount(firstprice)));
result.push_back(Pair("lastprice", ValueFromAmount(lastprice)));
5 years ago
}
// retrives costbasis from a tx spending bettx vout1
int64_t prices_costbasis(CTransaction bettx, uint256 &txidCostbasis)
5 years ago
{
int64_t costbasis = 0;
// if vout1 is spent, follow and extract costbasis from opreturn
//uint8_t prices_costbasisopretdecode(CScript scriptPubKey,uint256 &bettxid,CPubKey &pk,int32_t &height,int64_t &costbasis)
//uint256 txidCostbasis;
int32_t vini;
int32_t height;
txidCostbasis = zeroid;
if (CCgetspenttxid(txidCostbasis, vini, height, bettx.GetHash(), 1) < 0) {
std::cerr << "prices_costbasis() no costbasis txid found" << std::endl;
return 0;
}
5 years ago
CTransaction txCostbasis;
uint256 hashBlock;
uint256 bettxid;
CPubKey pk;
bool isLoaded = false;
uint8_t funcId = 0;
if ((isLoaded = myGetTransaction(txidCostbasis, txCostbasis, hashBlock)) &&
txCostbasis.vout.size() > 0 &&
(funcId = prices_costbasisopretdecode(txCostbasis.vout.back().scriptPubKey, bettxid, pk, height, costbasis)) != 0) {
return costbasis;
}
std::cerr << "prices_costbasis() cannot load costbasis tx or decode opret" << " isLoaded=" << isLoaded << " funcId=" << (int)funcId << std::endl;
return 0;
5 years ago
}
// calculates added bet total, returns the last baton txid
5 years ago
int64_t prices_batontxid(uint256 &batontxid, CTransaction bettx, uint256 bettxid)
5 years ago
{
int64_t addedbets = 0;
int32_t vini;
int32_t height;
int32_t retcode;
batontxid = bettxid; // initially set to the source bet tx
uint256 sourcetxid = bettxid;
5 years ago
// iterate through batons, adding up vout1 -> addedbets
5 years ago
while ((retcode = CCgetspenttxid(batontxid, vini, height, sourcetxid, 0)) == 0) {
CTransaction txBaton;
uint256 hashBlock;
uint256 bettxid;
CPubKey pk;
bool isLoaded = false;
uint8_t funcId = 0;
int64_t amount;
if ((isLoaded = myGetTransaction(batontxid, txBaton, hashBlock)) &&
txBaton.vout.size() > 0 &&
(funcId = prices_addopretdecode(txBaton.vout.back().scriptPubKey, bettxid, pk, amount)) != 0) {
addedbets += amount;
std::cerr << "prices_batontxid() added amount=" << amount << std::endl;
}
5 years ago
else {
std::cerr << "prices_batontxid() cannot load or decode add bet tx, isLoaded=" << isLoaded << " funcId=" << (int)funcId << std::endl;
return -1;
}
sourcetxid = batontxid;
}
5 years ago
return(addedbets);
}
UniValue PricesBet(int64_t txfee, int64_t amount, int16_t leverage, std::vector<std::string> synthetic)
5 years ago
{
int32_t nextheight = komodo_nextheight();
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ);
struct CCcontract_info *cp, C;
CPubKey pricespk, mypk;
int64_t betamount, firstprice;
std::vector<uint16_t> vec;
//char myaddr[64];
std::string rawtx;
if (leverage > PRICES_MAXLEVERAGE || leverage < -PRICES_MAXLEVERAGE)
5 years ago
{
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "leverage too big"));
5 years ago
return(result);
5 years ago
}
cp = CCinit(&C, EVAL_PRICES);
if (txfee == 0)
5 years ago
txfee = PRICES_TXFEE;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp, 0);
//GetCCaddress(cp, myaddr, mypk);
if (prices_syntheticvec(vec, synthetic) < 0 || (firstprice = prices_syntheticprice(vec, nextheight - 1, 1, leverage)) < 0 || vec.size() == 0 || vec.size() > 4096)
5 years ago
{
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid synthetic"));
5 years ago
return(result);
5 years ago
}
if (AddNormalinputs(mtx, mypk, amount + 5 * txfee, 64) >= amount + 5 * txfee)
5 years ago
{
5 years ago
betamount = (amount * 199) / 200;
mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, mypk)); // vout0 baton for total funding
5 years ago
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, betamount, pricespk));
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG)); // marker
rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_betopret(mypk, nextheight - 1, amount, leverage, firstprice, vec, zeroid));
return(prices_rawtxresult(result, rawtx, 0));
5 years ago
}
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "not enough funds"));
5 years ago
return(result);
5 years ago
}
UniValue PricesAddFunding(int64_t txfee, uint256 bettxid, int64_t amount)
5 years ago
{
5 years ago
int32_t nextheight = komodo_nextheight();
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ);
struct CCcontract_info *cp, C; CTransaction bettx;
CPubKey pricespk, mypk;
//int64_t addedbets = 0, betamount, firstprice;
std::vector<uint16_t> vec;
uint256 batontxid;
std::string rawtx;
//char myaddr[64];
cp = CCinit(&C, EVAL_PRICES);
if (txfee == 0)
5 years ago
txfee = PRICES_TXFEE;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp, 0);
//GetCCaddress(cp, myaddr, mypk);
5 years ago
if (AddNormalinputs(mtx, mypk, amount + 2*txfee, 64) >= amount + 2*txfee)
5 years ago
{
if (prices_batontxid(batontxid, bettx, bettxid) >= 0)
5 years ago
{
mtx.vin.push_back(CTxIn(batontxid, 0, CScript()));
mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, mypk)); // baton for total funding
mtx.vout.push_back(MakeCC1vout(cp->evalcode, amount, pricespk));
rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_addopret(bettxid, mypk, amount));
return(prices_rawtxresult(result, rawtx, 0));
5 years ago
}
else
{
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "couldnt find batonttxid"));
5 years ago
return(result);
}
5 years ago
}
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "not enough funds"));
5 years ago
return(result);
}
// set cost basis (open price) for the bet
UniValue PricesSetcostbasis(int64_t txfee, uint256 bettxid)
5 years ago
{
5 years ago
int32_t nextheight = komodo_nextheight();
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight);
UniValue result(UniValue::VOBJ);
struct CCcontract_info *cp, C; CTransaction bettx; uint256 hashBlock, batontxid, tokenid;
int64_t myfee, positionsize = 0, addedbets, firstprice = 0, lastprice, profits = 0, costbasis = 0, equity;
int32_t i, firstheight = 0, height, numvouts; int16_t leverage = 0;
std::vector<uint16_t> vec;
CPubKey pk, mypk, pricespk; std::string rawtx;
cp = CCinit(&C, EVAL_PRICES);
if (txfee == 0)
5 years ago
txfee = PRICES_TXFEE;
5 years ago
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp, 0);
if (myGetTransaction(bettxid, bettx, hashBlock) != 0 && (numvouts = bettx.vout.size()) > 3)
5 years ago
{
if (prices_betopretdecode(bettx.vout[numvouts - 1].scriptPubKey, pk, firstheight, positionsize, leverage, firstprice, vec, tokenid) == 'B')
5 years ago
{
if (nextheight <= firstheight + PRICES_DAYWINDOW + 1) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cannot calculate costbasis yet"));
return(result);
}
addedbets = prices_batontxid(batontxid, bettx, bettxid);
mtx.vin.push_back(CTxIn(bettxid, 1, CScript())); // spend vin1 with betamount
//for (i = 0; i < PRICES_DAYWINDOW + 1; i++) // the last datum for 24h is the actual costbasis value
//{
int32_t retcode = prices_syntheticprofits(costbasis, firstheight, firstheight + PRICES_DAYWINDOW, leverage, vec, positionsize, addedbets, profits, lastprice);
if (retcode < 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cannot calculate costbasis error getting price"));
return(result);
}
equity = positionsize + addedbets + profits;
/*if (equity < 0)
{ // we are in loss
result.push_back(Pair("rekt", (int64_t)1));
result.push_back(Pair("rektheight", (int64_t)firstheight + i));
5 years ago
break;
}*/
//}
//if (i == PRICES_DAYWINDOW + 1)
// result.push_back(Pair("rekt", 0));
prices_betjson(result, profits, costbasis, positionsize, addedbets, leverage, firstheight, firstprice, lastprice, equity);
if (AddNormalinputs(mtx, mypk, txfee, 4) >= txfee)
{
myfee = bettx.vout[1].nValue / 10; // fee for setting costbasis
result.push_back(Pair("myfee", myfee));
mtx.vout.push_back(CTxOut(myfee, CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(MakeCC1vout(cp->evalcode, bettx.vout[1].nValue - myfee, pricespk));
rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_costbasisopret(bettxid, mypk, firstheight + PRICES_DAYWINDOW /*- 1*/, costbasis));
return(prices_rawtxresult(result, rawtx, 0));
}
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "not enough funds"));
return(result);
5 years ago
}
5 years ago
}
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cant find bettxid"));
5 years ago
return(result);
}
UniValue PricesRekt(int64_t txfee, uint256 bettxid, int32_t rektheight)
5 years ago
{
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, positionsize, addedbets, firstprice, lastprice, profits, ignore, costbasis = 0, equity;
int32_t firstheight, numvouts;
int16_t leverage;
std::vector<uint16_t> vec;
CPubKey pk, mypk, pricespk;
std::string rawtx;
cp = CCinit(&C, EVAL_PRICES);
if (txfee == 0)
5 years ago
txfee = PRICES_TXFEE;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp, 0);
if (myGetTransaction(bettxid, bettx, hashBlock) != 0 && (numvouts = bettx.vout.size()) > 3)
5 years ago
{
if (prices_betopretdecode(bettx.vout[numvouts - 1].scriptPubKey, pk, firstheight, positionsize, leverage, firstprice, vec, tokenid) == 'B')
5 years ago
{
uint256 costbasistxid;
costbasis = prices_costbasis(bettx, costbasistxid);
if (costbasis == 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "costbasis not defined yet"));
return(result);
}
addedbets = prices_batontxid(batontxid, bettx, bettxid);
int32_t retcode = prices_syntheticprofits(costbasis, firstheight, rektheight, leverage, vec, positionsize, addedbets, profits, lastprice);
if (retcode < 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cannot get price"));
return(result);
}
equity = positionsize + addedbets + profits;
if (equity < 0)
5 years ago
{
5 years ago
myfee = (positionsize + addedbets) / 500;
}
prices_betjson(result, profits, costbasis, positionsize, addedbets, leverage, firstheight, firstprice, lastprice, equity);
if (myfee != 0)
5 years ago
{
mtx.vin.push_back(CTxIn(bettxid, 2, CScript()));
mtx.vout.push_back(CTxOut(myfee, CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(MakeCC1vout(cp->evalcode, bettx.vout[2].nValue - myfee - txfee, pricespk));
rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, prices_finalopret(bettxid, profits, rektheight, mypk, firstprice, costbasis, addedbets, positionsize, leverage));
return(prices_rawtxresult(result, rawtx, 0));
5 years ago
}
else
{
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "position not rekt"));
5 years ago
return(result);
5 years ago
}
}
else
{
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cant decode opret"));
5 years ago
return(result);
5 years ago
}
}
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cant find bettxid"));
5 years ago
return(result);
}
UniValue PricesCashout(int64_t txfee, uint256 bettxid)
6 years ago
{
5 years ago
int32_t nextheight = komodo_nextheight();
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ);
struct CCcontract_info *cp, C; char destaddr[64];
CTransaction bettx;
uint256 hashBlock, batontxid, tokenid;
int64_t CCchange = 0, positionsize, inputsum, ignore, addedbets, firstprice, lastprice, profits, costbasis = 0, equity;
int32_t i, firstheight, height, numvouts;
int16_t leverage;
std::vector<uint16_t> vec;
CPubKey pk, mypk, pricespk;
std::string rawtx;
cp = CCinit(&C, EVAL_PRICES);
if (txfee == 0)
5 years ago
txfee = PRICES_TXFEE;
5 years ago
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp, 0);
GetCCaddress(cp, destaddr, pricespk);
if (myGetTransaction(bettxid, bettx, hashBlock) != 0 && (numvouts = bettx.vout.size()) > 3)
5 years ago
{
if (prices_betopretdecode(bettx.vout[numvouts - 1].scriptPubKey, pk, firstheight, positionsize, leverage, firstprice, vec, tokenid) == 'B')
5 years ago
{
uint256 costbasistxid;
costbasis = prices_costbasis(bettx, costbasistxid);
if (costbasis == 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "costbasis not defined yet"));
return(result);
}
addedbets = prices_batontxid(batontxid, bettx, bettxid);
int32_t retcode = prices_syntheticprofits(costbasis, firstheight, nextheight - 1, leverage, vec, positionsize, addedbets, profits, lastprice);
if (retcode < 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cannot get price"));
return(result);
}
equity = positionsize + addedbets + profits;
if (equity < 0)
5 years ago
{
prices_betjson(result, profits, costbasis, positionsize, addedbets, leverage, firstheight, firstprice, lastprice, equity);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "position rekt"));
5 years ago
return(result);
5 years ago
}
prices_betjson(result, profits, costbasis, positionsize, addedbets, leverage, firstheight, firstprice, lastprice, equity);
mtx.vin.push_back(CTxIn(bettxid, 2, CScript()));
if ((inputsum = AddPricesInputs(cp, mtx, destaddr, profits + txfee, 64, bettxid, 2)) > profits + txfee)
5 years ago
CCchange = (inputsum - profits);
mtx.vout.push_back(CTxOut(bettx.vout[2].nValue + profits, 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, profits, nextheight - 1, mypk, firstprice, costbasis, addedbets, positionsize, leverage));
return(prices_rawtxresult(result, rawtx, 0));
5 years ago
}
else
{
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cant decode opret"));
5 years ago
return(result);
5 years ago
}
}
return(result);
6 years ago
}
UniValue PricesInfo(uint256 bettxid, int32_t refheight)
{
UniValue result(UniValue::VOBJ);
CTransaction bettx;
uint256 hashBlock, batontxid, tokenid;
int64_t myfee, ignore = 0, positionsize = 0, addedbets = 0, firstprice = 0, lastprice, profits = 0, costbasis = 0, equity;
int32_t i, firstheight = 0, height, numvouts;
int16_t leverage = 0;
std::vector<uint16_t> vec;
CPubKey pk, mypk, pricespk;
5 years ago
std::string rawtx;
uint256 costbasistxid;
5 years ago
if (myGetTransaction(bettxid, bettx, hashBlock) != 0 && (numvouts = bettx.vout.size()) > 3)
5 years ago
{
if (hashBlock.IsNull())
throw std::runtime_error("tx still in mempool");
if (prices_betopretdecode(bettx.vout[numvouts - 1].scriptPubKey, pk, firstheight, positionsize, leverage, firstprice, vec, tokenid) == 'B')
5 years ago
{
// check acceptable refheight:
if (refheight < 0 || refheight > 0 && refheight < firstheight) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "incorrect height"));
return(result);
}
if (refheight == 0)
refheight = komodo_nextheight()-1;
costbasis = prices_costbasis(bettx, costbasistxid);
addedbets = prices_batontxid(batontxid, bettx, bettxid);
if (costbasis != 0) { // costbasis fixed
int32_t retcode = prices_syntheticprofits(costbasis, firstheight, refheight, leverage, vec, positionsize, addedbets, profits, lastprice);
if (retcode < 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cannot get price"));
return(result);
}
equity = positionsize + addedbets + profits;
if (equity < 0)
{
result.push_back(Pair("rekt", 1));
result.push_back(Pair("rektfee", (positionsize + addedbets) / 500));
result.push_back(Pair("rektheight", (int64_t)refheight));
}
else
result.push_back(Pair("rekt", 0));
}
else {
bool isRekt = false;
for (i = 0; i < PRICES_DAYWINDOW + 1 && firstheight + i <= refheight; i++) // the last datum for 24h is the costbasis value
{
int32_t retcode = prices_syntheticprofits(costbasis, firstheight, firstheight + i, leverage, vec, positionsize, addedbets, profits, lastprice);
if (retcode < 0) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cannot get price"));
return(result);
}
equity = positionsize + addedbets + profits;
if (equity < 0)
{ // we are in loss
result.push_back(Pair("rekt", (int64_t)1));
result.push_back(Pair("rektfee", (positionsize + addedbets) / 500));
result.push_back(Pair("rektheight", (int64_t)firstheight + i));
isRekt = true;
break;
}
}
if (!isRekt /*i == PRICES_DAYWINDOW + 1*/)
result.push_back(Pair("rekt", 0));
}
result.push_back(Pair("batontxid", batontxid.GetHex()));
if(!costbasistxid.IsNull())
result.push_back(Pair("costbasistxid", costbasistxid.GetHex()));
prices_betjson(result, profits, costbasis, positionsize, addedbets, leverage, firstheight, firstprice, lastprice, equity);
result.push_back(Pair("height", (int64_t)refheight));
#ifdef TESTMODE
result.push_back(Pair("test_daywindow", PRICES_DAYWINDOW));
#endif
5 years ago
return(result);
}
}
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "cant find bettxid"));
5 years ago
return(result);
}
6 years ago
UniValue PricesList(uint32_t filter, CPubKey mypk)
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
struct CCcontract_info *cp, C;
int64_t amount, firstprice; int32_t height; int16_t leverage; uint256 txid, hashBlock, tokenid;
CPubKey pk, pricespk;
std::vector<uint16_t> vec;
CTransaction vintx;
cp = CCinit(&C, EVAL_PRICES);
pricespk = GetUnspendable(cp, 0);
5 years ago
SetCCtxids(addressIndex, cp->normaladdr, false);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it = addressIndex.begin(); it != addressIndex.end(); it++)
{
txid = it->first.txhash;
if (GetTransaction(txid, vintx, hashBlock, false) != 0)
{
bool bAppend = false;
if (vintx.vout.size() > 0 && prices_betopretdecode(vintx.vout[vintx.vout.size() - 1].scriptPubKey, pk, height, amount, leverage, firstprice, vec, tokenid) == 'B' &&
(mypk == CPubKey() || mypk == pk)) // if only mypubkey to list
{
if (filter == 0)
bAppend = true;
else {
int32_t vini;
int32_t height;
uint256 finaltxid;
int32_t spent = CCgetspenttxid(finaltxid, vini, height, txid, 2);
if (filter == 1 && spent < 0 || // open positions
filter == 2 && spent == 0) // closed positions
bAppend = true;
}
if (bAppend)
result.push_back(txid.GetHex());
}
std::cerr << "PricesList() " << " bettxid=" << txid.GetHex() << " mypk=" << HexStr(mypk) << " opret pk=" << HexStr(pk) << " filter=" << filter << " bAppend=" << bAppend << std::endl;
}
}
return(result);
}