Browse Source

Code rest of rpc calls with initial implementation

metaverse
jl777 6 years ago
parent
commit
143488c829
  1. 599
      src/cc/assets.cpp
  2. 16
      src/rpcserver.cpp
  3. 159
      src/wallet/rpcwallet.cpp

599
src/cc/assets.cpp

@ -25,10 +25,18 @@
#include <univalue.h>
#include <exception>
#ifdef ENABLE_WALLET
extern CWallet* pwalletMain;
#endif
extern uint8_t NOTARY_PUBKEY33[33];
uint256 Parseuint256(char *hexstr);
bool GetAddressUnspent(uint160 addressHash, int type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs);
// code rpc
// code info and totals to validate asset total and balances
// misc rpc, ie. CCaddress
// test underfill, overfill, exactfill
// sell and maybe even exchange
/*
Assets can be created or transferred.
@ -87,7 +95,7 @@ uint256 Parseuint256(char *hexstr);
fillbuy:
vin.0: normal input
vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
vin.2: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
vout.0: remaining amount of bid to unspendable
vout.1: vin.1 value to signer of vin.2
vout.2: vin.2 assetoshis to original pubkey
@ -98,14 +106,16 @@ uint256 Parseuint256(char *hexstr);
vin.0: normal input
vin.1: valid CC output for sale
vout.0: vin.1 assetoshis output to CC to unspendable
vout.1: normal output for change (if any)
vout.1: CC output for change (if any)
vout.2: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
exchange:
vin.0: normal input
vin.1: valid CC output
vout.0: vin.1 assetoshis output to CC to unspendable
vout.1: normal output for change (if any)
vout.1: CC output for change (if any)
vout.2: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
cancel:
@ -118,7 +128,7 @@ uint256 Parseuint256(char *hexstr);
fillsell:
vin.0: normal input
vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
vin.2: normal output that satisfies selloffer (*tx.vin[2])->nValue
vin.2+: normal output that satisfies selloffer (*tx.vin[2])->nValue
vout.0: remaining assetoshis -> unspendable
vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any
vout.2: vin.2 value to original pubkey [origpubkey]
@ -128,7 +138,7 @@ uint256 Parseuint256(char *hexstr);
fillexchange:
vin.0: normal input
vin.1: unspendable.(vout.0 assetoshis from exchange) exchangeTx.vout[0]
vin.2: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
vin.2+: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
vout.0: remaining assetoshis -> unspendable
vout.1: vin.1 assetoshis to signer of vin.2 exchangeTx.vout[0].nValue -> any
vout.2: vin.2 assetoshis2 to original pubkey [origpubkey]
@ -136,34 +146,6 @@ uint256 Parseuint256(char *hexstr);
vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
*/
/*
# Using Hoek to mangle asset transactions
# Install haskell stack & hoek
curl -sSL https://get.haskellstack.org/ | sh
git clone https://github.com/libscott/hoek; cd hoek; stack install
# Let...
addr=RHTcNNYXEZhLGRcXspA2H4gw2v4u6w8MNp
wif=UsNAMqFwntEpuFBTbG28e3uAJxBNRM8Vi5FxAqHfoRJJNoZ84Esj
pk=02184e11939da3805808cd18921a8b592b98bbaf9f506da8b272ebc3c5fa4d045c
# Our CC is a 2 of 2 where the subconditions are an secp256k1, and an EVAL code calling 0xe3 (EVAL_ASSETS).
cc='{"type":"threshold-sha-256","threshold":2,"subfulfillments":[{"type":"eval-sha-256","code":"e3"},{"type":"secp256k1-sha-256","publicKey":"02184e11939da3805808cd18921a8b592b98bbaf9f506da8b272ebc3c5fa4d045c"}]}'
# 1. Create a asset: Just use regular inputs and only colored outputs
createTx='{"inputs": [{"txid":"51b78168d94ec307e2855697209275d477e05d8647caf29cb9e38fb6a4661145","idx":0,"script":{"address":"'$addr'"}}],"outputs":[{"amount":10,"script":{"condition":'$cc'}}]}'
# 2. Transfer a asset: use CC inputs, CC outputs, and an OP_RETURN output with the txid of the tx that created the asset (change the txid):
transferTx='{"inputs": [{"txid":"51b78168d94ec307e2855697209275d477e05d8647caf29cb9e38fb6a4661145","idx":0,"script":{"fulfillment":'$cc'}}],"outputs":[{"amount":0,"script":{"op_return":"cafabda044ac904d56cee79bbbf3ed9b3891a69000ed08f0ddf0a3dd620a3ea6"}},{"amount":10,"script":{"condition":'$cc'}}]}'
# 3. Sign and encode
function signEncodeTx () {
signed=`hoek signTx '{"privateKeys":["'$wif'"],"tx":'"$1"'}'`;
hoek encodeTx "$signed"
}
signEncodeTx "$createTx"
signEncodeTx "$transferTx"
*/
#ifdef ENABLE_WALLET
extern CWallet* pwalletMain;
#endif
//BTCD Address: RAssetsAtGnvwgK9gVHBbAU4sVTah1hAm5
//BTCD Privkey: UvtvQVgVScXEYm4J3r4nE4nbFuGXSVM5pKec8VWXwgG9dmpWBuDh
@ -171,7 +153,7 @@ extern CWallet* pwalletMain;
//BTCD Privkey: Ux6XQekTxokko6gZHz24B7PUsmUQtWFzG2W9nUA8jba7UoVbPBF4
static uint256 zeroid;
const char *Unspendableaddr = "RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
const char *AssetsCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6" ;//"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
char Unspendablehex[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" };
uint8_t Unspendablepriv[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 };
@ -214,6 +196,14 @@ uint256 revuint256(uint256 txid)
return(revtxid);
}
char *uint256_str(char *dest,uint256 txid)
{
int32_t i,j=0;
for (i=31; i>=0; i--)
sprintf(&dest[j++ * 2] = ((uint8_t *)&txid)[i];
return(dest);
}
CScript EncodeOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,uint64_t price,std::vector<uint8_t> origpubkey)
{
CScript opret; uint8_t evalcode = EVAL_ASSETS;
@ -331,6 +321,8 @@ bool GetCCaddress(uint8_t evalcode,char *destaddr,CPubKey pk)
destaddr[0] = 0;
if ( evalcode == EVAL_ASSETS )
{
if ( pk.size() == 0 )
pk = GetUnspendable(EVAL_ASSETS,0);
if ( (payoutCond= MakeAssetCond(pk)) != 0 )
{
Getscriptaddress(destaddr,CCPubKey(payoutCond));
@ -399,16 +391,17 @@ bool SetOrigpubkey(std::vector<uint8_t> &origpubkey,uint64_t &price,CTransaction
else return(false);
}
bool Getorigaddr(char *destaddr,CTransaction& tx)
bool Getorigaddrs(char *CCaddr,char *destaddr,CTransaction& tx)
{
uint256 assetid,assetid2; uint64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector<uint8_t> origpubkey; CScript script;
n = tx.vout.size();
if ( n == 0 || (funcid= DecodeOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
return(false);
script = CScript() << origpubkey << OP_CHECKSIG;
return(Getscriptaddress(destaddr,script));
if ( GetCCaddress(EVAL_ASSETS,destaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 )
return(true);
else return(false);
}
CC* GetCryptoCondition(CScript const& scriptSig)
{
auto pc = scriptSig.begin();
@ -464,6 +457,8 @@ uint64_t IsAssetvout(uint64_t &price,std::vector<uint8_t> &origpubkey,CTransacti
if ( refassetid == tx.GetHash() && v == 0 )
return(nValue);
}
else if ( funcid == 'b' || funcid == 'B' )
return(0);
else if ( funcid != 'E' )
{
if ( assetid == refassetid )
@ -591,7 +586,6 @@ std::string FinalizeCCTx(uint8_t evalcode,CMutableTransaction &mtx,CPubKey mypk,
else return(0);
}
bool ValidateRemainder(uint64_t remaining_price,uint64_t remaining_nValue,uint64_t orig_nValue,uint64_t received,uint64_t paid,uint64_t totalprice)
{
uint64_t price,recvprice;
@ -640,27 +634,92 @@ bool SetFillamounts(uint64_t &paid,uint64_t &remaining_price,uint64_t orig_nValu
return(ValidateRemainder(remaining_price,remaining_nValue,orig_nValue,received,paid,totalprice));
} else return(false);
}
/*uint64_t IsNormalUtxo(uint64_t output,uint64_t txfee,uint256 feetxid,int32_t feevout)
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr)
{
CTransaction vintx; uint256 hashBlock; uint64_t nValue;
if ( GetTransaction(feetxid,vintx,hashBlock,false) != 0 )
int32_t i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
n = (int32_t)strlen(coinaddr);
addrstr.resize(n+1);
ptr = (char *)addrstr.data();
for (i=0; i<=n; i++)
ptr[i] = coinaddr[i];
CBitcoinAddress address(addrstr);
if ( address.GetIndexKey(hashBytes, type) == 0 )
return;
addresses.push_back(std::make_pair(hashBytes,type));
if ( getAddressesFromParams(params, addresses) == 0 )
return;
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
{
nValue = vintx.vout[feevout].nValue;
if ( vintx.vout[feevout].scriptPubKey.IsPayToCryptoCondition() == 0 && nValue >= output+txfee )
return(nValue);
if ( GetAddressUnspent((*it).first, (*it).second, unspentOutputs) == 0 )
return;
}
return(0);
}*/
uint64_t AddCCinputs(CMutableTransaction &mtx,CPubKey mypk,uint256 assetid,uint64_t total)
}
uint64_t AddCCinputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,uint64_t total,int32_t maxinputs)
{
uint64_t totalinputs = 0;
mtx.vin.push_back(CTxIn(Parseuint256((char *)"5117c5f5f7b077c3f8ef08bc0f5789d6b53a6fea61ee0a51b5c829797bd81a57"),0,CScript()));
totalinputs = COIN;
char coinaddr[64]; int32_t type=0; uint64_t price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(EVAL_ASSETS,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
//std::sort(unspentOutputs.begin(), unspentOutputs.end(), heightSort);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash.GetHex();
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsAssetvout(price,origpubkey,vintx,(int32_t)it->first.index,assetid)) > 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
}
}
}
return(totalinputs);
}
UniValue AssetOrders(uint256 refassetid)
{
uint64_t price; uint256 txid,hashBlock,assetid,assetid2; std::vector<uint8_t> origpubkey; CTransaction vintx; UniValue result(UniValue::VOBJ),obj(UniValue::VOBJ),a(UniValue::VARR); std::vector<uint8_t> origpubkey; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; uint8_t funcid; char funcidstr[16],origaddr[64],assetidstr[65];
SetCCunspents(unspentOutputs,(char *)AssetsCCaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash.GetHex();
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (funcid= DecodeOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey)) != 0 )
{
funcidstr[0] = funcid;
funcidstr[1] = 0;
item.push_back(Pair("funcid", funcidstr));
item.push_back(Pair("txid", uint256_str(assetidstr,txid)));
item.push_back(Pair("vout", (int64_t)it->first.index));
item.push_back(Pair("amount", (double)vintx.vout[it->first.index].nValue/COIN));
if ( funcid == 'b' || funcid == 'B' )
item.push_back(Pair("bidamount",(double)vintx.vout[0].nValue/COIN));
else item.push_back(Pair("askamount",(double)vintx.vout[0].nValue));
if ( origpubkey.size() == 33 )
{
GetCCaddress(EVAL_ASSETS,origaddr,pubkey2pk(origpubkey));
item.push_back(Pair("origaddress",origaddr));
}
if ( assetid != zeroid )
item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
if ( assetid2 != zeroid )
item.push_back(Pair("otherid",uint256_str(assetidstr,assetid2)));
if ( price > 0 )
item.push_back(Pair("price", (int64_t)price));
a.push_back(item);
}
}
}
return(result);
}
uint64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,uint64_t total,int32_t maxinputs)
{
int32_t n = 0; uint64_t nValue,totalinputs = 0; std::vector<COutput> vecOutputs;
@ -718,7 +777,7 @@ std::string AssetTransfer(uint64_t txfee,uint256 assetid,std::vector<uint8_t> de
{
for (i=0; i<n; i++)
total += amounts[i];*/
if ( (inputs= AddCCinputs(mtx,mypk,assetid,total)) > 0 )
if ( (inputs= AddCCinputs(mtx,mypk,assetid,total,60)) > 0 )
{
if ( inputs > total )
CCchange = (inputs - total);
@ -747,6 +806,30 @@ std::string CreateBuyOffer(uint64_t txfee,uint64_t bidamount,uint256 assetid,uin
return(0);
}
std::string CreateSell(uint64_t txfee,uint64_t askamount,uint256 assetid,uint256 assetid2,uint64_t pricetotal)
{
CMutableTransaction mtx; CPubKey mypk; uint64_t inputs,CCchange; CScript opret;
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddCCinputs(mtx,mypk,assetid,askamount,60)) > 0 )
{
mtx.vout.push_back(MakeAssetsVout(askamount,GetUnspendable(EVAL_ASSETS,0)));
if ( inputs > askamount )
CCchange = (askamount - total);
if ( CCchange != 0 )
mtx.vout.push_back(MakeAssetsVout(CCchange,mypk));
if ( assetid2 == zeroid )
opret = EncodeOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
else opret = EncodeOpRet('e',assetid,assetid2,pricetotal,Mypubkey());
return(FinalizeCCTx(EVAL_ASSETS,mtx,mypk,txfee,opret));
}
}
return(0);
}
std::string CancelBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid)
{
CMutableTransaction mtx; CTransaction vintx; uint256 hashBlock; uint64_t bidamount; CPubKey mypk;
@ -763,35 +846,51 @@ std::string CancelBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid)
return(FinalizeCCTx(EVAL_ASSETS,mtx,mypk,txfee,EncodeOpRet('o',assetid,zeroid,0,Mypubkey())));
}
}
fprintf(stderr,"no normal inputs\n");
return(0);
}
std::string FillBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid,uint256 filltxid,int32_t fillvout)
std::string CancelSell(uint64_t txfee,uint256 assetid,uint256 asktxid)
{
CTransaction vintx,filltx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey,tmppubkey; int32_t bidvout=0; uint64_t tmpprice,origprice,bidamount,paid_amount,fillamount,remaining_required;
CMutableTransaction mtx; CTransaction vintx; uint256 hashBlock; uint64_t askamount; CPubKey mypk;
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 && GetTransaction(filltxid,filltx,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(MakeAssetsVout(askamount,mypk));
return(FinalizeCCTx(EVAL_ASSETS,mtx,mypk,txfee,EncodeOpRet('x',assetid,zeroid,0,Mypubkey())));
}
}
return(0);
}
std::string FillBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid,uint64_t fillamount)
{
CTransaction vintx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey; int32_t bidvout=0; uint64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0;
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
{
bidamount = vintx.vout[bidvout].nValue;
SetOrigpubkey(origpubkey,origprice,vintx);
fillamount = filltx.vout[fillvout].nValue;
mtx.vin.push_back(CTxIn(bidtxid,bidvout,CScript()));
if ( IsAssetvout(tmpprice,tmppubkey,filltx,fillvout,assetid) == fillamount )
if ( (inputs= AddCCinputs(mtx,mypk,assetid,fillamount,60)) > 0 )
{
mtx.vin.push_back(CTxIn(filltxid,fillvout,CScript())); // CC
if ( inputs > fillamount )
CCchange = (inputs - fillamount);
SetFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
mtx.vout.push_back(MakeAssetsVout(bidamount - paid_amount,GetUnspendable(EVAL_ASSETS,0)));
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(MakeAssetsVout(fillamount,pubkey2pk(origpubkey)));
if ( filltx.vout[fillvout].nValue > fillamount )
{
mtx.vout.push_back(MakeAssetsVout(filltx.vout[fillvout].nValue - fillamount,mypk));
}
if ( CCchange != 0 )
mtx.vout.push_back(MakeAssetsVout(CCchange,mypk));
fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required);
return(FinalizeCCTx(EVAL_ASSETS,mtx,mypk,txfee,EncodeOpRet('B',assetid,zeroid,remaining_required,origpubkey)));
} else fprintf(stderr,"filltx wasnt for assetid\n");
@ -800,86 +899,74 @@ std::string FillBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid,uint256
return(0);
}
/*
selloffer:
vin.0: normal input
vin.1: valid CC output for sale
vout.0: vin.1 assetoshis output to CC to unspendable
vout.1: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
exchange:
vin.0: normal input
vin.1: valid CC output
vout.0: vin.1 assetoshis output to CC to unspendable
vout.1: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
cancel:
vin.0: normal input
vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
vout.1: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
fillsell:
vin.0: normal input
vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
vin.2: normal output that satisfies selloffer (*tx.vin[2])->nValue
vout.0: remaining assetoshis -> unspendable
vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any
vout.2: vin.2 value to original pubkey [origpubkey]
vout.3: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey]
fillexchange:
vin.0: normal input
vin.1: unspendable.(vout.0 assetoshis from exchange) exchangeTx.vout[0]
vin.2: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
vout.0: remaining assetoshis -> unspendable
vout.1: vin.1 assetoshis to signer of vin.2 exchangeTx.vout[0].nValue -> any
vout.2: vin.2 assetoshis2 to original pubkey [origpubkey]
vout.3: normal output for change (if any)
vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
*/
std::string FillSell(uint64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,uint64_t fillamount)
{
CTransaction vintx,filltx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey; int32_t askvout=0; uint64_t origprice,askamount,paid_amount,remaining_required,inputs,CCchange=0;
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
{
askamount = vintx.vout[askvout].nValue;
SetOrigpubkey(origpubkey,origprice,vintx);
mtx.vin.push_back(CTxIn(asktxid,askvout,CScript()));
if ( assetid2 == zeroid )
inputs = AddCCinputs(mtx,mypk,assetid2,fillamount);
else inputs = AddNormalinputs(mtx,mypk,fillamount,60);
if ( inputs > 0 )
{
if ( assetid2 == zeroid && inputs > fillamount )
CCchange = (inputs - fillamount);
SetFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
mtx.vout.push_back(MakeAssetsVout(askamount - paid_amount,GetUnspendable(EVAL_ASSETS,0)));
mtx.vout.push_back(MakeAssetsVout(paid_amount,mypk));
mtx.vout.push_back(MakeAssetsVout(fillamount,pubkey2pk(origpubkey)));
if ( CCchange != 0 )
mtx.vout.push_back(MakeAssetsVout(CCchange,mypk));
fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required);
return(FinalizeCCTx(EVAL_ASSETS,mtx,mypk,txfee,EncodeOpRet(assetid2==zeroid?'E':'S',assetid,assetid2,remaining_required,origpubkey)));
} else fprintf(stderr,"filltx not enough utxos\n");
}
}
return(0);
}
uint64_t AssetValidatevin(Eval* eval,char *origaddr,CTransaction &tx,CTransaction &vinTx)
uint64_t AssetValidateCCvin(Eval* eval,char *CCaddr,char *origaddr,CTransaction &tx,CTransaction &vinTx)
{
uint256 hashBlock; char destaddr[64],unspendable[64];
uint256 hashBlock; char destaddr[64];
origaddr[0] = destaddr[0] = 0;
GetCCaddress(EVAL_ASSETS,unspendable,GetUnspendable(EVAL_ASSETS,0));
if ( tx.vin[1].prevout.n != 0 )
if ( tx.vin.size() < 2 )
return eval->Invalid("not enough for CC vins");
else if ( tx.vin[1].prevout.n != 0 )
return eval->Invalid("vin1 needs to be buyvin.vout[0]");
else if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("always should find vin, but didnt");
else if ( Getscriptaddress(destaddr,vinTx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,unspendable) != 0 )
else if ( Getscriptaddress(destaddr,vinTx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,AssetsCCaddr) != 0 )
{
fprintf(stderr,"%s vs %s\n",destaddr,unspendable);
return eval->Invalid("invalid vin unspendableaddr");
fprintf(stderr,"%s vs %s\n",destaddr,AssetsCCaddr);
return eval->Invalid("invalid vin AssetsCCaddr");
}
else if ( vinTx.vout[0].nValue < 10000 )
return eval->Invalid("invalid dust for buyvin");
else if ( Getorigaddr(origaddr,vinTx) == 0 )
else if ( Getorigaddrs(CCaddr,origaddr,vinTx) == 0 )
return eval->Invalid("couldnt get origaddr for buyvin");
fprintf(stderr,"Got %.8f to origaddr.(%s)\n",(double)vinTx.vout[0].nValue/COIN,origaddr);
return(vinTx.vout[0].nValue);
}
uint64_t AssetValidateBuyvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *origaddr,CTransaction &tx,uint256 refassetid)
uint64_t AssetValidateBuyvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,CTransaction &tx,uint256 refassetid)
{
CTransaction vinTx; uint64_t nValue; uint256 assetid,assetid2;
int32_t i; for (i=31; i>=0; i--)
fprintf(stderr,"%02x",((uint8_t *)&refassetid)[i]);
fprintf(stderr," AssetValidateBuyvin\n");
if ( (nValue= AssetValidatevin(eval,origaddr,tx,vinTx)) == 0 )
CTransaction vinTx; uint64_t nValue; uint256 assetid,assetid2; uint8_t funcid;
if ( (nValue= AssetValidateCCvin(eval,CCaddr,origaddr,tx,vinTx)) == 0 )
return(0);
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("invalid normal vout0 for buyvin");
else
{
fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr);
if ( DecodeOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,assetid,assetid2,tmpprice,tmporigpubkey) != 'b' )
//fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr);
if ( (funcid= DecodeOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' )
return eval->Invalid("invalid opreturn for buyvin");
else if ( refassetid != assetid )
{
@ -892,29 +979,73 @@ uint64_t AssetValidateBuyvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t>
return(nValue);
}
uint64_t AssetValidateSellvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *origaddr,CTransaction &tx,uint256 assetid)
uint64_t AssetValidateSellvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,CTransaction &tx,uint256 assetid)
{
CTransaction vinTx; uint64_t nValue,assetoshis;
fprintf(stderr,"AssetValidateSellvin\n");
if ( (nValue= AssetValidatevin(eval,origaddr,tx,vinTx)) == 0 )
if ( (nValue= AssetValidateCCvin(eval,CCaddr,origaddr,tx,vinTx)) == 0 )
return(0);
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,0,assetid)) != 0 )
return eval->Invalid("invalid missing CC vout0 for sellvin");
else return(assetoshis);
}
bool ConstrainVout(CTxout vout,int32_t CCflag,char *cmpadr,uint64_t nValue)
{
char destaddr[64];
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
return(false);
else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
return(false);
else if ( (nValue == 0 && vout.nValue < 10000) || nValue != vout.nValue )
return(false);
else return(true);
}
bool AssetExactAmounts(Eval* eval,CTransaction &tx,uint256 assetid)
{
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; std::vector<uint8_t> tmporigpubkey; uint64_t tmpprice;
numvins = tx.vin.size();
numvouts = tx.vout.size();
for (i=1; i<numvins; i++)
{
if ( IsAssetInput(tx.vin[i].scriptSig) != 0 )
{
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("always should find vin, but didnt");
else if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
inputs += assetoshis;
}
}
for (i=0; i<numvouts; i++)
{
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs )
return(false);
else return(true);
}
bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,uint256 assetid,uint256 assetid2,uint64_t remaining_price,std::vector<uint8_t> origpubkey)
{
static uint256 zero;
CTxDestination address; CTransaction vinTx; uint256 hashBlock; int32_t i,numvins; uint64_t nValue,assetoshis,outputs,inputs,tmpprice,ignore; std::vector<uint8_t> tmporigpubkey,ignorepubkey; char destaddr[64],origaddr[64];
CTxDestination address; CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,preventCCvins,preventCCvouts; uint64_t nValue,assetoshis,outputs,inputs,tmpprice,ignore; std::vector<uint8_t> tmporigpubkey,ignorepubkey; char destaddr[64],origaddr[64],CCaddr[64];
fprintf(stderr,"AssetValidate (%c)\n",funcid);
numvins = tx.vin.size();
outputs = inputs = 0;
preventCCvins = preventCCvouts = -1;
if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("illegal asset vin0");
if ( funcid != 'c' && assetid == zero )
return eval->Invalid("illegal assetid");
fprintf(stderr,"switch\n");
else if ( numvouts < 1 )
return eval->Invalid("no vouts");
else if ( funcid != 'c' )
{
if ( assetid == zero )
return eval->Invalid("illegal assetid");
else if ( AssetExactAmounts(eval,tx,assetid) == false )
eval->Invalid("asset inputs != outputs");
}
switch ( funcid )
{
case 'c': // create wont be called to be verified as it has no CC inputs
@ -931,25 +1062,8 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
//vout.0 to n-2: assetoshis output to CC
//vout.n-2: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid]
for (i=1; i<numvins; i++)
{
if ( IsAssetInput(tx.vin[i].scriptSig) != 0 )
{
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("always should find vin, but didnt");
else if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
inputs += assetoshis;
}
}
for (i=0; i<numvouts-1; i++)
{
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
outputs += assetoshis;
}
if ( inputs == 0 )
return eval->Invalid("no asset inputs for transfer");
else if ( inputs != outputs )
return eval->Invalid("mismatched inputs and outputs for transfer");
fprintf(stderr,"transfer validated %.8f -> %.8f\n",(double)inputs/COIN,(double)outputs/COIN);
break;
@ -960,27 +1074,11 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
if ( remaining_price == 0 )
return eval->Invalid("illegal null amount for buyoffer");
for (i=1; i<numvins; i++)
{
if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
return eval->Invalid("invalid CC vin for buyoffer");
}
destaddr[0] = 0;
for (i=0; i<numvouts-1; i++)
{
if ( i == 0 )
{
if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("invalid normal vout for buyoffer");
else if ( Getscriptaddress(destaddr,tx.vout[i].scriptPubKey) == 0 || strcmp(destaddr,Unspendableaddr) != 0 )
return eval->Invalid("invalid vout0 destaddr for buyoffer");
else if ( tx.vout[i].nValue < 10000 )
return eval->Invalid("invalid vout0 dust for buyoffer");
}
else if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("invalid CC vout for buyoffer");
}
fprintf(stderr,"buy offer validated to destaddr.(%s)\n",destaddr);
else if ( ConstrainVout(tx.vout[0],1,AssetsCCaddr,0) == 0 )
return eval->Invalid("invalid vout for buyoffer");
preventCCvins = 1;
preventCCvouts = 1;
fprintf(stderr,"buy offer validated to destaddr.(%s)\n",AssetsCCaddr);
break;
case 'o': // cancelbuy
@ -989,55 +1087,50 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
//vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
//vout.1: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
if ( (nValue= AssetValidateBuyvin(eval,tmpprice,tmporigpubkey,origaddr,tx,assetid)) == 0 )
if ( (nValue= AssetValidateBuyvin(eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
return(false);
else if ( nValue != tx.vout[0].nValue )
return eval->Invalid("mismatched refund for cancelbuy");
else if ( Getscriptaddress(destaddr,tx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,origaddr) != 0 )
return eval->Invalid("invalid vout0 destaddr for cancelbuy");
else if ( tmporigpubkey != origpubkey )
return eval->Invalid("mismatched origpubkeys for cancelbuy");
else if ( ConstrainVout(tx.vout[0],0,origaddr,nValue) == 0 )
return eval->Invalid("invalid refund for cancelbuy");
preventCCvins = 1;
preventCCvouts = 0;
fprintf(stderr,"cancelbuy validated to destaddr.(%s)\n",destaddr);
break;
case 'B': // fillbuy:
//vin.0: normal input
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
//vin.2: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
//vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
//vout.0: remaining amount of bid to unspendable
//vout.1: vin.1 value to signer of vin.2
//vout.2: vin.2 assetoshis to original pubkey
//vout.3: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
fprintf(stderr,"inside fillbuy\n");
if ( (nValue= AssetValidateBuyvin(eval,tmpprice,tmporigpubkey,origaddr,tx,assetid)) == 0 )
preventCCvouts = 4;
if ( (nValue= AssetValidateBuyvin(eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
return(false);
else if ( numvouts < 3 )
return eval->Invalid("not enough vouts for fillbuy");
else if ( tmporigpubkey != origpubkey )
return eval->Invalid("mismatched origpubkeys for fillbuy");
else if ( IsAssetInput(tx.vin[2].scriptSig) != 0 )
if ( inputs != outputs )
return eval->Invalid("mismatched inputs vs outputs for fillbuy");
else
{
if ( eval->GetTxUnconfirmed(tx.vin[2].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("always should find vin, but didnt");
else if ( (assetoshis= IsAssetvout(ignore,ignorepubkey,vinTx,tx.vin[2].prevout.n,assetid)) != 0 )
if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
return eval->Invalid("vout1 is CC for fillbuy");
else if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
return eval->Invalid("vout2 is normal for fillbuy");
else if ( ValidateRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,tmpprice) == false )
return eval->Invalid("mismatched remainder for fillbuy");
else if ( remaining_price != 0 )
{
if ( tx.vout[2].nValue > assetoshis )
{
fprintf(stderr,"[2] value %.8f vs %.8f\n",(double)tx.vout[2].nValue/COIN,(double)assetoshis/COIN);
return eval->Invalid("mismatched assetoshis for fillbuy");
}
else if ( Getscriptaddress(destaddr,tx.vout[2].scriptPubKey) == 0 || strcmp(destaddr,origaddr) != 0 )
{
fprintf(stderr,"destaddr.(%s) vs origaddr.(%s)\n",destaddr,origaddr);
return eval->Invalid("mismatched vout2 destaddr for fillbuy");
}
else if ( ValidateRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,tmpprice) == false )
return eval->Invalid("mismatched remainder for fillbuy");
else if ( remaining_price != 0 )
{
if ( remaining_price < 10000 )
return eval->Invalid("dust vout0 to unspendableaddr for fillbuy");
else if ( Getscriptaddress(destaddr,tx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,Unspendableaddr) != 0 )
return eval->Invalid("mismatched vout0 unspendableaddr for fillbuy");
}
} else return eval->Invalid("vin2 not enough asset2 for fillbuy");
if ( remaining_price < 10000 )
return eval->Invalid("dust vout0 to AssetsCCaddr for fillbuy");
else if ( ConstrainVout(tx.vout[0],1,AssetsCCaddr,0) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
}
} else return eval->Invalid("vin2 not asset for fillbuy");
fprintf(stderr,"fillbuy validated\n");
break;
@ -1052,17 +1145,9 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
//'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
if ( remaining_price == 0 )
return eval->Invalid("illegal null remaining_price for selloffer");
if ( IsAssetInput(tx.vin[1].scriptSig) != 0 )
{
if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("always should find vin, but didnt");
else if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,tx.vin[1].prevout.n,assetid)) == 0 )
return eval->Invalid("illegal missing assetvin for selloffer");
else if ( Getscriptaddress(destaddr,tx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,Unspendableaddr) != 0 )
return eval->Invalid("mismatched vout0 unspendableaddr for selloffer");
else if ( tx.vout[0].nValue != assetoshis )
return eval->Invalid("mismatched assetoshis for selloffer");
} else return eval->Invalid("illegal normal vin1 for selloffer");
else if ( ConstrainVout(tx.vout[0],1,AssetsCCaddr,0) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
preventCCvouts = 1;
break;
case 'x': // cancel
@ -1071,20 +1156,22 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
//vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
//vout.1: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
if ( (assetoshis= AssetValidateSellvin(eval,tmpprice,tmporigpubkey,origaddr,tx,assetid)) == 0 )
if ( (assetoshis= AssetValidateSellvin(eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
return(false);
else if ( assetoshis != tx.vout[0].nValue )
return eval->Invalid("mismatched refund for cancelbuy");
else if ( Getscriptaddress(destaddr,tx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,origaddr) != 0 )
return eval->Invalid("invalid vout0 destaddr for cancel");
else if ( tmporigpubkey != origpubkey )
return eval->Invalid("mismatched origpubkeys for cancel");
else if ( ConstrainVout(tx.vout[0],1,CCaddr,assetoshis) == 0 )
return eval->Invalid("invalid vout for cancel");
preventCCvins = 2;
preventCCvouts = 1;
break;
case 'S': // fillsell
case 'E': // fillexchange
//vin.0: normal input
//vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
//'S'.vin.2: normal output that satisfies selloffer (*tx.vin[2])->nValue
//'E'.vin.2: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
//'S'.vin.2+: normal output that satisfies selloffer (*tx.vin[2])->nValue
//'E'.vin.2+: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue
//vout.0: remaining assetoshis -> unspendable
//vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any
//'S'.vout.2: vin.2 value to original pubkey [origpubkey]
@ -1092,40 +1179,54 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
//vout.3: normal output for change (if any)
//'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey]
//'E'.vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
if ( (assetoshis= AssetValidateSellvin(eval,tmpprice,tmporigpubkey,origaddr,tx,assetid)) == 0 )
if ( funcid == 'E' )
{
if ( AssetExactAmounts(eval,tx,assetid2) == false )
eval->Invalid("asset2 inputs != outputs");
}
if ( (assetoshis= AssetValidateSellvin(eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
return(false);
else if ( numvouts < 3 )
return eval->Invalid("not enough vouts for fill");
else if ( tmporigpubkey != origpubkey )
return eval->Invalid("mismatched origpubkeys for fillsell");
else if ( funcid == 'S' && IsAssetInput(tx.vin[2].scriptSig) != 0 )
return eval->Invalid("invalid vin2 is CC for fillsell");
else if ( funcid == 'E' && IsAssetInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("invalid vin2 is CC for fillexchange");
else if ( eval->GetTxUnconfirmed(tx.vin[2].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("always should find vin, but didnt");
else if ( funcid == 'E' && (IsAssetvout(ignore,ignorepubkey,vinTx,tx.vin[2].prevout.n,assetid2) != tx.vout[2].nValue || tx.vout[2].nValue == 0) )
return eval->Invalid("invalid asset2 vin value for fillexchange");
else if ( funcid == 'E' && IsAssetvout(ignore,ignorepubkey,tx,2,assetid2) == 0 )
return eval->Invalid("invalid asset2 voutvalue for fillexchange");
else if ( Getscriptaddress(destaddr,tx.vout[2].scriptPubKey) == 0 || strcmp(destaddr,origaddr) != 0 )
return eval->Invalid("mismatched vout2 destaddr for fill");
else if ( vinTx.vout[tx.vin[2].prevout.n].nValue != tx.vout[2].nValue )
return eval->Invalid("mismatched vout2 nValue for fill");
else if ( ValidateRemainder(remaining_price,tx.vout[0].nValue,assetoshis,tx.vout[2].nValue,tx.vout[1].nValue,tmpprice) == false )
return eval->Invalid("mismatched remainder for fill");
else if ( IsAssetvout(ignore,ignorepubkey,vinTx,tx.vin[1].prevout.n,assetid) == 0 )
return eval->Invalid("mismatched vout0 unspendableaddr for fill");
else if ( remaining_price != 0 )
return eval->Invalid("mismatched origpubkeys for fill");
else
{
if ( Getscriptaddress(destaddr,tx.vout[0].scriptPubKey) == 0 || strcmp(destaddr,Unspendableaddr) != 0 )
return eval->Invalid("mismatched vout0 unspendableaddr for fill");
else if ( IsAssetvout(ignore,ignorepubkey,tx,0,assetid) == 0 )
return eval->Invalid("not asset vout0 to unspendableaddr for fill");
else if ( funcid == 'S' && remaining_price < 10000 )
return eval->Invalid("dust vout0 to unspendableaddr for fill");
}
if ( ValidateRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,tmpprice) == false )
return eval->Invalid("mismatched remainder for fill");
else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 )
return eval->Invalid("normal vout1 for fillask");
else if ( funcid == 'E' && ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
return eval->Invalid("normal vout2 for fillask");
else if ( funcid == 'S' && ConstrainVout(tx.vout[2],0,origaddr,0) == 0 )
return eval->Invalid("CC vout2 for fillask");
else if ( remaining_price != 0 )
{
if ( remaining_price < 10000 )
return eval->Invalid("dust vout0 to AssetsCCaddr for fill");
else if ( ConstrainVout(tx.vout[0],1,AssetsCCaddr,0) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill");
}
} else return eval->Invalid("vin2 not enough asset2 for fillbuy");
fprintf(stderr,"fill validated\n")
break;
}
fprintf(stderr,"done Process assets\n");
if ( preventCCvins >= 0 )
{
for (i=preventCCvins; i<numvins; i++)
{
if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
return eval->Invalid("invalid CC vin");
}
}
if ( preventCCvouts >= 0 )
{
for (i=preventCCvouts; i<numvouts; i++)
{
else if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("invalid CC vout");
}
}
return(true);
}

16
src/rpcserver.cpp

@ -346,11 +346,19 @@ static const CRPCCommand vRPCCommands[] =
#endif
/* tokens */
{ "tokens", "tokencreate", &tokencreate, true },
{ "tokens", "tokentransfer", &tokentransfer, true },
{ "tokens", "tokenbid", &tokenbid, true },
{ "tokens", "tokencancelbid", &tokencancelbid, true },
{ "tokens", "tokenorders", &tokenorders, true },
{ "tokens", "tokenaddress", &tokenaddress, true },
{ "tokens", "tokenbalance", &tokenbalance, true },
{ "tokens", "tokencreate", &tokencreate, true },
{ "tokens", "tokentransfer", &tokentransfer, true },
{ "tokens", "tokenbid", &tokenbid, true },
{ "tokens", "tokencancelbid", &tokencancelbid, true },
{ "tokens", "tokenfillbid", &tokenfillbid, true },
{ "tokens", "tokenask", &tokenask, true },
{ "tokens", "tokenswapask", &tokenswapask, true },
{ "tokens", "tokencancelask", &tokencancelas true },
{ "tokens", "tokenfillask", &tokenfillask, true },
{ "tokens", "tokenfillswap", &tokenfillswap true },
/* Address index */
{ "addressindex", "getaddressmempool", &getaddressmempool, true },

159
src/wallet/rpcwallet.cpp

@ -4830,11 +4830,19 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
return(siglen);
}
#define EVAL_ASSETS 0xe3
std::string CreateAsset(uint64_t txfee,uint64_t assetsupply,std::string name,std::string description);
std::string AssetTransfer(uint64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,uint64_t total);
std::string CreateBuyOffer(uint64_t txfee,uint64_t bidamount,uint256 assetid,uint64_t pricetotal);
std::string CancelBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid);
std::string FillBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid,uint256 filltxid,int32_t fillvout);
std::string FillBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid,uint64_t fillamount);
std::string CreateSell(uint64_t txfee,uint64_t askamount,uint256 assetid,uint256 assetid2,uint64_t pricetotal);
std::string CancelSell(uint64_t txfee,uint256 assetid,uint256 asktxid);
std::string FillSell(uint64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,uint64_t fillamount);
uint64_t AddCCinputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,uint64_t total,int32_t maxinputs);
bool GetCCaddress(uint8_t evalcode,char *destaddr,CPubKey pk);
std::vector<uint8_t> Mypubkey();
UniValue AssetOrders(uint256 tokenid);
uint256 Parseuint256(char *hexstr)
{
@ -4844,6 +4852,54 @@ uint256 Parseuint256(char *hexstr)
return(txid);
}
UniValue tokenorders(const UniValue& params, bool fHelp)
{
uint256 tokenid;
if ( fHelp || params.size() > 1 )
throw runtime_error("tokenorders [tokenid]\n");
if ( params.size() == 1 )
tokenid = Parseuint256((char *)params[0].get_str().c_str());
else memset(&tokenid,0,sizeof(tokenid));
return(AssetOrders(tokenid));
}
UniValue tokenbalance(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); char destaddr[64]; CMutableTransaction mtx; uint256 tokenid; uin64_t balance; std::vector<unsigned char> pubkey;
if ( fHelp || params.size() > 2 )
throw runtime_error("tokenbalance tokenid [pubkey]\n");
tokenid = Parseuint256((char *)params[0].get_str().c_str());
if ( params.size() == 2 )
pubkey = ParseHex(params[1].get_str().c_str());
else pubkey = Mypubkey();
result.push_back(Pair("result", "success"));
if ( GetCCaddress(EVAL_ASSETS,destaddr,pubkey2pk(pubkey)) != 0 )
result.push_back(Pair("CCaddress",destaddr));
balance = AddCCinputs(mtx,pubkey2pk(pubkey),tokenid,0,0);
result.push_back(Pair("tokenid", params[0].get_str()));
result.push_back(Pair("balance", (int64_t)balance));
return(result);
}
UniValue tokenaddress(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::vector<unsigned char> pubkey; char destaddr[64];
if ( fHelp || params.size() > 1 )
throw runtime_error("tokenaddress [pubkey]\n");
result.push_back(Pair("result", "success"));
if ( GetCCaddress(EVAL_ASSETS,destaddr,pubkey2pk(pubkey)) != 0 )
result.push_back(Pair("AssetsCCaddress",destaddr));
if ( params.size() == 1 )
{
pubkey = ParseHex(params[0].get_str().c_str());
if ( GetCCaddress(EVAL_ASSETS,destaddr,pubkey2pk(pubkey)) != 0 )
result.push_back(Pair("CCaddress",destaddr));
}
if ( GetCCaddress(EVAL_ASSETS,destaddr,pubkey2pk(Mypubkey())) != 0 )
result.push_back(Pair("myCCaddress",destaddr));
return(result);
}
UniValue tokencreate(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string name,description,hex; uint64_t supply;
@ -4915,14 +4971,105 @@ UniValue tokencancelbid(const UniValue& params, bool fHelp)
UniValue tokenfillbid(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int32_t fillvout; std::string hex; uint256 tokenid,bidtxid,filltxid;
UniValue result(UniValue::VOBJ); uint64_t fillamount; std::string hex; uint256 tokenid,bidtxid;
if ( fHelp || params.size() != 3 )
throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n");
tokenid = Parseuint256((char *)params[0].get_str().c_str());
bidtxid = Parseuint256((char *)params[1].get_str().c_str());
fillamount = atol(params[2].get_str().c_str());
hex = FillBuyOffer(0,tokenid,bidtxid,fillamount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else result.push_back(Pair("error", "couldnt fill bid"));
return(result);
}
UniValue tokenask(const UniValue& params, bool fHelp)
{
static uint256 zeroid;
UniValue result(UniValue::VOBJ); uint64_t askamount,numtokens; std::string hex; double price; uint256 tokenid;
if ( fHelp || params.size() != 3 )
throw runtime_error("tokenask numtokens tokenid price\n");
numtokens = atoi(params[0].get_str().c_str());
tokenid = Parseuint256((char *)params[1].get_str().c_str());
price = atof(params[2].get_str().c_str());
askamount = (price * numtokens) * COIN + 0.0000000049999;
hex = CreateSell(0,numtokens,tokenid,zeroid,askamount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else result.push_back(Pair("error", "couldnt create ask"));
return(result);
}
UniValue tokenswapask(const UniValue& params, bool fHelp)
{
static uint256 zeroid;
UniValue result(UniValue::VOBJ); uint64_t askamount,numtokens; std::string hex; double price; uint256 tokenid,otherid;
if ( fHelp || params.size() != 4 )
throw runtime_error("tokenfillbid tokenid bidtxid filltxid fillvout\n");
throw runtime_error("tokenswap numtokens tokenid otherid price\n");
numtokens = atoi(params[0].get_str().c_str());
tokenid = Parseuint256((char *)params[1].get_str().c_str());
otherid = Parseuint256((char *)params[2].get_str().c_str());
price = atof(params[3].get_str().c_str());
askamount = (price * numtokens) * COIN + 0.0000000049999;
hex = CreateSell(0,numtokens,tokenid,otherid,askamount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else result.push_back(Pair("error", "couldnt create swap"));
return(result);
}
UniValue tokencancelask(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid;
if ( fHelp || params.size() != 2 )
throw runtime_error("tokencancelask tokenid asktxid\n");
tokenid = Parseuint256((char *)params[0].get_str().c_str());
bidtxid = Parseuint256((char *)params[1].get_str().c_str());
filltxid = Parseuint256((char *)params[2].get_str().c_str());
fillvout = atoi(params[3].get_str().c_str());
hex = FillBuyOffer(0,tokenid,bidtxid,filltxid,fillvout);
hex = CancelSell(0,tokenid,asktxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else result.push_back(Pair("error", "couldnt cancel bid"));
return(result);
}
UniValue tokenfillask(const UniValue& params, bool fHelp)
{
static uint256 zeroid;
UniValue result(UniValue::VOBJ); uint64_t fillamount; std::string hex; uint256 tokenid,asktxid;
if ( fHelp || params.size() != 3 )
throw runtime_error("tokenfillask tokenid asktxid fillamount\n");
tokenid = Parseuint256((char *)params[0].get_str().c_str());
asktxid = Parseuint256((char *)params[1].get_str().c_str());
fillamount = atol(params[2].get_str().c_str());
hex = FillSell(0,tokenid,zeroid,asktxid,fillamount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else result.push_back(Pair("error", "couldnt fill bid"));
return(result);
}
UniValue tokenfillswap(const UniValue& params, bool fHelp)
{
static uint256 zeroid;
UniValue result(UniValue::VOBJ); uint64_t fillamount; std::string hex; uint256 tokenid,otherid,asktxid;
if ( fHelp || params.size() != 4 )
throw runtime_error("tokenfillswap tokenid otherid asktxid fillamount\n");
tokenid = Parseuint256((char *)params[0].get_str().c_str());
otherid = Parseuint256((char *)params[1].get_str().c_str());
asktxid = Parseuint256((char *)params[2].get_str().c_str());
fillamount = atol(params[3].get_str().c_str());
hex = FillSell(0,tokenid,otherid,asktxid,fillamount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));

Loading…
Cancel
Save