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