Split Asset contract into Tokens and Assets

This commit is contained in:
dimxy
2019-01-07 23:19:47 +05:00
parent 4582a08461
commit 8e8a94404f
17 changed files with 3591 additions and 591 deletions

View File

@@ -14,6 +14,8 @@
******************************************************************************/
#include "CCassets.h"
//#include "CCtokens.h"
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
{
@@ -21,25 +23,31 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs!=0?maxinputs:64);
threshold = total/(maxinputs!=0?maxinputs:64); // TODO: is maxinputs really not over 64, what if i want to calc total balance?
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
if (it->second.satoshis < threshold)
continue;
for (j=0; j<mtx.vin.size(); j++)
if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
if (txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n)
break;
if ( j != mtx.vin.size() )
if( j != mtx.vin.size() )
continue;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
if( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
if( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
continue;
fprintf(stderr,"AddAssetInputs() check destaddress=%s vout amount=%.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN);
if ( (nValue= IsAssetvout(1, cp, NULL, price,origpubkey,vintx,vout,assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if( (nValue = IsAssetvout(cp, price, origpubkey, vintx, vout, assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -57,12 +65,13 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
return(totalinputs);
}
int64_t GetAssetBalance(CPubKey pk,uint256 tokenid)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_ASSETS);
return(AddAssetInputs(cp,mtx,pk,tokenid,0,0));
cp = CCinit(&C,EVAL_TOKENS);
return(AddTokenCCInputs(cp,mtx,pk,tokenid,0,0));
}
UniValue AssetInfo(uint256 assetid)
@@ -75,11 +84,11 @@ UniValue AssetInfo(uint256 assetid)
result.push_back(Pair("error","cant find assetid"));
return(result);
}
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
if ( vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
{
fprintf(stderr,"assetid isnt assetcreation txid\n");
fprintf(stderr,"assetid isnt token creation txid\n");
result.push_back(Pair("result","error"));
result.push_back(Pair("error","assetid isnt assetcreation txid"));
result.push_back(Pair("error","assetid isnt token creation txid"));
}
result.push_back(Pair("result","success"));
result.push_back(Pair("tokenid",uint256_str(str,assetid)));
@@ -92,15 +101,20 @@ UniValue AssetInfo(uint256 assetid)
UniValue AssetList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[65];
cp = CCinit(&C,EVAL_ASSETS);
UniValue result(UniValue::VARR);
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
struct CCcontract_info *cp,C; uint256 txid,hashBlock;
CTransaction vintx; std::vector<uint8_t> origpubkey;
std::string name,description; char str[65];
cp = CCinit(&C,EVAL_TOKENS);
SetCCtxids(addressIndex,cp->normaladdr);
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 )
{
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 )
if ( vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 )
{
result.push_back(uint256_str(str,txid));
}
@@ -112,17 +126,33 @@ UniValue AssetList()
UniValue AssetOrders(uint256 refassetid)
{
static uint256 zero;
int64_t price; uint256 txid,hashBlock,assetid,assetid2; std::vector<uint8_t> origpubkey; CTransaction vintx; UniValue result(UniValue::VARR); std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; uint8_t funcid; char numstr[32],funcidstr[16],origaddr[64],assetidstr[65]; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_ASSETS);
SetCCunspents(unspentOutputs,(char *)cp->unspendableCCaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
UniValue result(UniValue::VARR);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsAssets;
struct CCcontract_info *cpTokens, tokensC;
struct CCcontract_info *cpAssets, assetsC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
auto addOrders = [&](struct CCcontract_info *cp, std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it)
{
uint256 txid, hashBlock, assetid, assetid2;
int64_t price;
std::vector<uint8_t> origpubkey;
CTransaction vintx;
uint8_t funcid, evalCode;
char numstr[32], funcidstr[16], origaddr[64], assetidstr[65];
txid = it->first.txhash;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
//std::cerr << "addOrders txid" << txid.GetHex() << std::endl;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey)) != 0 )
funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey);
//std::cerr << "addOrders vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << std::endl;
if (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
{
if ( refassetid != zero && assetid != refassetid )
if (refassetid != zero && assetid != refassetid)
{
//int32_t z;
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]);
@@ -131,11 +161,13 @@ UniValue AssetOrders(uint256 refassetid)
//fprintf(stderr," assetid\n");
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]);
//fprintf(stderr," refassetid\n");
continue;
return;
}
if ( vintx.vout[it->first.index].nValue == 0 )
continue;
if (vintx.vout[it->first.index].nValue == 0)
return;
UniValue item(UniValue::VOBJ);
funcidstr[0] = funcid;
funcidstr[1] = 0;
item.push_back(Pair("funcid", funcidstr));
@@ -157,8 +189,8 @@ UniValue AssetOrders(uint256 refassetid)
}
if ( origpubkey.size() == 33 )
{
GetCCaddress(cp,origaddr,pubkey2pk(origpubkey));
item.push_back(Pair("origaddress",origaddr));
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey)); // TODO: what is this? is it asset or token??
item.push_back(Pair("origaddress", origaddr));
}
if ( assetid != zeroid )
item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
@@ -184,11 +216,27 @@ UniValue AssetOrders(uint256 refassetid)
//fprintf(stderr,"func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN);
}
}
}
};
SetCCunspents(unspentOutputsTokens, (char *)cpTokens->unspendableCCaddr);
SetCCunspents(unspentOutputsAssets, (char *)cpAssets->unspendableCCaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
itTokens != unspentOutputsTokens.end();
itTokens++)
addOrders(cpTokens, itTokens);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itAssets = unspentOutputsAssets.begin();
itAssets != unspentOutputsAssets.end();
itAssets++)
addOrders(cpAssets, itAssets);
return(result);
}
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
// not used (use TokenCreate instead)
/* std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; struct CCcontract_info *cp,C;
@@ -213,9 +261,10 @@ std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetCreateOpRet('c',Mypubkey(),name,description)));
}
return("");
}
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
} */
// not used (use TokenTransfer instead)
/* std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
@@ -230,11 +279,11 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
{
/*n = outputs.size();
if ( n == amounts.size() )
{
for (i=0; i<n; i++)
total += amounts[i];*/
//n = outputs.size();
//if ( n == amounts.size() )
//{
// for (i=0; i<n; i++)
// total += amounts[i];
mask = ~((1LL << mtx.vin.size()) - 1);
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
{
@@ -254,9 +303,10 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
}
return("");
}
} */
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
// deprecated
/* std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
@@ -281,76 +331,106 @@ std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> dest
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
}
return("");
}
} */
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
// rpc tokenbid implementation, locks 'bidamount' coins for the 'pricetotal' of tokens
std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, int64_t pricetotal)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( bidamount < 0 || pricetotal < 0 )
CPubKey mypk;
struct CCcontract_info *cpAssets, C;
uint256 hashBlock;
CTransaction vintx;
std::vector<uint8_t> origpubkey;
std::string name,description;
int64_t inputs;
std::cerr << "CreateBuyOffer() bidamount=" << bidamount << " numtokens(pricetotal)=" << pricetotal << std::endl;
if (bidamount < 0 || pricetotal < 0)
{
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal);
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n", (long long)bidamount, (long long)pricetotal);
return("");
}
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
if (GetTransaction(assetid, vintx, hashBlock, false) == 0)
{
fprintf(stderr,"cant find assetid\n");
return("");
}
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, origpubkey, name, description) == 0)
{
fprintf(stderr,"assetid isnt assetcreation txid\n");
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
if ( txfee == 0 )
cpAssets = CCinit(&C,EVAL_ASSETS); // NOTE: assets here!
if (txfee == 0)
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 )
if ((inputs = AddNormalinputs(mtx, mypk, bidamount+txfee, 64)) > 0)
{
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount,GetUnspendable(cp,0)));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('b',assetid,zeroid,pricetotal,Mypubkey())));
std::cerr << "CreateBuyOffer() inputs=" << inputs << std::endl;
if (inputs < bidamount+txfee) {
std::cerr << "CreateBuyOffer(): insufficient coins to make buy offer" << std::endl;
CCerror = strprintf("insufficient coins to make buy offer");
return ("");
}
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, GetUnspendable(cpAssets,0)));
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, Mypubkey())));
}
CCerror = strprintf("no coins found to make buy offer");
return("");
}
// rpc tokenask implementation, locks 'askamount' tokens for the 'pricetotal'
std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
CPubKey mypk;
uint64_t mask;
int64_t inputs, CCchange;
CScript opret;
struct CCcontract_info *cp,C;
//std::cerr << "CreateSell() askamount=" << askamount << " pricetotal=" << pricetotal << std::endl;
if ( askamount < 0 || pricetotal < 0 )
{
if (askamount < 0 || pricetotal < 0) {
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
cp = CCinit(&C, EVAL_TOKENS); // NOTE: tokens is here
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
if ((inputs = AddTokenCCInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
{
if (inputs < askamount) {
//askamount = inputs;
//was: askamount = inputs;
std::cerr << "CreateSell(): insufficient tokens for ask" << std::endl;
CCerror = strprintf("insufficient tokens for ask");
return ("");
}
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
if ( inputs > askamount )
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,askamount, GetUnspendable(cp,0)));
if (inputs > askamount)
CCchange = (inputs - askamount);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk));
opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, Mypubkey());
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
}
else {
fprintf(stderr, "need some assets to place ask\n");
fprintf(stderr, "need some tokens to place ask\n");
}
}
else { // dimxy added 'else', because it was misleading message before
@@ -363,34 +443,48 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
//////////////////////////////////////////
fprintf(stderr,"asset swaps disabled\n");
return("");
//////////////////////////////////////////
if ( askamount < 0 || pricetotal < 0 )
{
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
cp = CCinit(&C, EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
{
if ( inputs < askamount )
askamount = inputs;
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
if ( inputs > askamount )
if (inputs < askamount) {
//was: askamount = inputs;
std::cerr << "CreateSwap(): insufficient tokens for ask" << std::endl;
CCerror = strprintf("insufficient tokens for ask");
return ("");
}
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, GetUnspendable(cp, 0)));
if (inputs > askamount)
CCchange = (inputs - askamount);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
if ( assetid2 == zeroid )
opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk));
if (assetid2 == zeroid)
opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, Mypubkey());
else
{
opret = EncodeAssetOpRet('e',assetid,assetid2,pricetotal,Mypubkey());
opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, Mypubkey());
}
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
}
@@ -405,146 +499,213 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
return("");
}
// unlocks coins
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_ASSETS);
CTransaction vintx;
uint64_t mask;
uint256 hashBlock;
int64_t bidamount;
CPubKey mypk;
struct CCcontract_info *cp,C;
cp = CCinit(&C, EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
{
bidamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(bidtxid,0,CScript()));
mtx.vin.push_back(CTxIn(bidtxid, 0, CScript()));
mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('o',assetid,zeroid,0,Mypubkey())));
return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, Mypubkey())));
}
}
return("");
}
//unlocks tokens
std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_ASSETS);
CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk;
struct CCcontract_info *cp,C;
cp = CCinit(&C, EVAL_TOKENS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
{
askamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(asktxid,0,CScript()));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,mypk));
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('x',assetid,zeroid,0,Mypubkey())));
mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk));
return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, Mypubkey())));
}
}
return("");
}
//send tokens, receive coins:
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; uint256 hashBlock; CPubKey mypk; std::vector<uint8_t> origpubkey; int32_t bidvout=0; uint64_t mask; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C;
if ( fillamount < 0 )
CTransaction vintx;
uint256 hashBlock;
CPubKey mypk;
std::vector<uint8_t> origpubkey;
int32_t bidvout=0;
uint64_t mask;
int64_t origprice, bidamount, paid_amount, remaining_required, inputs, CCchange=0;
struct CCcontract_info *cp,C;
if (fillamount < 0)
{
fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount);
fprintf(stderr,"negative fillamount %lld\n", (long long)fillamount);
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
if ( txfee == 0 )
cp = CCinit(&C, EVAL_TOKENS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
{
bidamount = vintx.vout[bidvout].nValue;
SetAssetOrigpubkey(origpubkey,origprice,vintx);
mtx.vin.push_back(CTxIn(bidtxid,bidvout,CScript()));
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,fillamount,60)) > 0 )
SetAssetOrigpubkey(origpubkey, origprice, vintx);
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript()));
if ((inputs = AddTokenCCInputs(cp, mtx, mypk, assetid, fillamount, 60)) > 0)
{
if ( inputs < fillamount )
fillamount = inputs;
SetBidFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
if ( inputs > fillamount )
if (inputs < fillamount) {
std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl;
CCerror = strprintf("insufficient tokens to fill buy offer");
return ("");
}
SetBidFillamounts(paid_amount, remaining_required, bidamount, fillamount, origprice);
if (inputs > fillamount)
CCchange = (inputs - fillamount);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount - paid_amount,GetUnspendable(cp,0)));
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cp,0))); // tokens
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,fillamount,pubkey2pk(origpubkey)));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required);
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('B',assetid,zeroid,remaining_required,origpubkey)));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins
fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required);
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey)));
} else return("dont have any assets to fill bid\n");
}
}
return("no normal coins left");
}
// send coins, receive tokens
std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx,filltx; uint256 hashBlock; CPubKey mypk; std::vector<uint8_t> origpubkey; double dprice; uint64_t mask; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C;
if ( fillunits < 0 )
CTransaction vintx,filltx;
uint256 hashBlock;
CPubKey mypk;
std::vector<uint8_t> origpubkey;
double dprice;
uint64_t mask;
int32_t askvout=0;
int64_t received_assetoshis, total_nValue, orig_assetoshis, paid_nValue, remaining_nValue, inputs, CCchange=0;
struct CCcontract_info *cpTokens, tokensC;
struct CCcontract_info *cpAssets, assetsC;
if (fillunits < 0)
{
CCerror = strprintf("negative fillunits %lld\n",(long long)fillunits);
fprintf(stderr,"%s\n",CCerror.c_str());
return("");
}
if ( assetid2 != zeroid )
if (assetid2 != zeroid)
{
CCerror = "asset swaps disabled";
fprintf(stderr,"%s\n",CCerror.c_str());
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
if ( txfee == 0 )
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
if (txfee == 0)
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
if (AddNormalinputs(mtx,mypk,txfee,3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
{
orig_assetoshis = vintx.vout[askvout].nValue;
SetAssetOrigpubkey(origpubkey,total_nValue,vintx);
SetAssetOrigpubkey(origpubkey, total_nValue, vintx);
dprice = (double)total_nValue / orig_assetoshis;
paid_nValue = dprice * fillunits;
mtx.vin.push_back(CTxIn(asktxid,askvout,CScript()));
if ( assetid2 != zeroid )
inputs = AddAssetInputs(cp,mtx,mypk,assetid2,paid_nValue,60);
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx!
if (assetid2 != zeroid)
inputs = AddAssetInputs(cpTokens, mtx, mypk, assetid2, paid_nValue, 60);
else
{
inputs = AddNormalinputs(mtx,mypk,paid_nValue,60);
inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60);
mask = ~((1LL << mtx.vin.size()) - 1);
}
if ( inputs > 0 )
if (inputs > 0)
{
if ( inputs < paid_nValue )
paid_nValue = inputs;
if ( assetid2 != zeroid )
SetSwapFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
else SetAskFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
if ( assetid2 != zeroid && inputs > paid_nValue )
if (inputs < paid_nValue) {
std::cerr << "FillSell(): insufficient coins to fill sell" << std::endl;
CCerror = strprintf("insufficient coins to fill sell");
return ("");
}
if (assetid2 != zeroid)
SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue);
else
SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue);
if (assetid2 != zeroid && inputs > paid_nValue)
CCchange = (inputs - paid_nValue);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0)));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk));
if ( assetid2 != zeroid )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,paid_nValue,origpubkey));
else mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey)));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // coins
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); // tokens
if (assetid2 != zeroid)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens (not implemented correctly)
else
mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, origpubkey)));
} else {
CCerror = strprintf("filltx not enough utxos");
fprintf(stderr,"%s\n", CCerror.c_str());