1 /******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
4 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
5 * the top-level directory of this distribution for the individual copyright *
6 * holder information and the developer policies on copyright and licensing. *
8 * Unless otherwise agreed in a custom licensing agreement, no part of the *
9 * SuperNET software, including this file may be copied, modified, propagated *
10 * or distributed except according to the terms contained in the LICENSE file *
12 * Removal or modification of this copyright notice is prohibited. *
14 ******************************************************************************/
21 int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
23 char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
24 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
25 GetCCaddress(cp,coinaddr,pk);
26 SetCCunspents(unspentOutputs,coinaddr);
27 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
29 txid = it->first.txhash;
30 vout = (int32_t)it->first.index;
31 for (j=0; j<mtx.vin.size(); j++)
32 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
34 if ( j != mtx.vin.size() )
36 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
38 if ( (nValue= IsAssetvout(price,origpubkey,vintx,vout,assetid)) > 0 )
40 if ( total != 0 && maxinputs != 0 )
41 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
42 nValue = it->second.satoshis;
43 totalinputs += nValue;
45 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
53 int64_t GetAssetBalance(CPubKey pk,uint256 tokenid)
55 CMutableTransaction mtx; struct CCcontract_info *cp,C;
56 cp = CCinit(&C,EVAL_ASSETS);
57 return(AddAssetInputs(cp,mtx,pk,tokenid,0,0));
60 UniValue AssetOrders(uint256 refassetid)
63 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;
64 cp = CCinit(&C,EVAL_ASSETS);
65 SetCCunspents(unspentOutputs,(char *)cp->unspendableCCaddr);
66 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
68 txid = it->first.txhash;
69 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
71 if ( vintx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey)) != 0 )
73 if ( refassetid != zero && assetid != refassetid )
76 //for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]);
77 //fprintf(stderr," txid\n");
78 //for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&assetid)[z]);
79 //fprintf(stderr," assetid\n");
80 //for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]);
81 //fprintf(stderr," refassetid\n");
84 if ( vintx.vout[it->first.index].nValue == 0 )
86 UniValue item(UniValue::VOBJ);
87 funcidstr[0] = funcid;
89 item.push_back(Pair("funcid", funcidstr));
90 item.push_back(Pair("txid", uint256_str(assetidstr,txid)));
91 item.push_back(Pair("vout", (int64_t)it->first.index));
92 if ( funcid == 'b' || funcid == 'B' )
94 sprintf(numstr,"%.8f",(double)vintx.vout[it->first.index].nValue/COIN);
95 item.push_back(Pair("amount",numstr));
96 sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
97 item.push_back(Pair("bidamount",numstr));
101 sprintf(numstr,"%llu",(long long)vintx.vout[it->first.index].nValue);
102 item.push_back(Pair("amount",numstr));
103 sprintf(numstr,"%llu",(long long)vintx.vout[0].nValue);
104 item.push_back(Pair("askamount",numstr));
106 if ( origpubkey.size() == 33 )
108 GetCCaddress(cp,origaddr,pubkey2pk(origpubkey));
109 item.push_back(Pair("origaddress",origaddr));
111 if ( assetid != zeroid )
112 item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
113 if ( assetid2 != zeroid )
114 item.push_back(Pair("otherid",uint256_str(assetidstr,assetid2)));
117 if ( funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e' )
119 sprintf(numstr,"%.8f",(double)price / COIN);
120 item.push_back(Pair("totalrequired", numstr));
121 sprintf(numstr,"%.8f",(double)price / (COIN * vintx.vout[0].nValue));
122 item.push_back(Pair("price", numstr));
126 item.push_back(Pair("totalrequired", (int64_t)price));
127 sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue / (price * COIN));
128 item.push_back(Pair("price",numstr));
131 result.push_back(item);
132 //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);
139 std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
141 CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C;
142 if ( assetsupply < 0 )
144 fprintf(stderr,"negative assetsupply %lld\n",(long long)assetsupply);
147 cp = CCinit(&C,EVAL_ASSETS);
148 if ( name.size() > 32 || description.size() > 4096 )
150 fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
155 mypk = pubkey2pk(Mypubkey());
156 if ( AddNormalinputs(mtx,mypk,assetsupply+2*txfee,64) > 0 )
158 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,assetsupply,mypk));
159 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(cp->CChexstr) << OP_CHECKSIG));
160 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetCreateOpRet('c',Mypubkey(),name,description)));
165 std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
167 CMutableTransaction mtx; CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
170 fprintf(stderr,"negative total %lld\n",(long long)total);
173 cp = CCinit(&C,EVAL_ASSETS);
176 mypk = pubkey2pk(Mypubkey());
177 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
179 /*n = outputs.size();
180 if ( n == amounts.size() )
183 total += amounts[i];*/
184 if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
186 if ( inputs > total )
187 CCchange = (inputs - total);
188 //for (i=0; i<n; i++)
189 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,pubkey2pk(destpubkey)));
191 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
192 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
193 } else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
194 //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
199 std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
201 CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx;
202 if ( bidamount < 0 || pricetotal < 0 )
204 fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal);
207 if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
209 fprintf(stderr,"cant find assetid\n");
212 cp = CCinit(&C,EVAL_ASSETS);
215 mypk = pubkey2pk(Mypubkey());
216 if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 )
218 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount,GetUnspendable(cp,0)));
219 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetOpRet('b',assetid,zeroid,pricetotal,Mypubkey())));
224 std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal)
226 CMutableTransaction mtx; CPubKey mypk; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
227 if ( askamount < 0 || pricetotal < 0 )
229 fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
232 cp = CCinit(&C,EVAL_ASSETS);
235 mypk = pubkey2pk(Mypubkey());
236 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
238 if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
240 if ( inputs < askamount )
242 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
243 if ( inputs > askamount )
244 CCchange = (inputs - askamount);
246 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
247 opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
248 return(FinalizeCCTx(cp,mtx,mypk,txfee,opret));
249 } else fprintf(stderr,"need some assets to place ask\n");
251 fprintf(stderr,"need some native coins to place ask\n");
255 std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal)
257 CMutableTransaction mtx; CPubKey mypk; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
258 if ( askamount < 0 || pricetotal < 0 )
260 fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
263 cp = CCinit(&C,EVAL_ASSETS);
266 mypk = pubkey2pk(Mypubkey());
267 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
269 if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
271 if ( inputs < askamount )
273 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
274 if ( inputs > askamount )
275 CCchange = (inputs - askamount);
277 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
278 if ( assetid2 == zeroid )
279 opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
282 opret = EncodeAssetOpRet('e',assetid,assetid2,pricetotal,Mypubkey());
284 return(FinalizeCCTx(cp,mtx,mypk,txfee,opret));
285 } else fprintf(stderr,"need some assets to place ask\n");
287 fprintf(stderr,"need some native coins to place ask\n");
291 std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
293 CMutableTransaction mtx; CTransaction vintx; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C;
294 cp = CCinit(&C,EVAL_ASSETS);
297 mypk = pubkey2pk(Mypubkey());
298 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
300 if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
302 bidamount = vintx.vout[0].nValue;
303 mtx.vin.push_back(CTxIn(bidtxid,0,CScript()));
304 mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
305 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetOpRet('o',assetid,zeroid,0,Mypubkey())));
311 std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
313 CMutableTransaction mtx; CTransaction vintx; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C;
314 cp = CCinit(&C,EVAL_ASSETS);
317 mypk = pubkey2pk(Mypubkey());
318 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
320 if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
322 askamount = vintx.vout[0].nValue;
323 mtx.vin.push_back(CTxIn(asktxid,0,CScript()));
324 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,mypk));
325 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetOpRet('x',assetid,zeroid,0,Mypubkey())));
331 std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount)
333 CTransaction vintx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey; int32_t bidvout=0; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C;
334 if ( fillamount < 0 )
336 fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount);
339 cp = CCinit(&C,EVAL_ASSETS);
342 mypk = pubkey2pk(Mypubkey());
343 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
345 if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
347 bidamount = vintx.vout[bidvout].nValue;
348 SetAssetOrigpubkey(origpubkey,origprice,vintx);
349 mtx.vin.push_back(CTxIn(bidtxid,bidvout,CScript()));
350 if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,fillamount,60)) > 0 )
352 if ( inputs < fillamount )
354 SetBidFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
355 if ( inputs > fillamount )
356 CCchange = (inputs - fillamount);
357 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount - paid_amount,GetUnspendable(cp,0)));
358 mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
359 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,fillamount,pubkey2pk(origpubkey)));
361 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
362 fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required);
363 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetOpRet('B',assetid,zeroid,remaining_required,origpubkey)));
364 } else return("dont have any assets to fill bid\n");
367 return("no normal coins left");
370 std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits)
372 CTransaction vintx,filltx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector<uint8_t> origpubkey; double dprice; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C;
375 fprintf(stderr,"negative fillunits %lld\n",(long long)fillunits);
378 cp = CCinit(&C,EVAL_ASSETS);
381 mypk = pubkey2pk(Mypubkey());
382 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
384 if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
386 orig_assetoshis = vintx.vout[askvout].nValue;
387 SetAssetOrigpubkey(origpubkey,total_nValue,vintx);
388 dprice = (double)total_nValue / orig_assetoshis;
389 paid_nValue = dprice * fillunits;
390 mtx.vin.push_back(CTxIn(asktxid,askvout,CScript()));
391 if ( assetid2 != zeroid )
392 inputs = AddAssetInputs(cp,mtx,mypk,assetid2,paid_nValue,60);
393 else inputs = AddNormalinputs(mtx,mypk,paid_nValue,60);
396 if ( inputs < paid_nValue )
397 paid_nValue = inputs;
398 if ( assetid2 != zeroid )
399 SetSwapFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
400 else SetAskFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
401 if ( assetid2 != zeroid && inputs > paid_nValue )
402 CCchange = (inputs - paid_nValue);
403 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0)));
404 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk));
405 mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG));
407 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
408 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey)));
409 } else fprintf(stderr,"filltx not enough utxos\n");