]> Git Repo - VerusCoin.git/blob - src/cc/CCassetstx.cpp
Prevent bid for nonexistent assetid
[VerusCoin.git] / src / cc / CCassetstx.cpp
1 /******************************************************************************
2  * Copyright © 2014-2018 The SuperNET Developers.                             *
3  *                                                                            *
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.  *
7  *                                                                            *
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 *
11  *                                                                            *
12  * Removal or modification of this copyright notice is prohibited.            *
13  *                                                                            *
14  ******************************************************************************/
15
16 #include "CCassets.h"
17
18 // need allassets
19 // find asset
20
21 int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
22 {
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++)
28     {
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 )
33                 break;
34         if ( j != mtx.vin.size() )
35             continue;
36         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
37         {
38             if ( (nValue= IsAssetvout(price,origpubkey,vintx,vout,assetid)) > 0 )
39             {
40                 if ( total != 0 && maxinputs != 0 )
41                     mtx.vin.push_back(CTxIn(txid,vout,CScript()));
42                 nValue = it->second.satoshis;
43                 totalinputs += nValue;
44                 n++;
45                 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
46                     break;
47             }
48         }
49     }
50     return(totalinputs);
51 }
52
53 int64_t GetAssetBalance(CPubKey pk,uint256 tokenid)
54 {
55     CMutableTransaction mtx; struct CCcontract_info *cp,C;
56     cp = CCinit(&C,EVAL_ASSETS);
57     return(AddAssetInputs(cp,mtx,pk,tokenid,0,0));
58 }
59
60 UniValue AssetOrders(uint256 refassetid)
61 {
62     static uint256 zero;
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++)
67     {
68         txid = it->first.txhash;
69         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
70         {
71             if ( vintx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey)) != 0 )
72             {
73                 if ( refassetid != zero && assetid != refassetid )
74                 {
75                     //int32_t z;
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");
82                     continue;
83                 }
84                 if ( vintx.vout[it->first.index].nValue == 0 )
85                     continue;
86                 UniValue item(UniValue::VOBJ);
87                 funcidstr[0] = funcid;
88                 funcidstr[1] = 0;
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' )
93                 {
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));
98                 }
99                 else
100                 {
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));
105                 }
106                 if ( origpubkey.size() == 33 )
107                 {
108                     GetCCaddress(cp,origaddr,pubkey2pk(origpubkey));
109                     item.push_back(Pair("origaddress",origaddr));
110                 }
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)));
115                 if ( price > 0 )
116                 {
117                     if ( funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e' )
118                     {
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));
123                     }
124                     else
125                     {
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));
129                     }
130                 }
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);
133             }
134         }
135     }
136     return(result);
137 }
138
139 std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
140 {
141     CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C;
142     if ( assetsupply < 0 )
143     {
144         fprintf(stderr,"negative assetsupply %lld\n",(long long)assetsupply);
145         return(0);
146     }
147     cp = CCinit(&C,EVAL_ASSETS);
148     if ( name.size() > 32 || description.size() > 4096 )
149     {
150         fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
151         return(0);
152     }
153     if ( txfee == 0 )
154         txfee = 10000;
155     mypk = pubkey2pk(Mypubkey());
156     if ( AddNormalinputs(mtx,mypk,assetsupply+2*txfee,64) > 0 )
157     {
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)));
161     }
162     return(0);
163 }
164                
165 std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
166 {
167     CMutableTransaction mtx; CPubKey mypk; int64_t CCchange=0,inputs=0;  struct CCcontract_info *cp,C;
168     if ( total < 0 )
169     {
170         fprintf(stderr,"negative total %lld\n",(long long)total);
171         return(0);
172     }
173     cp = CCinit(&C,EVAL_ASSETS);
174     if ( txfee == 0 )
175         txfee = 10000;
176     mypk = pubkey2pk(Mypubkey());
177     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
178     {
179         /*n = outputs.size();
180         if ( n == amounts.size() )
181         {
182             for (i=0; i<n; i++)
183                 total += amounts[i];*/
184             if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
185             {
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)));
190                 if ( CCchange != 0 )
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());
195     }
196     return(0);
197 }
198
199 std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
200 {
201     CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx;
202     if ( bidamount < 0 || pricetotal < 0 )
203     {
204         fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal);
205         return(0);
206     }
207     if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
208     {
209         fprintf(stderr,"cant find assetid\n");
210         return(0);
211     }
212     cp = CCinit(&C,EVAL_ASSETS);
213     if ( txfee == 0 )
214         txfee = 10000;
215     mypk = pubkey2pk(Mypubkey());
216     if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 )
217     {
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())));
220     }
221     return(0);
222 }
223
224 std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal)
225 {
226     CMutableTransaction mtx; CPubKey mypk; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
227     if ( askamount < 0 || pricetotal < 0 )
228     {
229         fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
230         return(0);
231     }
232     cp = CCinit(&C,EVAL_ASSETS);
233     if ( txfee == 0 )
234         txfee = 10000;
235     mypk = pubkey2pk(Mypubkey());
236     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
237     {
238         if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
239         {
240             if ( inputs < askamount )
241                 askamount = inputs;
242             mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
243             if ( inputs > askamount )
244                 CCchange = (inputs - askamount);
245             if ( CCchange != 0 )
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");
250     }
251     fprintf(stderr,"need some native coins to place ask\n");
252     return(0);
253 }
254
255 std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal)
256 {
257     CMutableTransaction mtx; CPubKey mypk; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
258     if ( askamount < 0 || pricetotal < 0 )
259     {
260         fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
261         return(0);
262     }
263     cp = CCinit(&C,EVAL_ASSETS);
264     if ( txfee == 0 )
265         txfee = 10000;
266     mypk = pubkey2pk(Mypubkey());
267     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
268     {
269         if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
270         {
271             if ( inputs < askamount )
272                 askamount = inputs;
273             mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
274             if ( inputs > askamount )
275                 CCchange = (inputs - askamount);
276             if ( CCchange != 0 )
277                 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
278             if ( assetid2 == zeroid )
279                 opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
280             else
281             {
282                 opret = EncodeAssetOpRet('e',assetid,assetid2,pricetotal,Mypubkey());
283             }
284             return(FinalizeCCTx(cp,mtx,mypk,txfee,opret));
285         } else fprintf(stderr,"need some assets to place ask\n");
286     }
287     fprintf(stderr,"need some native coins to place ask\n");
288     return(0);
289 }
290
291 std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
292 {
293     CMutableTransaction mtx; CTransaction vintx; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C;
294     cp = CCinit(&C,EVAL_ASSETS);
295     if ( txfee == 0 )
296         txfee = 10000;
297     mypk = pubkey2pk(Mypubkey());
298     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
299     {
300         if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
301         {
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())));
306         }
307     }
308     return(0);
309 }
310
311 std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
312 {
313     CMutableTransaction mtx; CTransaction vintx; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C;
314     cp = CCinit(&C,EVAL_ASSETS);
315     if ( txfee == 0 )
316         txfee = 10000;
317     mypk = pubkey2pk(Mypubkey());
318     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
319     {
320         if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
321         {
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())));
326         }
327     }
328     return(0);
329 }
330
331 std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount)
332 {
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 )
335     {
336         fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount);
337         return(0);
338     }
339     cp = CCinit(&C,EVAL_ASSETS);
340     if ( txfee == 0 )
341         txfee = 10000;
342     mypk = pubkey2pk(Mypubkey());
343     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
344     {
345         if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
346         {
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 )
351             {
352                 if ( inputs < fillamount )
353                     fillamount = inputs;
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)));
360                 if ( CCchange != 0 )
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");
365         }
366     }
367     return("no normal coins left");
368 }
369
370 std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits)
371 {
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;
373     if ( fillunits < 0 )
374     {
375         fprintf(stderr,"negative fillunits %lld\n",(long long)fillunits);
376         return(0);
377     }
378     cp = CCinit(&C,EVAL_ASSETS);
379     if ( txfee == 0 )
380         txfee = 10000;
381     mypk = pubkey2pk(Mypubkey());
382     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
383     {
384         if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
385         {
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);
394             if ( inputs > 0 )
395             {
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));
406                 if ( CCchange != 0 )
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");
410         }
411     }
412     return(0);
413 }
This page took 0.045975 seconds and 4 git commands to generate.