]> Git Repo - VerusCoin.git/blame - src/cc/rewards.cpp
-print
[VerusCoin.git] / src / cc / rewards.cpp
CommitLineData
194ad5b8 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 "CCinclude.h"
17
18/*
cfea7a46 19 The rewards CC contract is initially for OOT, which needs this functionality. However, many of the attributes can be parameterized to allow different rewards programs to run. Multiple rewards plans could even run on the same blockchain, though the user would need to choose which one to lock funds into.
20
21 At the high level, the user would lock funds for some amount of time and at the end of it, would get all the locked funds back with an additional reward. So there needs to be a lock funds and unlock funds ability. Additionally, the rewards need to come from somewhere, so similar to the faucet, there would be a way to fund the reward.
22
23 Additional requirements are for the user to be able to lock funds via SPV. This requirement in turns forces the creation of a way for anybody to be able to unlock the funds as that operation requires a native daemon running and cant be done over SPV. The idea is to allow anybody to run a script that would unlock all funds that are matured. As far as the user is concerned, he locks his funds via SPV and after some time it comes back with an extra reward.
24
25 In reality, the funds are locked into a CC address that is unspendable, except for some special conditions and it needs to come back to the address that funded the lock. In order to implement this, several things are clear.
26
27 1) each locked CC utxo needs to be linked to a specific rewards plan
28 2) each locked CC utxo needs to know the only address that it can be unlocked into
29 3) SPV requirement means the lock transaction needs to be able to be created without any CC signing
30
31 The opreturn will be used to store the name of the rewards plan and all funding and locked funds with the same plan will use the same pool of rewards. plan names will be limited to 8 chars and encoded into a uint64_t.
32
33 The initial funding transaction will have all the parameters for the rewards plan encoded in the vouts. Additional fundings will just increase the available CC utxo for the rewards.
34
35 Locks wont have any CC vins, but will send to the RewardsCCaddress, with the plan stringbits in the opreturn. vout1 will have the unlock address and no other destination is valid.
36
37 Unlock does a CC spend to the vout1 address
d5dae053 38
39
40 createfunding
41 vins.*: normal inputs
42 vout.0: CC vout for funding
43 vout.1: normal marker vout for easy searching
44 vout.2: normal change
45 vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit
46
47 addfunding
48 vins.*: normal inputs
49 vout.0: CC vout for funding
50 vout.1: normal change
51 vout.n-1: opreturn 'A' sbits fundingtxid
52
53 lock
54 vins.*: normal inputs
55 vout.0: CC vout for locked funds
56 vout.1: normal output to unlock address
57 vout.2: change
58 vout.n-1: opreturn 'L' sbits fundingtxid
59
60 unlock
61 vin.0: locked funds CC vout.0 from lock
62 vin.1+: funding CC vout.0 from 'F' and 'A' and 'U'
63 vout.0: funding CC change
64 vout.1: normal output to unlock address
65 vout.n-1: opreturn 'U' sbits fundingtxid
66
194ad5b8 67 */
68
f66eff04 69uint64_t RewardsCalc(uint64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
194ad5b8 70{
da07d84b 71 int32_t numblocks; uint64_t duration,reward = 0;
10078e85 72 fprintf(stderr,"minseconds %llu maxseconds %llu\n",(long long)minseconds,(long long)maxseconds);
da07d84b 73 if ( (duration= CCduration(numblocks,txid)) < minseconds )
626f89e2 74 {
fb89b441 75 fprintf(stderr,"duration %llu < minseconds %llu\n",(long long)duration,(long long)minseconds);
572ce781 76 return(0);
77 //duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24);
59f69770 78 } else if ( duration > maxseconds )
10078e85 79 duration = maxseconds;
9f92a697 80 reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100);
d40b8630 81 fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/COIN);
194ad5b8 82 return(reward);
83}
84
88acd162 85CScript EncodeRewardsFundingOpRet(uint8_t funcid,uint64_t sbits,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
6dcd15b5 86{
87 CScript opret; uint8_t evalcode = EVAL_REWARDS;
88acd162 88 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << APR << minseconds << maxseconds << mindeposit);
89 return(opret);
90}
91
92uint8_t DecodeRewardsFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit)
93{
94 std::vector<uint8_t> vopret; uint8_t *script,e,f;
95 GetOpReturnData(scriptPubKey, vopret);
96 script = (uint8_t *)vopret.data();
0af767e0 97 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 )
6dcd15b5 98 {
88acd162 99 if ( e == EVAL_REWARDS && f == 'F' )
100 return(f);
6dcd15b5 101 }
88acd162 102 return(0);
103}
104
c4e7f616 105CScript EncodeRewardsOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid)
88acd162 106{
107 CScript opret; uint8_t evalcode = EVAL_REWARDS;
c4e7f616 108 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid);
6dcd15b5 109 return(opret);
110}
111
0af767e0 112uint8_t DecodeRewardsOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid)
6dcd15b5 113{
9f2d38b3 114 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; uint64_t APR,minseconds,maxseconds,mindeposit;
6dcd15b5 115 GetOpReturnData(scriptPubKey, vopret);
0af767e0 116 if ( vopret.size() > 2 )
6dcd15b5 117 {
0af767e0 118 script = (uint8_t *)vopret.data();
119 if ( script[0] == EVAL_REWARDS )
120 {
121 if ( script[1] == 'F' )
122 {
cb35ec92 123 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 )
85afb4f0 124 {
0af767e0 125 fundingtxid = txid;
85afb4f0 126 return('F');
127 } else fprintf(stderr,"unmarshal error for F\n");
0af767e0 128 }
129 else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid) != 0 )
130 {
131 if ( e == EVAL_REWARDS && (f == 'L' || f == 'U' || f == 'A') )
132 return(f);
cb35ec92 133 else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
0af767e0 134 }
cb35ec92 135 } else fprintf(stderr,"script[0] %02x != EVAL_REWARDS\n",script[0]);
5641892d 136 } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
88acd162 137 return(0);
6dcd15b5 138}
139
112803d8 140uint64_t IsRewardsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,uint64_t refsbits,uint256 reffundingtxid)
194ad5b8 141{
112803d8 142 char destaddr[64]; uint64_t sbits; uint256 fundingtxid,txid; uint8_t funcid; int32_t numvouts;
143 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 && (numvouts= (int32_t)tx.vout.size()) > 0 )
194ad5b8 144 {
112803d8 145 txid = tx.GetHash();
146 if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 && sbits == refsbits && (fundingtxid == reffundingtxid || txid == reffundingtxid) )
147 {
148
149 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
150 return(tx.vout[v].nValue);
151 }
194ad5b8 152 }
153 return(0);
154}
155
112803d8 156bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee,uint64_t refsbits,uint256 reffundingtxid)
194ad5b8 157{
158 static uint256 zerohash;
0af767e0 159 CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis;
194ad5b8 160 numvins = tx.vin.size();
161 numvouts = tx.vout.size();
162 for (i=0; i<numvins; i++)
163 {
287efad4 164 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
194ad5b8 165 {
166 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
167 return eval->Invalid("always should find vin, but didnt");
168 else
169 {
170 if ( hashBlock == zerohash )
171 return eval->Invalid("cant rewards from mempool");
112803d8 172 if ( (assetoshis= IsRewardsvout(cp,vinTx,tx.vin[i].prevout.n,refsbits,reffundingtxid)) != 0 )
194ad5b8 173 inputs += assetoshis;
174 }
175 }
176 }
177 for (i=0; i<numvouts; i++)
178 {
179 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
112803d8 180 if ( (assetoshis= IsRewardsvout(cp,tx,i,refsbits,reffundingtxid)) != 0 )
194ad5b8 181 outputs += assetoshis;
182 }
0af767e0 183 if ( inputs != outputs+txfee )
194ad5b8 184 {
185 fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
0af767e0 186 return eval->Invalid("mismatched inputs != outputs + txfee");
194ad5b8 187 }
188 else return(true);
189}
190
287efad4 191bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
194ad5b8 192{
9f2d38b3 193 uint256 txid,fundingtxid,hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
194ad5b8 194 numvins = tx.vin.size();
195 numvouts = tx.vout.size();
196 preventCCvins = preventCCvouts = -1;
197 if ( numvouts < 1 )
198 return eval->Invalid("no vouts");
199 else
200 {
0af767e0 201 txid = tx.GetHash();
202 if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
194ad5b8 203 {
0af767e0 204 if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
205 return eval->Invalid("cant find fundingtxid");
206 else if ( fundingTx.vout.size() > 0 && DecodeRewardsFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 'F' )
207 return eval->Invalid("fundingTx not valid");
208 switch ( funcid )
194ad5b8 209 {
0af767e0 210 case 'F':
211 //vins.*: normal inputs
212 //vout.0: CC vout for funding
213 //vout.1: normal marker vout for easy searching
214 //vout.2: normal change
215 //vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit
216 return eval->Invalid("unexpected RewardsValidate for createfunding");
217 break;
218 case 'A':
219 //vins.*: normal inputs
220 //vout.0: CC vout for funding
221 //vout.1: normal change
222 //vout.n-1: opreturn 'A' sbits fundingtxid
223 return eval->Invalid("unexpected RewardsValidate for addfunding");
224 break;
225 case 'L':
226 //vins.*: normal inputs
227 //vout.0: CC vout for locked funds
228 //vout.1: normal output to unlock address
229 //vout.2: change
230 //vout.n-1: opreturn 'L' sbits fundingtxid
231 return eval->Invalid("unexpected RewardsValidate for lock");
232 break;
233 case 'U':
234 //vin.0: locked funds CC vout.0 from lock
235 //vin.1+: funding CC vout.0 from 'F' and 'A' and 'U'
236 //vout.0: funding CC change
237 //vout.1: normal output to unlock address
238 //vout.n-1: opreturn 'U' sbits fundingtxid
239 for (i=0; i<numvins; i++)
240 {
241 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
242 return eval->Invalid("unexpected normal vin for unlock");
243 }
112803d8 244 if ( RewardsExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue,sbits,fundingtxid) == 0 )
0af767e0 245 return false;
246 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
247 return eval->Invalid("always should find vin.0, but didnt");
248 else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
249 return eval->Invalid("lock tx vout.0 is normal output");
250 else if ( tx.vout.size() < 3 )
251 return eval->Invalid("unlock tx not enough vouts");
252 else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
253 return eval->Invalid("unlock tx vout.0 is normal output");
9f2d38b3 254 else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
0af767e0 255 return eval->Invalid("unlock tx vout.1 is CC output");
763ec3ca 256 else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey )
257 return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey");
0af767e0 258 amount = vinTx.vout[0].nValue;
43b91cca 259 reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);
0af767e0 260 if ( tx.vout[1].nValue > amount+reward )
261 return eval->Invalid("unlock tx vout.1 isnt amount+reward");
262 preventCCvouts = 1;
263 break;
264 }
194ad5b8 265 }
0af767e0 266 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
194ad5b8 267 }
268 return(true);
269}
270
791cf78c 271// 'L' vs 'F' and 'A'
112803d8 272uint64_t AddRewardsInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs,uint64_t refsbits,uint256 reffundingtxid)
194ad5b8 273{
d0d96ab0 274 char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
194ad5b8 275 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
e04b5c08 276 GetCCaddress(cp,coinaddr,pk);
194ad5b8 277 SetCCunspents(unspentOutputs,coinaddr);
278 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
279 {
280 txid = it->first.txhash;
fac87764 281 vout = (int32_t)it->first.index;
93ac96fa 282 if ( it->second.satoshis < 1000000 )
c2342f7b 283 continue;
1cbb6e13 284 fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
fac87764 285 for (j=0; j<mtx.vin.size(); j++)
286 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
287 break;
288 if ( j != mtx.vin.size() )
289 continue;
6deb8c09 290 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
194ad5b8 291 {
0af767e0 292 if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
194ad5b8 293 {
112803d8 294 if ( sbits != refsbits || fundingtxid != reffundingtxid )
295 continue;
242ba739 296 fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
d5dae053 297 if ( fundsflag != 0 && funcid != 'F' && funcid != 'A' && funcid != 'U' )
791cf78c 298 continue;
337c2501 299 else if ( fundsflag == 0 && (funcid != 'L' || tx.vout.size() < 4) )
791cf78c 300 continue;
194ad5b8 301 if ( total != 0 && maxinputs != 0 )
d5dae053 302 {
303 if ( fundsflag == 0 )
304 scriptPubKey = tx.vout[1].scriptPubKey;
fac87764 305 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
d5dae053 306 }
cfea7a46 307 totalinputs += it->second.satoshis;
194ad5b8 308 n++;
309 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
310 break;
93637d45 311 } else fprintf(stderr,"null funcid\n");
194ad5b8 312 }
313 }
314 return(totalinputs);
315}
316
fac87764 317uint64_t RewardsPlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
cfea7a46 318{
d0d96ab0 319 char coinaddr[64]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; uint8_t funcid;
cfea7a46 320 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
cfea7a46 321 GetCCaddress(cp,coinaddr,pk);
322 SetCCunspents(unspentOutputs,coinaddr);
323 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
324 {
fac87764 325 txid = it->first.txhash;
326 vout = (int32_t)it->first.index;
327 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 328 {
0af767e0 329 if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
cfea7a46 330 {
fac87764 331 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
332 {
112803d8 333 if ( refsbits == sbits && (nValue= IsRewardsvout(cp,tx,vout,sbits,fundingtxid)) > 0 )
fac87764 334 totalinputs += nValue;
2205fd65 335 else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN);
ba30129f 336 } //else fprintf(stderr,"else case\n");
64d610d4 337 } else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
cfea7a46 338 }
339 }
340 return(totalinputs);
341}
342
db6bfcc4 343bool RewardsPlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey rewardspk,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit)
eac2c15e 344{
db6bfcc4 345 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
fac87764 346 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
4610bb91 347 GetCCaddress(cp,CCaddr,rewardspk);
348 SetCCtxids(txids,CCaddr);
fac87764 349 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
350 {
351 //int height = it->first.blockHeight;
352 txid = it->first.txhash;
d18420d2 353 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
fac87764 354 {
d0d96ab0 355 //char str[65]; fprintf(stderr,"rewards plan %s\n",uint256_str(str,txid));
d18420d2 356 if ( DecodeRewardsFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 'F' )
fac87764 357 {
358 if ( sbits == refsbits )
359 return(true);
360 }
361 }
362 }
363 return(false);
eac2c15e 364}
365
fdd22810 366UniValue RewardsInfo(uint256 rewardsid)
367{
94ada5ec 368 UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; uint64_t APR,minseconds,maxseconds,mindeposit,sbits,funding; CPubKey rewardspk; struct CCcontract_info *cp,C; char str[67],numstr[65];
fdd22810 369 if ( GetTransaction(rewardsid,vintx,hashBlock,false) == 0 )
370 {
bbf9b82f 371 fprintf(stderr,"cant find fundingtxid\n");
372 result.push_back(Pair("error","cant find fundingtxid"));
373 return(result);
fdd22810 374 }
bbf9b82f 375 if ( vintx.vout.size() > 0 && DecodeRewardsFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 0 )
fdd22810 376 {
bbf9b82f 377 fprintf(stderr,"fundingtxid isnt rewards creation txid\n");
378 result.push_back(Pair("error","fundingtxid isnt rewards creation txid"));
379 return(result);
fdd22810 380 }
381 result.push_back(Pair("result","success"));
382 result.push_back(Pair("fundingtxid",uint256_str(str,rewardsid)));
34589c80 383 unstringbits(str,sbits);
384 result.push_back(Pair("name",str));
d4e61763 385 result.push_back(Pair("sbits",sbits));
fdd22810 386 sprintf(numstr,"%.8f",(double)APR/COIN);
387 result.push_back(Pair("APR",numstr));
388 result.push_back(Pair("minseconds",minseconds));
389 result.push_back(Pair("maxseconds",maxseconds));
390 sprintf(numstr,"%.8f",(double)mindeposit/COIN);
391 result.push_back(Pair("mindeposit",numstr));
94ada5ec 392 cp = CCinit(&C,EVAL_REWARDS);
393 rewardspk = GetUnspendable(cp,0);
394 funding = RewardsPlanFunds(sbits,cp,rewardspk,rewardsid);
395 sprintf(numstr,"%.8f",(double)funding/COIN);
fdd22810 396 result.push_back(Pair("funding",numstr));
397 return(result);
398}
399
400UniValue RewardsList()
401{
9fa1bcd2 402 UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; char str[65];
fdd22810 403 cp = CCinit(&C,EVAL_REWARDS);
404 SetCCtxids(addressIndex,cp->normaladdr);
405 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
406 {
407 txid = it->first.txhash;
408 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
409 {
9fa1bcd2 410 if ( vintx.vout.size() > 0 && DecodeRewardsFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 0 )
fdd22810 411 {
412 result.push_back(uint256_str(str,txid));
413 }
414 }
415 }
416 return(result);
417}
418
8eee6bd8 419std::string RewardsCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t APR,int64_t minseconds,int64_t maxseconds,int64_t mindeposit)
194ad5b8 420{
db6bfcc4 421 CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C;
d587c96c 422 if ( funds < COIN || mindeposit < 0 || minseconds < 0 || maxseconds < 0 )
46bbc433 423 {
424 fprintf(stderr,"negative parameter error\n");
425 return(0);
426 }
e04b5c08 427 cp = CCinit(&C,EVAL_REWARDS);
194ad5b8 428 if ( txfee == 0 )
429 txfee = 10000;
430 mypk = pubkey2pk(Mypubkey());
e04b5c08 431 rewardspk = GetUnspendable(cp,0);
d549130d 432 sbits = stringbits(planstr);
db6bfcc4 433 if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) != 0 )
eac2c15e 434 {
2205fd65 435 fprintf(stderr,"Rewards plan (%s) already exists\n",planstr);
eac2c15e 436 return(0);
437 }
88acd162 438 if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 )
194ad5b8 439 {
cfea7a46 440 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,rewardspk));
88acd162 441 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(rewardspk)) << OP_CHECKSIG));
6e281d1c 442 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsFundingOpRet('F',sbits,APR,minseconds,maxseconds,mindeposit)));
194ad5b8 443 }
88acd162 444 fprintf(stderr,"cant find enough inputs\n");
194ad5b8 445 return(0);
446}
447
46bbc433 448std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
e95b9582 449{
db6bfcc4 450 CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C;
46bbc433 451 if ( amount < 0 )
452 {
453 fprintf(stderr,"negative parameter error\n");
454 return(0);
455 }
e95b9582 456 cp = CCinit(&C,EVAL_REWARDS);
457 if ( txfee == 0 )
458 txfee = 10000;
459 mypk = pubkey2pk(Mypubkey());
460 rewardspk = GetUnspendable(cp,0);
d549130d 461 sbits = stringbits(planstr);
db6bfcc4 462 if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) == 0 )
e95b9582 463 {
eac2c15e 464 fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
465 return(0);
e95b9582 466 }
d4e61763 467 sbits = stringbits(planstr);
eac2c15e 468 if ( AddNormalinputs(mtx,mypk,amount+txfee,64) > 0 )
469 {
470 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,rewardspk));
6e281d1c 471 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsOpRet('A',sbits,fundingtxid)));
eac2c15e 472 } else fprintf(stderr,"cant find enough inputs\n");
473 fprintf(stderr,"cant find fundingtxid\n");
e95b9582 474 return(0);
475}
476
46bbc433 477std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t deposit)
194ad5b8 478{
87ccafbd 479 CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
46bbc433 480 if ( deposit < 0 )
481 {
482 fprintf(stderr,"negative parameter error\n");
483 return(0);
484 }
e04b5c08 485 cp = CCinit(&C,EVAL_REWARDS);
85c54375 486 if ( txfee == 0 )
487 txfee = 10000;
194ad5b8 488 mypk = pubkey2pk(Mypubkey());
cfea7a46 489 rewardspk = GetUnspendable(cp,0);
fac87764 490 sbits = stringbits(planstr);
1d801ae6 491 if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
492 {
493 fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
494 return(0);
495 }
496 if ( deposit < mindeposit )
497 {
498 fprintf(stderr,"Rewards plan %s deposit %.8f < mindeposit %.8f\n",planstr,(double)deposit/COIN,(double)mindeposit/COIN);
499 return(0);
500 }
501 if ( (funding= RewardsPlanFunds(sbits,cp,rewardspk,fundingtxid)) >= deposit ) // arbitrary cmpval
194ad5b8 502 {
791cf78c 503 if ( AddNormalinputs(mtx,mypk,deposit+2*txfee,64) > 0 )
cfea7a46 504 {
1d801ae6 505 mtx.vout.push_back(MakeCC1vout(cp->evalcode,deposit,rewardspk));
791cf78c 506 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
6e281d1c 507 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsOpRet('L',sbits,fundingtxid)));
9d2841c3 508 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)deposit/COIN);
cfea7a46 509 }
88acd162 510 fprintf(stderr,"cant find rewards inputs\n");
194ad5b8 511 return(0);
512}
513
9d2841c3 514std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
515{
d5dae053 516 CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript opret,scriptPubKey,ignore; uint256 hashBlock; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
9d2841c3 517 cp = CCinit(&C,EVAL_REWARDS);
518 if ( txfee == 0 )
519 txfee = 10000;
520 rewardspk = GetUnspendable(cp,0);
521 mypk = pubkey2pk(Mypubkey());
522 sbits = stringbits(planstr);
523 if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
524 {
525 fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
526 return(0);
527 }
ba30129f 528 fprintf(stderr,"APR %.8f minseconds.%llu maxseconds.%llu mindeposit %.8f\n",(double)APR/COIN,(long long)minseconds,(long long)maxseconds,(double)mindeposit/COIN);
9d2841c3 529 if ( locktxid == zeroid )
112803d8 530 amount = AddRewardsInputs(scriptPubKey,0,cp,mtx,rewardspk,(1LL << 30),1,sbits,fundingtxid);
9d2841c3 531 else
532 {
1d0c7762 533 GetCCaddress(cp,coinaddr,rewardspk);
9d2841c3 534 if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
535 {
b938be96 536 fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
9d2841c3 537 return(0);
538 }
d5dae053 539 if ( GetTransaction(locktxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
540 {
4f839b5c 541 scriptPubKey = tx.vout[1].scriptPubKey;
d5dae053 542 mtx.vin.push_back(CTxIn(locktxid,0,CScript()));
543 }
544 else
545 {
546 fprintf(stderr,"%s no normal vout.1 in locktxid\n",coinaddr);
547 return(0);
548 }
9d2841c3 549 }
d5dae053 550 if ( amount > 0 && (reward= RewardsCalc(amount,mtx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit)) > txfee && scriptPubKey.size() > 0 )
9d2841c3 551 {
112803d8 552 if ( (inputs= AddRewardsInputs(ignore,1,cp,mtx,rewardspk,reward+txfee,30,sbits,fundingtxid)) > 0 )
9d2841c3 553 {
d5dae053 554 if ( inputs >= (reward + 2*txfee) )
555 CCchange = (inputs - (reward + txfee));
82381395 556 fprintf(stderr,"inputs %.8f CCchange %.8f amount %.8f reward %.8f\n",(double)inputs/COIN,(double)CCchange/COIN,(double)amount/COIN,(double)reward/COIN);
31ffb5c5 557 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,rewardspk));
d5dae053 558 mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey));
d2aba1d6 559 return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid)));
9d2841c3 560 }
561 fprintf(stderr,"cant find enough rewards inputs\n");
562 }
563 fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
564 return(0);
565}
194ad5b8 566
This page took 0.18964 seconds and 4 git commands to generate.