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