]> Git Repo - VerusCoin.git/blame - src/cc/rewards.cpp
Test
[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
194ad5b8 38 */
39
f66eff04 40uint64_t RewardsCalc(uint64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
194ad5b8 41{
f66eff04 42 uint64_t duration,reward = 0;
43 if ( (duration= CCduration(txid)) < minseconds )
626f89e2 44 {
45 //return(0);
2e2244a2 46 duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24);
626f89e2 47 }
f66eff04 48 else if ( duration > maxseconds )
49 maxseconds = duration;
9f92a697 50 reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100);
d40b8630 51 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 52 return(reward);
53}
54
88acd162 55CScript EncodeRewardsFundingOpRet(uint8_t funcid,uint64_t sbits,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
6dcd15b5 56{
57 CScript opret; uint8_t evalcode = EVAL_REWARDS;
88acd162 58 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << APR << minseconds << maxseconds << mindeposit);
59 return(opret);
60}
61
62uint8_t DecodeRewardsFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit)
63{
64 std::vector<uint8_t> vopret; uint8_t *script,e,f;
65 GetOpReturnData(scriptPubKey, vopret);
66 script = (uint8_t *)vopret.data();
67 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 )
6dcd15b5 68 {
88acd162 69 if ( e == EVAL_REWARDS && f == 'F' )
70 return(f);
6dcd15b5 71 }
88acd162 72 return(0);
73}
74
c4e7f616 75CScript EncodeRewardsOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid)
88acd162 76{
77 CScript opret; uint8_t evalcode = EVAL_REWARDS;
c4e7f616 78 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid);
6dcd15b5 79 return(opret);
80}
81
c4e7f616 82uint8_t DecodeRewardsOpRet(const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid)
6dcd15b5 83{
88acd162 84 std::vector<uint8_t> vopret; uint8_t *script,e,f;
6dcd15b5 85 GetOpReturnData(scriptPubKey, vopret);
86 script = (uint8_t *)vopret.data();
c4e7f616 87 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid) != 0 )
6dcd15b5 88 {
eac2c15e 89 if ( e == EVAL_REWARDS && (f == 'L' || f == 'U' || f == 'A') )
88acd162 90 return(f);
6dcd15b5 91 }
88acd162 92 return(0);
6dcd15b5 93}
94
e04b5c08 95uint64_t IsRewardsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
194ad5b8 96{
97 char destaddr[64];
98 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
99 {
e04b5c08 100 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
194ad5b8 101 return(tx.vout[v].nValue);
102 }
103 return(0);
104}
105
287efad4 106bool RewardsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
194ad5b8 107{
108 static uint256 zerohash;
109 CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis;
110 numvins = tx.vin.size();
111 numvouts = tx.vout.size();
112 for (i=0; i<numvins; i++)
113 {
287efad4 114 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
194ad5b8 115 {
116 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
117 return eval->Invalid("always should find vin, but didnt");
118 else
119 {
120 if ( hashBlock == zerohash )
121 return eval->Invalid("cant rewards from mempool");
e04b5c08 122 if ( (assetoshis= IsRewardsvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
194ad5b8 123 inputs += assetoshis;
124 }
125 }
126 }
127 for (i=0; i<numvouts; i++)
128 {
129 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
e04b5c08 130 if ( (assetoshis= IsRewardsvout(cp,tx,i)) != 0 )
194ad5b8 131 outputs += assetoshis;
132 }
133 if ( inputs != outputs+COIN+txfee )
134 {
135 fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
136 return eval->Invalid("mismatched inputs != outputs + COIN + txfee");
137 }
138 else return(true);
139}
140
287efad4 141bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
194ad5b8 142{
143 int32_t numvins,numvouts,preventCCvins,preventCCvouts,i;
144 numvins = tx.vin.size();
145 numvouts = tx.vout.size();
146 preventCCvins = preventCCvouts = -1;
147 if ( numvouts < 1 )
148 return eval->Invalid("no vouts");
149 else
150 {
cfea7a46 151 // follow rules
194ad5b8 152 for (i=0; i<numvins; i++)
153 {
154 if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
155 return eval->Invalid("illegal normal vini");
156 }
287efad4 157 if ( RewardsExactAmounts(cp,eval,tx,1,10000) == false )
194ad5b8 158 return false;
159 else
160 {
161 preventCCvouts = 1;
e04b5c08 162 if ( IsRewardsvout(cp,tx,0) != 0 )
194ad5b8 163 {
164 preventCCvouts++;
165 i = 1;
166 } else i = 0;
167 if ( tx.vout[i].nValue != COIN )
168 return eval->Invalid("invalid rewards output");
169 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
170 }
171 }
172 return(true);
173}
174
791cf78c 175// 'L' vs 'F' and 'A'
176uint64_t AddRewardsInputs(int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
194ad5b8 177{
791cf78c 178 char coinaddr[64]; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
194ad5b8 179 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
e04b5c08 180 GetCCaddress(cp,coinaddr,pk);
194ad5b8 181 SetCCunspents(unspentOutputs,coinaddr);
182 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
183 {
184 txid = it->first.txhash;
fac87764 185 vout = (int32_t)it->first.index;
186 for (j=0; j<mtx.vin.size(); j++)
187 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
188 break;
189 if ( j != mtx.vin.size() )
190 continue;
feb9f834 191 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
194ad5b8 192 {
a89a76c4 193 if ( (funcid= DecodeRewardsFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit)) == 'F' || (funcid= DecodeRewardsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
194ad5b8 194 {
791cf78c 195 if ( fundsflag != 0 && funcid != 'F' && funcid != 'A' )
196 continue;
337c2501 197 else if ( fundsflag == 0 && (funcid != 'L' || tx.vout.size() < 4) )
791cf78c 198 continue;
194ad5b8 199 if ( total != 0 && maxinputs != 0 )
fac87764 200 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
cfea7a46 201 totalinputs += it->second.satoshis;
194ad5b8 202 n++;
203 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
204 break;
205 }
206 }
207 }
208 return(totalinputs);
209}
210
fac87764 211uint64_t RewardsPlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
cfea7a46 212{
4610bb91 213 char coinaddr[64]; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; uint8_t funcid;
cfea7a46 214 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
cfea7a46 215 GetCCaddress(cp,coinaddr,pk);
216 SetCCunspents(unspentOutputs,coinaddr);
217 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
218 {
fac87764 219 txid = it->first.txhash;
220 vout = (int32_t)it->first.index;
221 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 222 {
0efcb199 223 if ( (funcid= DecodeRewardsFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit)) == 'F' || (funcid= DecodeRewardsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'A' )
cfea7a46 224 {
fac87764 225 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
226 {
227 if ( refsbits == sbits && (nValue= IsRewardsvout(cp,tx,vout)) > 0 )
e90ab9d5 228 {
fac87764 229 totalinputs += nValue;
e90ab9d5 230 }
2205fd65 231 else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN);
e90ab9d5 232 } else fprintf(stderr,"else case\n");
64d610d4 233 } else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
cfea7a46 234 }
235 }
236 return(totalinputs);
237}
238
db6bfcc4 239bool RewardsPlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey rewardspk,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit)
eac2c15e 240{
db6bfcc4 241 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
fac87764 242 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
4610bb91 243 GetCCaddress(cp,CCaddr,rewardspk);
244 SetCCtxids(txids,CCaddr);
fac87764 245 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
246 {
247 //int height = it->first.blockHeight;
248 txid = it->first.txhash;
d18420d2 249 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
fac87764 250 {
d18420d2 251 if ( DecodeRewardsFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 'F' )
fac87764 252 {
253 if ( sbits == refsbits )
254 return(true);
255 }
256 }
257 }
258 return(false);
eac2c15e 259}
260
fdd22810 261UniValue RewardsInfo(uint256 rewardsid)
262{
46bbc433 263 UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; uint64_t APR,minseconds,maxseconds,mindeposit,sbits; char str[67],numstr[65];
fdd22810 264 if ( GetTransaction(rewardsid,vintx,hashBlock,false) == 0 )
265 {
bbf9b82f 266 fprintf(stderr,"cant find fundingtxid\n");
267 result.push_back(Pair("error","cant find fundingtxid"));
268 return(result);
fdd22810 269 }
bbf9b82f 270 if ( vintx.vout.size() > 0 && DecodeRewardsFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 0 )
fdd22810 271 {
bbf9b82f 272 fprintf(stderr,"fundingtxid isnt rewards creation txid\n");
273 result.push_back(Pair("error","fundingtxid isnt rewards creation txid"));
274 return(result);
fdd22810 275 }
276 result.push_back(Pair("result","success"));
277 result.push_back(Pair("fundingtxid",uint256_str(str,rewardsid)));
34589c80 278 unstringbits(str,sbits);
279 result.push_back(Pair("name",str));
d4e61763 280 result.push_back(Pair("sbits",sbits));
fdd22810 281 sprintf(numstr,"%.8f",(double)APR/COIN);
282 result.push_back(Pair("APR",numstr));
283 result.push_back(Pair("minseconds",minseconds));
284 result.push_back(Pair("maxseconds",maxseconds));
285 sprintf(numstr,"%.8f",(double)mindeposit/COIN);
286 result.push_back(Pair("mindeposit",numstr));
287 sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
288 result.push_back(Pair("funding",numstr));
289 return(result);
290}
291
292UniValue RewardsList()
293{
9fa1bcd2 294 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 295 cp = CCinit(&C,EVAL_REWARDS);
296 SetCCtxids(addressIndex,cp->normaladdr);
297 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
298 {
299 txid = it->first.txhash;
300 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
301 {
9fa1bcd2 302 if ( vintx.vout.size() > 0 && DecodeRewardsFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 0 )
fdd22810 303 {
304 result.push_back(uint256_str(str,txid));
305 }
306 }
307 }
308 return(result);
309}
310
8eee6bd8 311std::string RewardsCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t APR,int64_t minseconds,int64_t maxseconds,int64_t mindeposit)
194ad5b8 312{
db6bfcc4 313 CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C;
46bbc433 314 if ( funds < 0 || mindeposit < 0 || minseconds < 0 || maxseconds < 0 )
315 {
316 fprintf(stderr,"negative parameter error\n");
317 return(0);
318 }
e04b5c08 319 cp = CCinit(&C,EVAL_REWARDS);
194ad5b8 320 if ( txfee == 0 )
321 txfee = 10000;
322 mypk = pubkey2pk(Mypubkey());
e04b5c08 323 rewardspk = GetUnspendable(cp,0);
d549130d 324 sbits = stringbits(planstr);
db6bfcc4 325 if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) != 0 )
eac2c15e 326 {
2205fd65 327 fprintf(stderr,"Rewards plan (%s) already exists\n",planstr);
eac2c15e 328 return(0);
329 }
88acd162 330 if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 )
194ad5b8 331 {
cfea7a46 332 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,rewardspk));
88acd162 333 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(rewardspk)) << OP_CHECKSIG));
334 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeRewardsFundingOpRet('F',sbits,APR,minseconds,maxseconds,mindeposit)));
194ad5b8 335 }
88acd162 336 fprintf(stderr,"cant find enough inputs\n");
194ad5b8 337 return(0);
338}
339
46bbc433 340std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
e95b9582 341{
db6bfcc4 342 CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C;
46bbc433 343 if ( amount < 0 )
344 {
345 fprintf(stderr,"negative parameter error\n");
346 return(0);
347 }
e95b9582 348 cp = CCinit(&C,EVAL_REWARDS);
349 if ( txfee == 0 )
350 txfee = 10000;
351 mypk = pubkey2pk(Mypubkey());
352 rewardspk = GetUnspendable(cp,0);
d549130d 353 sbits = stringbits(planstr);
db6bfcc4 354 if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) == 0 )
e95b9582 355 {
eac2c15e 356 fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
357 return(0);
e95b9582 358 }
d4e61763 359 sbits = stringbits(planstr);
eac2c15e 360 if ( AddNormalinputs(mtx,mypk,amount+txfee,64) > 0 )
361 {
362 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,rewardspk));
363 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeRewardsOpRet('A',sbits,fundingtxid)));
364 } else fprintf(stderr,"cant find enough inputs\n");
365 fprintf(stderr,"cant find fundingtxid\n");
e95b9582 366 return(0);
367}
368
46bbc433 369std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t deposit)
194ad5b8 370{
87ccafbd 371 CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
46bbc433 372 if ( deposit < 0 )
373 {
374 fprintf(stderr,"negative parameter error\n");
375 return(0);
376 }
e04b5c08 377 cp = CCinit(&C,EVAL_REWARDS);
85c54375 378 if ( txfee == 0 )
379 txfee = 10000;
194ad5b8 380 mypk = pubkey2pk(Mypubkey());
cfea7a46 381 rewardspk = GetUnspendable(cp,0);
fac87764 382 sbits = stringbits(planstr);
1d801ae6 383 if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
384 {
385 fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
386 return(0);
387 }
388 if ( deposit < mindeposit )
389 {
390 fprintf(stderr,"Rewards plan %s deposit %.8f < mindeposit %.8f\n",planstr,(double)deposit/COIN,(double)mindeposit/COIN);
391 return(0);
392 }
393 if ( (funding= RewardsPlanFunds(sbits,cp,rewardspk,fundingtxid)) >= deposit ) // arbitrary cmpval
194ad5b8 394 {
791cf78c 395 if ( AddNormalinputs(mtx,mypk,deposit+2*txfee,64) > 0 )
cfea7a46 396 {
1d801ae6 397 mtx.vout.push_back(MakeCC1vout(cp->evalcode,deposit,rewardspk));
791cf78c 398 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
c4e7f616 399 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeRewardsOpRet('L',sbits,fundingtxid)));
9d2841c3 400 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)deposit/COIN);
cfea7a46 401 }
88acd162 402 fprintf(stderr,"cant find rewards inputs\n");
194ad5b8 403 return(0);
404}
405
9d2841c3 406std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
407{
408 CMutableTransaction mtx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript opret; uint64_t funding,sbits,reward,amount=0,inputs,CCchange=0,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
409 cp = CCinit(&C,EVAL_REWARDS);
410 if ( txfee == 0 )
411 txfee = 10000;
412 rewardspk = GetUnspendable(cp,0);
413 mypk = pubkey2pk(Mypubkey());
414 sbits = stringbits(planstr);
415 if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
416 {
417 fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
418 return(0);
419 }
791cf78c 420 // need to deal with finding the right utxos
9d2841c3 421 if ( locktxid == zeroid )
791cf78c 422 amount = AddRewardsInputs(0,cp,mtx,rewardspk,(1LL << 30),1);
9d2841c3 423 else
424 {
1d0c7762 425 GetCCaddress(cp,coinaddr,rewardspk);
9d2841c3 426 if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
427 {
b938be96 428 fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
9d2841c3 429 return(0);
430 }
431 mtx.vin.push_back(CTxIn(locktxid,0,CScript()));
432 }
433 if ( amount > 0 && (reward= RewardsCalc(amount,mtx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit)) > txfee )
434 {
feb9f834 435 if ( (inputs= AddRewardsInputs(1,cp,mtx,mypk,reward+amount+txfee,30)) > 0 )
9d2841c3 436 {
437 if ( inputs >= (amount + reward + 2*txfee) )
438 CCchange = (inputs - (amount + reward + txfee));
439 if ( CCchange != 0 )
440 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,rewardspk));
441 mtx.vout.push_back(CTxOut(amount+reward,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
442 return(FinalizeCCTx(cp,mtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid)));
443 }
444 fprintf(stderr,"cant find enough rewards inputs\n");
445 }
446 fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
447 return(0);
448}
194ad5b8 449
This page took 0.102297 seconds and 4 git commands to generate.