]>
Commit | Line | Data |
---|---|---|
c926780f | 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 "CCPrices.h" | |
17 | ||
18 | /* | |
366625ca | 19 | Prices CC would best build on top of the oracles CC, ie. to combine payments for multiple oracles and to calculate a 51% protected price feed. |
20 | ||
059f7e44 | 21 | We need to assume there is an oracle for a specific price. In the event there are more than one provider, the majority need to be within correlation distance to update a pricepoint. |
22 | ||
23 | int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format); | |
24 | ||
25 | Using the above function, a consensus price can be obtained for a datasource. | |
26 | ||
27 | given an oracletxid, the marketaddr and format can be extracted to be used for future calls to OraclePrice. This allows to set a starting price and that in turn allows cash settled leveraged trading! | |
28 | ||
29 | Funds work like with dice, ie. there is a Prices plan that traders bet against. | |
30 | ||
31 | PricesOpen -> oracletxid start with 'L' price, leverage, amount | |
32 | funds are locked into global CC address | |
33 | it can be closed at anytime by the trader for cash settlement | |
34 | the house account can close it if rekt | |
35 | ||
366625ca | 36 | |
c926780f | 37 | */ |
38 | ||
39 | // start of consensus code | |
40 | ||
41 | int64_t IsPricesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) | |
42 | { | |
43 | char destaddr[64]; | |
44 | if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) | |
45 | { | |
46 | if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) | |
47 | return(tx.vout[v].nValue); | |
48 | } | |
49 | return(0); | |
50 | } | |
51 | ||
52 | bool PricesExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) | |
53 | { | |
54 | static uint256 zerohash; | |
55 | CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; | |
56 | numvins = tx.vin.size(); | |
57 | numvouts = tx.vout.size(); | |
58 | for (i=0; i<numvins; i++) | |
59 | { | |
60 | //fprintf(stderr,"vini.%d\n",i); | |
61 | if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 ) | |
62 | { | |
63 | //fprintf(stderr,"vini.%d check mempool\n",i); | |
64 | if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) | |
65 | return eval->Invalid("cant find vinTx"); | |
66 | else | |
67 | { | |
68 | //fprintf(stderr,"vini.%d check hash and vout\n",i); | |
69 | if ( hashBlock == zerohash ) | |
70 | return eval->Invalid("cant Prices from mempool"); | |
71 | if ( (assetoshis= IsPricesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) | |
72 | inputs += assetoshis; | |
73 | } | |
74 | } | |
75 | } | |
76 | for (i=0; i<numvouts; i++) | |
77 | { | |
78 | //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts); | |
79 | if ( (assetoshis= IsPricesvout(cp,tx,i)) != 0 ) | |
80 | outputs += assetoshis; | |
81 | } | |
82 | if ( inputs != outputs+txfee ) | |
83 | { | |
84 | fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); | |
85 | return eval->Invalid("mismatched inputs != outputs + txfee"); | |
86 | } | |
87 | else return(true); | |
88 | } | |
89 | ||
90 | bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) | |
91 | { | |
92 | int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; | |
93 | return(false); | |
94 | std::vector<std::pair<CAddressIndexKey, CAmount> > txids; | |
95 | numvins = tx.vin.size(); | |
96 | numvouts = tx.vout.size(); | |
97 | preventCCvins = preventCCvouts = -1; | |
98 | if ( numvouts < 1 ) | |
99 | return eval->Invalid("no vouts"); | |
100 | else | |
101 | { | |
102 | for (i=0; i<numvins; i++) | |
103 | { | |
104 | if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) | |
105 | { | |
106 | return eval->Invalid("illegal normal vini"); | |
107 | } | |
108 | } | |
109 | //fprintf(stderr,"check amounts\n"); | |
110 | if ( PricesExactAmounts(cp,eval,tx,1,10000) == false ) | |
111 | { | |
112 | fprintf(stderr,"Pricesget invalid amount\n"); | |
113 | return false; | |
114 | } | |
115 | else | |
116 | { | |
117 | txid = tx.GetHash(); | |
118 | memcpy(hash,&txid,sizeof(hash)); | |
119 | retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); | |
120 | if ( retval != 0 ) | |
121 | fprintf(stderr,"Pricesget validated\n"); | |
122 | else fprintf(stderr,"Pricesget invalid\n"); | |
123 | return(retval); | |
124 | } | |
125 | } | |
126 | } | |
127 | // end of consensus code | |
128 | ||
129 | // helper functions for rpc calls in rpcwallet.cpp | |
130 | ||
131 | int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) | |
132 | { | |
133 | char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0; | |
134 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; | |
135 | GetCCaddress(cp,coinaddr,pk); | |
136 | SetCCunspents(unspentOutputs,coinaddr); | |
137 | for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) | |
138 | { | |
139 | txid = it->first.txhash; | |
140 | vout = (int32_t)it->first.index; | |
141 | // no need to prevent dup | |
142 | if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) | |
143 | { | |
144 | if ( (nValue= IsPricesvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) | |
145 | { | |
146 | if ( total != 0 && maxinputs != 0 ) | |
147 | mtx.vin.push_back(CTxIn(txid,vout,CScript())); | |
148 | nValue = it->second.satoshis; | |
149 | totalinputs += nValue; | |
150 | n++; | |
151 | if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) | |
152 | break; | |
153 | } | |
154 | } | |
155 | } | |
156 | return(totalinputs); | |
157 | } | |
158 | ||
059f7e44 | 159 | /* |
160 | UniValue PriceInfo(uint256 origtxid) | |
c926780f | 161 | { |
059f7e44 | 162 | UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ); |
163 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; | |
164 | CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey markerpubkey,pk; struct CCcontract_info *cp,C; uint8_t buf33[33]; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data; | |
165 | cp = CCinit(&C,EVAL_ORACLES); | |
166 | buf33[0] = 0x02; | |
167 | endiancpy(&buf33[1],(uint8_t *)&origtxid,32); | |
168 | markerpubkey = buf2pk(buf33); | |
169 | Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG); | |
170 | if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 ) | |
c926780f | 171 | { |
059f7e44 | 172 | if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) |
c926780f | 173 | { |
059f7e44 | 174 | result.push_back(Pair("result","success")); |
175 | result.push_back(Pair("txid",uint256_str(str,origtxid))); | |
176 | result.push_back(Pair("name",name)); | |
177 | result.push_back(Pair("description",description)); | |
178 | result.push_back(Pair("format",format)); | |
179 | result.push_back(Pair("marker",markeraddr)); | |
180 | SetCCunspents(unspentOutputs,markeraddr); | |
181 | for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) | |
c926780f | 182 | { |
059f7e44 | 183 | txid = it->first.txhash; |
184 | if ( GetTransaction(txid,regtx,hashBlock,false) != 0 ) | |
c926780f | 185 | { |
059f7e44 | 186 | if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid ) |
187 | { | |
188 | obj.push_back(Pair("provider",pubkey33_str(str,(uint8_t *)pk.begin()))); | |
189 | Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey); | |
190 | batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); | |
191 | obj.push_back(Pair("baton",batonaddr)); | |
192 | obj.push_back(Pair("batontxid",uint256_str(str,batontxid))); | |
193 | funding = LifetimeOraclesFunds(cp,oracletxid,pk); | |
194 | sprintf(numstr,"%.8f",(double)funding/COIN); | |
195 | obj.push_back(Pair("lifetime",numstr)); | |
196 | funding = AddOracleInputs(cp,mtx,pk,0,0); | |
197 | sprintf(numstr,"%.8f",(double)funding/COIN); | |
198 | obj.push_back(Pair("funds",numstr)); | |
199 | sprintf(numstr,"%.8f",(double)datafee/COIN); | |
200 | obj.push_back(Pair("datafee",numstr)); | |
201 | a.push_back(obj); | |
202 | } | |
c926780f | 203 | } |
c926780f | 204 | } |
059f7e44 | 205 | result.push_back(Pair("registered",a)); |
c926780f | 206 | } |
059f7e44 | 207 | } |
208 | return(result); | |
c926780f | 209 | } |
210 | ||
059f7e44 | 211 | UniValue PricesList() |
c926780f | 212 | { |
059f7e44 | 213 | UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65]; |
214 | cp = CCinit(&C,EVAL_ORACLES); | |
215 | SetCCtxids(addressIndex,cp->normaladdr); | |
216 | for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) | |
c926780f | 217 | { |
059f7e44 | 218 | txid = it->first.txhash; |
219 | if ( GetTransaction(txid,createtx,hashBlock,false) != 0 ) | |
220 | { | |
221 | if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) | |
222 | { | |
223 | result.push_back(uint256_str(str,txid)); | |
224 | } | |
225 | } | |
c926780f | 226 | } |
c926780f | 227 | return(result); |
228 | } | |
059f7e44 | 229 | */ |