Skip prices
[VerusCoin.git] / src / cc / gateways.cpp
CommitLineData
c926780f 1/******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
3 * *
4 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
5 * the top-level directory of this distribution for the individual copyright *
6 * holder information and the developer policies on copyright and licensing. *
7 * *
8 * Unless otherwise agreed in a custom licensing agreement, no part of the *
9 * SuperNET software, including this file may be copied, modified, propagated *
10 * or distributed except according to the terms contained in the LICENSE file *
11 * *
12 * Removal or modification of this copyright notice is prohibited. *
13 * *
14 ******************************************************************************/
15
16#include "CCGateways.h"
17
18/*
366625ca 19 Uses MofN CC's normal msig handling to create automated deposits -> token issuing. And partial signing by the selected pubkeys for releasing the funds. A user would be able to select which pubkeys to use to construct the automated deposit/redeem multisigs.
20
21 the potential pubkeys to be used would be based on active oracle data providers with recent activity.
22
3515c101 23 bind asset <-> KMD gateway deposit address
24 KMD deposit -> globally spendable marker utxo
25 spend marker utxo and spend linked/locked asset to user's CC address
26
27 redeem -> asset to global CC address with withdraw address -> gateway spendable marker utxo
28 spend market utxo and withdraw from gateway deposit address
29
30 rpc calls:
31 GatewayList
32 GatewayInfo bindtxid
33 GatewayBind coin tokenid M N pubkey(s)
34 external: deposit to depositaddr with claimpubkey
35 GatewayDeposit coin tokenid external.deposittxid -> markertxid
36 GatewayClaim coin tokenid external.deposittxid markertxid -> spend marker and deposit asset
37
38 GatewayWithdraw coin tokenid withdrawaddr
39 external: do withdraw to withdrawaddr and spend marker, support for partial signatures and autocomplete
40
41 deposit addr can be 1 to MofN pubkeys
42 1:1 gateway with native coin
366625ca 43
c926780f 44*/
45
46// start of consensus code
47
3515c101 48CScript EncodeGatewaysBindOpRet(uint8_t funcid,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2)
49{
50 CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
51 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys);
52 return(opret);
53}
54
55CScript EncodeGatewaysOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector<struct oracle_merklepair> publishers,int32_t height,uint256 cointxid,std::string deposithex,std::vector<uint256>proof,std::vector<uint8_t> redeemscript,int64_t amount)
56{
57 CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
58 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << height << cointxid << deposithex << proof << redeemscript << amount);
59 return(opret);
60}
61
62uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector<struct oracle_merklepair> &publishers,int32_t &height,uint256 &cointxid,std::string &deposithex,std::vector<uint256> &proof,std::vector<uint8_t> &redeemscript,int64_t &amount)
63{
64 std::vector<uint8_t> vopret; uint8_t *script,e,f;
65 GetOpReturnData(scriptPubKey, vopret);
66 script = (uint8_t *)vopret.data();
67 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> height; ss >> cointxid; ss >> deposithex; ss >> proof; ss >> redeemscript; ss >> amount) != 0 )
68 {
69 return(f);
70 }
71 return(0);
72}
73
74uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2)
75{
76 std::vector<uint8_t> vopret; uint8_t *script,e,f;
77 GetOpReturnData(scriptPubKey, vopret);
78 script = (uint8_t *)vopret.data();
79 depositaddr[0] = 0;
80 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> prefix; ss >> prefix2; ss >> taddr; ss >> tokenid; ss >> totalsupply; ss >> M; ss >> N; ss >> pubkeys) != 0 )
81 {
82 if ( prefix == 60 )
83 {
84 if ( N > 1 )
85 Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
86 else Getscriptaddress(depositaddr,CScript() << Mypubkey(pubkeys[0]) << OP_CHECKSIG);
87 }
88 else
89 {
90 fprintf(stderr,"need to generate non-KMD addresses\n");
91 }
92 return(f);
93 }
94 return(0);
95}
96
c926780f 97int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
98{
99 char destaddr[64];
100 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
101 {
102 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
103 return(tx.vout[v].nValue);
104 }
105 return(0);
106}
107
108bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
109{
110 static uint256 zerohash;
111 CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
112 numvins = tx.vin.size();
113 numvouts = tx.vout.size();
114 for (i=0; i<numvins; i++)
115 {
116 //fprintf(stderr,"vini.%d\n",i);
117 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
118 {
119 //fprintf(stderr,"vini.%d check mempool\n",i);
120 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
121 return eval->Invalid("cant find vinTx");
122 else
123 {
124 //fprintf(stderr,"vini.%d check hash and vout\n",i);
125 if ( hashBlock == zerohash )
126 return eval->Invalid("cant Gateways from mempool");
127 if ( (assetoshis= IsGatewaysvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
128 inputs += assetoshis;
129 }
130 }
131 }
132 for (i=0; i<numvouts; i++)
133 {
134 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
135 if ( (assetoshis= IsGatewaysvout(cp,tx,i)) != 0 )
136 outputs += assetoshis;
137 }
138 if ( inputs != outputs+txfee )
139 {
140 fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
141 return eval->Invalid("mismatched inputs != outputs + txfee");
142 }
143 else return(true);
144}
145
146bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
147{
148 int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
149 return(false);
150 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
151 numvins = tx.vin.size();
152 numvouts = tx.vout.size();
153 preventCCvins = preventCCvouts = -1;
154 if ( numvouts < 1 )
155 return eval->Invalid("no vouts");
156 else
157 {
158 for (i=0; i<numvins; i++)
159 {
160 if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
161 {
162 return eval->Invalid("illegal normal vini");
163 }
164 }
165 //fprintf(stderr,"check amounts\n");
166 if ( GatewaysExactAmounts(cp,eval,tx,1,10000) == false )
167 {
168 fprintf(stderr,"Gatewaysget invalid amount\n");
169 return false;
170 }
171 else
172 {
173 txid = tx.GetHash();
174 memcpy(hash,&txid,sizeof(hash));
175 retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
176 if ( retval != 0 )
177 fprintf(stderr,"Gatewaysget validated\n");
178 else fprintf(stderr,"Gatewaysget invalid\n");
179 return(retval);
180 }
181 }
182}
183// end of consensus code
184
185// helper functions for rpc calls in rpcwallet.cpp
186
187int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
188{
189 char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
190 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
191 GetCCaddress(cp,coinaddr,pk);
192 SetCCunspents(unspentOutputs,coinaddr);
193 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
194 {
195 txid = it->first.txhash;
196 vout = (int32_t)it->first.index;
197 // no need to prevent dup
198 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
199 {
3515c101 200 if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
c926780f 201 {
202 if ( total != 0 && maxinputs != 0 )
203 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
204 nValue = it->second.satoshis;
205 totalinputs += nValue;
206 n++;
207 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
208 break;
209 }
210 }
211 }
212 return(totalinputs);
213}
214
3515c101 215UniValue GatewaysInfo(uint256 bindtxid)
216{
217 UniValue result(UniValue::VOBJ); std::string coin; char str[65],numstr[65],depositaddr[64]; uint8_t M,N; std::vector<CPubKey> pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid; CTransaction tx; CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int64_t totalsupply,remaining;
218 result.push_back(Pair("result","success"));
219 result.push_back(Pair("name","Gateways"));
220 cp = CCinit(&C,EVAL_GATEWAYS);
221 Gatewayspk = GetUnspendable(cp,0);
222 if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
223 {
224 if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 )
225 {
226 depositaddr[0] = 0;
227 if ( N > 1 )
228 {
229 result.push_back(Pair("M",M));
230 result.push_back(Pair("N",N));
231 }
232 result.push_back(Pair("coin",coin));
233 result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
234 result.push_back(Pair("taddr",taddr));
235 result.push_back(Pair("prefix",prefix));
236 result.push_back(Pair("prefix2",prefix2));
237 result.push_back(Pair("deposit",depositaddr));
238 result.push_back(Pair("tokenid",uint256_str(str,tokenid)));
239 sprintf(numstr,"%.8f",(double)totalsupply/COIN);
240 result.push_back(Pair("totalsupply",numstr));
241 remaining = CCaddress_balance(depositaddr);
242 sprintf(numstr,"%.8f",(double)remaining/COIN);
243 result.push_back(Pair("remaining",numstr));
244 sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN);
245 result.push_back(Pair("issued",numstr));
246 }
247 }
248 return(result);
249}
250
251UniValue GatewaysList()
252{
253 UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin,depositaddr; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector<CPubKey> pubkeys;
254 cp = CCinit(&C,EVAL_GATEWAYS);
255 SetCCtxids(addressIndex,cp->unspendableCCaddr);
256 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
257 {
258 txid = it->first.txhash;
259 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
260 {
261 if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 )
262 {
263 result.push_back(uint256_str(str,txid));
264 }
265 }
266 }
267 return(result);
268}
269
270std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys)
c926780f 271{
3515c101 272 CMutableTransaction mtx; CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char coinaddr[64],str[65],*fstr;
c926780f 273 cp = CCinit(&C,EVAL_GATEWAYS);
3515c101 274 if ( N == 0 || N > 15 || M > N )
275 {
276 fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
277 return("");
278 }
279 if ( strcmp((char *)"KMD",coin.c_str()) != 0 )
280 {
281 fprintf(stderr,"only KMD supported for now\n");
282 return("");
283 }
284 taddr = 0;
285 prefix = 60;
286 prefix2 = 85;
287 if ( pubkeys.size() != N )
288 {
289 fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
290 return("");
291 }
292 for (i=0; i<N; i++)
293 {
294 Getscriptaddress(coinaddr,CScript() << Mypubkey(pubkeys[i]) << OP_CHECKSIG);
295 if ( (balance= CCaddress_balance(coinaddr)) == 0 )
296 {
297 fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i);
298 return("");
299 }
300 }
c926780f 301 if ( txfee == 0 )
302 txfee = 10000;
c926780f 303 mypk = pubkey2pk(Mypubkey());
3515c101 304 gatewayspk = GetUnspendable(cp,0);
305 if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 )
306 {
307 fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin,tokenid);
308 return("");
309 }
310 if ( (fullsupply= CCfullsupply(tokenid)) != tokensupply )
311 {
312 fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s tokensupply %.8f != fullsupply %.8f\n",coin,tokenid,(double)tokensupply/COIN,(double)fullsupply/COIN);
313 return("");
314 }
315 if ( CCtoken_balance(destaddr,tokenid) != tokensupply )
316 {
317 fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s token balance %.8f != %.8f\n",coin,tokenid,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)tokensupply/COIN);
318 return("");
319 }
320 if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= orcaletx.vout.size()) <= 0 )
321 {
322 fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
323 return("");
324 }
325 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
326 {
327 fprintf(stderr,"mismatched oracle name %s != %s\n",name,coin);
328 return("");
329 }
330 if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 )
331 {
332 fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh");
333 return("");
334 }
335 if ( GatewaysBindExists(cp,gatewayspk,coin,tokenid) != 0 ) // dont forget to check mempool!
336 {
337 fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin,tokenid);
338 return("");
339 }
340 if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
341 {
342 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk));
343 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2)));
344 }
345 fprintf(stderr,"cant find enough inputs\n");
346 return("");
347}
348
349uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
350{
351 CTransaction tx; uint256 hash,mhash; int64_t val; int32_t numvouts,merkleht; CPubKey pk; std::vector<uint8_t>data;
352 txid = zeroid;
353 while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
354 {
355 if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,hash,pk,data) == 'D' && oracletxid == reforacletxid )
356 {
357 if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
c926780f 358 {
3515c101 359 if ( oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()) == sizeof(hash) &&
360 oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()) == sizeof(hash) && mhash != zeroid )
c926780f 361 {
3515c101 362 txid = batontxid;
363 return(mhash);
364 } else return(zeroid);
c926780f 365 }
3515c101 366 batontxid = hash;
367 } else break;
368 }
369 return(zeroid);
370}
371
372int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vector<uint256>proof,uint256 merkleroot,std::vector<uint8_t>redeemscript)
373{
374 uint256 txid = zeroid; CTransaction tx; std::string name,description,format; CScript scriptPubKey; char destaddr[64]; int64_t nValue = 0;
375 if ( GetTransaction(oracletxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
376 {
377 fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid));
378 return(0);
379 }
380 if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin )
381 {
382 fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name,refcoin);
383 return(0);
384 }
385 if ( DecodeHexTx(tx,deposithex) != 0 )
386 {
387 scriptPubKey = CScript() << redeemscript;
388 Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
389 if ( strcmp(refdepositaddr,destaddr) == 0 && scriptPubKey == tx.vout[1].scriptPubKey )
390 {
391 txid = tx.GetHash();
392 nValue = tx.vout[0].nValue;
393 }
394 else
395 {
396 Getscriptaddress(destaddr,tx.vout[1].scriptPubKey);
397 if ( strcmp(refdepositaddr,destaddr) == 0 && scriptPubKey == tx.vout[0].scriptPubKey )
398 {
399 txid = tx.GetHash();
400 nValue = tx.vout[1].nValue;
401 }
402 }
403 }
404 if ( txid == cointxid )
405 {
406 fprintf(stderr,"verify proof for cointxid in merkleroot\n");
407 return(nValue);
408 } else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch.%d\n",refdepositaddr,destaddr,txid != cointxid,scriptPubKey != tx.vout[1].scriptPubKey);
409 return(0);
410}
411
412int64_t GatewaysDepositval(CTransaction tx)
413{
414 int32_t numvouts,height; int64_t amount; std::string coin,deposithex; std::vector<struct oracle_merklepair> publishers; uint256 bindtxid,cointxid; std::vector<uint256> proof; std::vector<uint8_t> claimpubkey;
415 if ( (numvouts= tx.vout.size()) > 0 )
416 {
417 if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' )
418 {
419 // coin, bindtxid, publishers
420 fprintf(stderr,"need to validate deposittxid more\n");
421 return(amount);
c926780f 422 }
3515c101 423 }
424 return(0);
425}
426
427std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,std::vector<CPubKey>pubkeys,int32_t height,std::string refcoin,uint256 cointxid,std::string deposithex,std::vector<uint256>proof,std::vector<uint8_t> redeemscript,int64_t amount)
428{
429 CMutableTransaction mtx; CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid; int64_t totalsupply; int32_t i,m,n; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector<CPubKey> msigpubkeys; std::vector<struct oracle_merklepair> publishers; struct oracle_merklepair P; char str[65],depositaddr[64];
430 cp = CCinit(&C,EVAL_GATEWAYS);
431 if ( txfee == 0 )
432 txfee = 10000;
433 mypk = pubkey2pk(Mypubkey());
434 gatewayspk = GetUnspendable(cp,0);
435 if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 )
436 {
437 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
c926780f 438 return("");
3515c101 439 }
440 if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin )
441 {
442 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin);
443 return("");
444 }
445 n = (int32_t)pubkeys.size();
446 merkleroot = zeroid;
447 for (i=m=0; i<n; i++)
448 {
449 if ( (mhash= GatewaysReverseScan(txid,height,oracletxid,OraclesBatontxid(oracletxid,pubkeys[i].pk))) != zeroid )
450 {
451 if ( merkleroot == zeroid )
452 merkleroot = mhash, m = 1;
453 else if ( mhash == merkleroot )
454 m++;
455 P.pk = pubkeys[i].pk;
456 P.txid = txid;
457 publishers.push_back(P);
458 }
459 }
460 if ( merkleroot == zeroid || m < n/2 )
461 {
462 fprintf(stderr,"couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d\n",height,coin,uint256_str(str,oracletxid),m,n);
463 return("");
464 }
465 if ( GatewaysVerify(depositaddr,oracletxid,coin,cointxid,deposithex,proof,merkleroot,redeemscript) != amount )
466 {
467 fprintf(stderr,"deposittxid didnt validate\n");
468 return("");
469 }
470 if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
471 {
472 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk));
473 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,height,cointxid,deposithex,proof,redeemscript,amount)));
474 }
475 fprintf(stderr,"cant find enough inputs\n");
c926780f 476 return("");
477}
478
3515c101 479std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,std::vector<uint8_t> claimpubkey,int64_t amount)
c926780f 480{
3515c101 481 CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; int64_t totalsupply,inputs,CCchange=0; int32_t numvouts; uint256 assetid,oracletxid; char str[65],depositaddr[64];
c926780f 482 cp = CCinit(&C,EVAL_GATEWAYS);
3515c101 483 assetscp = CCinit(&C2,EVAL_ASSETS);
484 memcpy(cp->unspendablepriv2,assetscp->CCpriv,32);
c926780f 485 if ( txfee == 0 )
486 txfee = 10000;
487 mypk = pubkey2pk(Mypubkey());
3515c101 488 gatewayspk = GetUnspendable(cp,0);
489 if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
c926780f 490 {
3515c101 491 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
492 return("");
c926780f 493 }
3515c101 494 if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
495 {
496 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin);
497 return("");
498 }
499 if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
500 {
501 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
502 return("");
503 }
504 if ( (total= GatewaysDepositval(tx)) == 0 )
505 {
506 fprintf(stderr,"invalid Gateways deposittxid %s\n",uint256_str(str,deposittxid));
507 return("");
508 }
509 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
510 {
511 if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,total,60)) > 0 )
512 {
513 if ( inputs > total )
514 CCchange = (inputs - total);
515 mtx.vin.push_back(CTxIn(deposittxid,0,CScript()));
516 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,mypk));
517 if ( CCchange != 0 )
518 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk));
519 return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
520 }
521 }
522 fprintf(stderr,"cant find enough inputs or mismatched total\n");
c926780f 523 return("");
524}
525
3515c101 526std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
c926780f 527{
3515c101 528 CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint256 assetid; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; char depositaddr[64];
c926780f 529 cp = CCinit(&C,EVAL_GATEWAYS);
3515c101 530 assetscp = CCinit(&C2,EVAL_ASSETS);
531 if ( txfee == 0 )
532 txfee = 10000;
533 mypk = pubkey2pk(Mypubkey());
534 gatewayspk = GetUnspendable(cp,0);
535 if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
536 {
537 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
538 return("");
539 }
540 if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
541 {
542 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin);
543 return("");
544 }
545 if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
546 {
547 if ( (inputs= AddAssetInputs(assetscp,mtx,mypk,assetid,amount,60)) > 0 )
548 {
549 if ( inputs > amount )
550 CCchange = (inputs - amount);
551 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,gatewayspk));
552 if ( CCchange != 0 )
553 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
554 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG));
555 return(FinalizeCCTx(mask,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
556 }
557 }
558 fprintf(stderr,"cant find enough inputs or mismatched total\n");
559 return("");
c926780f 560}
561
3515c101 562// withdrawtxid used on external chain to create baton address, its existence in mempool (along with the withdraw) proof that the withdraw is pending
563
564
This page took 0.100034 seconds and 4 git commands to generate.