]> Git Repo - VerusCoin.git/blob - src/cc/gateways.cpp
Test
[VerusCoin.git] / src / cc / gateways.cpp
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 /*
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  
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
43  
44  In order to create a new gateway it is necessary to follow some strict steps.
45  1. create a token with the max possible supply that will be issued
46  2. transfer 100% of them to the gateways CC's global pubkey's asset CC address. (yes it is a bit confusing)
47  3. create an oracle with the identical name, ie. KMD and format must start with Ihh (height, blockhash, merkleroot)
48  4. register a publisher and fund it with a subscribe. there will be a special client app that will automatically publish the merkleroots.
49  5. Now a gatewaysbind can bind an external coin to an asset, along with the oracle for the merkleroots. the txid from the bind is used in most of the other gateways CC calls
50  
51  usage:
52   ./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC
53  a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a
54  
55  transfer to gateways pubkey: 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 RDMqGyREkP1Gwub1Nr5Ye8a325LGZsWBCb
56  ./c tokentransfer a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 100000000000000
57  2206fc39c0f384ca79819eb491ddbf889642cbfe4d0796bb6a8010ed53064a56
58  
59  ./c oraclescreate KMD blockheaders Ihh
60  1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808
61  
62  ./c oraclesregister 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 1000000
63  83b59eac238cbe54616ee13b2fdde85a48ec869295eb04051671a1727c9eb402
64  
65  ./c oraclessubscribe 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1000
66  f9499d8bb04ffb511fcec4838d72e642ec832558824a2ce5aed87f1f686f8102
67  
68  ./c gatewaysbind a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 KMD 100000000000000 1 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92
69  e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
70  
71  ./c gatewaysinfo e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
72  {
73  "result": "success",
74  "name": "Gateways",
75  "pubkey": "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92",
76  "coin": "KMD",
77  "oracletxid": "1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808",
78  "taddr": 0,
79  "prefix": 60,
80  "prefix2": 85,
81  "deposit": "",
82  "tokenid": "a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a",
83  "totalsupply": "1000000.00000000",
84  "remaining": "1000000.00000000",
85  "issued": "0.00000000"
86  }
87
88  To make a gateway deposit, send the funds to the "deposit" address, along with any amount to the same pubkey address you want to get the assetized KMD to appear in.
89  
90  ./komodo-cli z_sendmany "<funding addr>" '[{"address":"RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha","amount":0.0001},{"address":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","amount":7.6999}]'
91  bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 height.1003776
92  
93  ./komodo-cli gettxoutproof '["bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009"]'
94  04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b
95  
96  ./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009
97  010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b
98
99  gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof redeemscript amount numpks oraclepks
100 ./komodo-cli -ac_name=AT5 gatewaysdeposit e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e 1003776 KMD bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 0 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b proofhere 76a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac 7.6999 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92
101 */
102
103 // start of consensus code
104
105 CScript 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)
106 {
107     CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
108     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys << oracletxid);
109     return(opret);
110 }
111
112 CScript EncodeGatewaysOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256>txids,int32_t height,uint256 cointxid,std::string deposithex,std::vector<uint8_t>proof,std::vector<uint8_t> redeemscript,int64_t amount)
113 {
114     CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
115     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << deposithex << proof << redeemscript << amount);
116     return(opret);
117 }
118
119 uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector<CPubKey>&publishers,std::vector<uint256>&txids,int32_t &height,uint256 &cointxid,std::string &deposithex,std::vector<uint8_t> &proof,std::vector<uint8_t> &redeemscript,int64_t &amount)
120 {
121     std::vector<uint8_t> vopret; uint8_t *script,e,f;
122     GetOpReturnData(scriptPubKey, vopret);
123     script = (uint8_t *)vopret.data();
124     if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> deposithex; ss >> proof; ss >> redeemscript; ss >> amount) != 0 )
125     {
126         return(f);
127     }
128     return(0);
129 }
130
131 uint8_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)
132 {
133     std::vector<uint8_t> vopret; uint8_t *script,e,f;
134     GetOpReturnData(scriptPubKey, vopret);
135     script = (uint8_t *)vopret.data();
136     depositaddr[0] = 0;
137     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; ss >> oracletxid) != 0 )
138     {
139         if ( prefix == 60 )
140         {
141             if ( N > 1 )
142                 Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
143             else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
144         }
145         else
146         {
147             fprintf(stderr,"need to generate non-KMD addresses prefix.%d\n",prefix);
148         }
149         return(f);
150     } else fprintf(stderr,"error decoding bind opret\n");
151     return(0);
152 }
153
154 int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
155 {
156     char destaddr[64];
157     if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
158     {
159         if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
160             return(tx.vout[v].nValue);
161     }
162     return(0);
163 }
164
165 bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
166 {
167     static uint256 zerohash;
168     CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
169     numvins = tx.vin.size();
170     numvouts = tx.vout.size();
171     for (i=0; i<numvins; i++)
172     {
173         //fprintf(stderr,"vini.%d\n",i);
174         if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
175         {
176             //fprintf(stderr,"vini.%d check mempool\n",i);
177             if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
178                 return eval->Invalid("cant find vinTx");
179             else
180             {
181                 //fprintf(stderr,"vini.%d check hash and vout\n",i);
182                 if ( hashBlock == zerohash )
183                     return eval->Invalid("cant Gateways from mempool");
184                 if ( (assetoshis= IsGatewaysvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
185                     inputs += assetoshis;
186             }
187         }
188     }
189     for (i=0; i<numvouts; i++)
190     {
191         //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
192         if ( (assetoshis= IsGatewaysvout(cp,tx,i)) != 0 )
193             outputs += assetoshis;
194     }
195     if ( inputs != outputs+txfee )
196     {
197         fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
198         return eval->Invalid("mismatched inputs != outputs + txfee");
199     }
200     else return(true);
201 }
202
203 bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
204 {
205     int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
206     return(false);
207     std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
208     numvins = tx.vin.size();
209     numvouts = tx.vout.size();
210     preventCCvins = preventCCvouts = -1;
211     if ( numvouts < 1 )
212         return eval->Invalid("no vouts");
213     else
214     {
215         for (i=0; i<numvins; i++)
216         {
217             if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
218             {
219                 return eval->Invalid("illegal normal vini");
220             }
221         }
222         //fprintf(stderr,"check amounts\n");
223         if ( GatewaysExactAmounts(cp,eval,tx,1,10000) == false )
224         {
225             fprintf(stderr,"Gatewaysget invalid amount\n");
226             return false;
227         }
228         else
229         {
230             txid = tx.GetHash();
231             memcpy(hash,&txid,sizeof(hash));
232             retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
233             if ( retval != 0 )
234                 fprintf(stderr,"Gatewaysget validated\n");
235             else fprintf(stderr,"Gatewaysget invalid\n");
236             return(retval);
237         }
238     }
239 }
240 // end of consensus code
241
242 // helper functions for rpc calls in rpcwallet.cpp
243
244 int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
245 {
246     char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
247     std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
248     GetCCaddress(cp,coinaddr,pk);
249     SetCCunspents(unspentOutputs,coinaddr);
250     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
251     {
252         txid = it->first.txhash;
253         vout = (int32_t)it->first.index;
254         // no need to prevent dup
255         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
256         {
257             if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
258             {
259                 if ( total != 0 && maxinputs != 0 )
260                     mtx.vin.push_back(CTxIn(txid,vout,CScript()));
261                 nValue = it->second.satoshis;
262                 totalinputs += nValue;
263                 n++;
264                 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
265                     break;
266             }
267         }
268     }
269     return(totalinputs);
270 }
271
272 UniValue GatewaysInfo(uint256 bindtxid)
273 {
274     UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector<CPubKey> pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining;
275     result.push_back(Pair("result","success"));
276     result.push_back(Pair("name","Gateways"));
277     cp = CCinit(&C,EVAL_GATEWAYS);
278     Gatewayspk = GetUnspendable(cp,0);
279     _GetCCaddress(gatewaysassets,EVAL_ASSETS,Gatewayspk);
280     if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
281     {
282         depositaddr[0] = 0;
283         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 )
284         {
285             if ( N > 1 )
286             {
287                 result.push_back(Pair("M",M));
288                 result.push_back(Pair("N",N));
289                 for (i=0; i<N; i++)
290                     a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i]));
291                 result.push_back(Pair("pubkeys",a));
292             } else result.push_back(Pair("pubkey",pubkey33_str(str,(uint8_t *)&pubkeys[0])));
293             result.push_back(Pair("coin",coin));
294             result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
295             result.push_back(Pair("taddr",taddr));
296             result.push_back(Pair("prefix",prefix));
297             result.push_back(Pair("prefix2",prefix2));
298             result.push_back(Pair("deposit",depositaddr));
299             result.push_back(Pair("tokenid",uint256_str(str,tokenid)));
300             sprintf(numstr,"%.8f",(double)totalsupply/COIN);
301             result.push_back(Pair("totalsupply",numstr));
302             remaining = CCaddress_balance(gatewaysassets);
303             sprintf(numstr,"%.8f",(double)remaining/COIN);
304             result.push_back(Pair("remaining",numstr));
305             sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN);
306             result.push_back(Pair("issued",numstr));
307         }
308     }
309     return(result);
310 }
311
312 UniValue GatewaysList()
313 {
314     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; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector<CPubKey> pubkeys;
315     cp = CCinit(&C,EVAL_GATEWAYS);
316     SetCCtxids(addressIndex,cp->unspendableCCaddr);
317     for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
318     {
319         txid = it->first.txhash;
320         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
321         {
322             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 )
323             {
324                 result.push_back(uint256_str(str,txid));
325             }
326         }
327     }
328     return(result);
329 }
330
331 std::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)
332 {
333     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 destaddr[64],coinaddr[64],str[65],*fstr;
334     cp = CCinit(&C,EVAL_GATEWAYS);
335     if ( N == 0 || N > 15 || M > N )
336     {
337         fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
338         return("");
339     }
340     if ( strcmp((char *)"KMD",coin.c_str()) != 0 )
341     {
342         fprintf(stderr,"only KMD supported for now\n");
343         return("");
344     }
345     taddr = 0;
346     prefix = 60;
347     prefix2 = 85;
348     if ( pubkeys.size() != N )
349     {
350         fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
351         return("");
352     }
353     for (i=0; i<N; i++)
354     {
355         Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
356         if ( CCaddress_balance(coinaddr) == 0 )
357         {
358             fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i);
359             return("");
360         }
361     }
362     if ( txfee == 0 )
363         txfee = 10000;
364     mypk = pubkey2pk(Mypubkey());
365     gatewayspk = GetUnspendable(cp,0);
366     if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 )
367     {
368         fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid));
369         return("");
370     }
371     if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply )
372     {
373         fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s totalsupply %.8f != fullsupply %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN);
374         return("");
375     }
376     if ( CCtoken_balance(destaddr,tokenid) != totalsupply )
377     {
378         fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN);
379         return("");
380     }
381     if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
382     {
383         fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
384         return("");
385     }
386     if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
387     {
388         fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str());
389         return("");
390     }
391     if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 )
392     {
393         fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh");
394         return("");
395     }
396     fprintf(stderr,"implement GatewaysBindExists\n");
397     /*if ( GatewaysBindExists(cp,gatewayspk,coin,tokenid) != 0 ) // dont forget to check mempool!
398     {
399         fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid));
400         return("");
401     }*/
402     if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
403     {
404         mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk));
405         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2)));
406     }
407     fprintf(stderr,"cant find enough inputs\n");
408     return("");
409 }
410
411 uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
412 {
413     CTransaction tx; uint256 hash,mhash,hashBlock,oracletxid; int64_t val; int32_t numvouts; int64_t merkleht; CPubKey pk; std::vector<uint8_t>data;
414     txid = zeroid;
415     while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
416     {
417         if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,hash,pk,data) == 'D' && oracletxid == reforacletxid )
418         {
419             if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
420             {
421                 if ( oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()) == sizeof(hash) &&
422                 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 )
423                 {
424                     txid = batontxid;
425                     return(mhash);
426                 } else return(zeroid);
427             }
428             batontxid = hash;
429         } else break;
430     }
431     return(zeroid);
432 }
433
434 int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vector<uint8_t>proof,uint256 merkleroot,std::vector<uint8_t>redeemscript)
435 {
436     uint256 hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],str[65]; int32_t i,numvouts; int64_t nValue = 0;
437     if ( GetTransaction(oracletxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
438     {
439         fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid));
440         return(0);
441     }
442     if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin )
443     {
444         fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str());
445         return(0);
446     }
447     if ( DecodeHexTx(tx,deposithex) != 0 )
448     {
449         for (i=0; i<numvouts; i++)
450         {
451             Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
452             if ( strcmp(refdepositaddr,destaddr) == 0 )
453             {
454                 if ( redeemscript.size() == tx.vout[claimvout].scriptPubKey.size() && memcmp(&redeemscript.data(),tx.vout[claimvout].scriptPubKey.data(),redeemscript.size()) == 0 )
455                 {
456                     txid = tx.GetHash();
457                     nValue = tx.vout[i].nValue;
458                     break;
459                 }
460                 else
461                 {
462                     int j;
463                     for (j=0; j<redeemscript.size(); j++)
464                         fprintf(stderr,"%02x",((uint8_t *)redeemscript.data())[j]);
465                     fprintf(stderr," redeemscript.%d\n",(int32_t)redeemscript.size());
466                     for (j=0; j<tx.vout[claimvout].scriptPubKey.size(); j++)
467                         fprintf(stderr,"%02x",((uint8_t *)tx.vout[claimvout].scriptPubKey.data())[j]);
468                     fprintf(stderr," claimvout.%d scriptPubKey.%d mismatch\n",claimvout,(int32_t)tx.vout[claimvout].scriptPubKey.size());
469                 }
470             } else fprintf(stderr,"i.%d %s vs %s\n",i,destaddr,refdepositaddr);
471         }
472     }
473     if ( txid == cointxid )
474     {
475         fprintf(stderr,"verify proof for cointxid in merkleroot\n");
476         return(nValue);
477     } else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch\n",refdepositaddr,destaddr,txid != cointxid);
478     return(0);
479 }
480
481 int64_t GatewaysDepositval(CTransaction tx)
482 {
483     int32_t numvouts,height; int64_t amount; std::string coin,deposithex; std::vector<CPubKey> publishers; std::vector<uint256>txids; uint256 bindtxid,cointxid; std::vector<uint8_t> proof; std::vector<uint8_t> claimpubkey;
484     if ( (numvouts= tx.vout.size()) > 0 )
485     {
486         if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' )
487         {
488             // coin, bindtxid, publishers
489             fprintf(stderr,"need to validate deposittxid more\n");
490             return(amount);
491         }
492     }
493     return(0);
494 }
495
496 std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,std::vector<CPubKey>pubkeys,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,std::vector<uint8_t> redeemscript,int64_t amount)
497 {
498     CMutableTransaction mtx; CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector<CPubKey> msigpubkeys,publishers; std::vector<uint256>txids; char str[65],depositaddr[64];
499     cp = CCinit(&C,EVAL_GATEWAYS);
500     if ( txfee == 0 )
501         txfee = 10000;
502     mypk = pubkey2pk(Mypubkey());
503     gatewayspk = GetUnspendable(cp,0);
504     fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size());
505     if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 )
506     {
507         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
508         return("");
509     }
510     if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin )
511     {
512         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
513         return("");
514     }
515     n = (int32_t)pubkeys.size();
516     merkleroot = zeroid;
517     for (i=m=0; i<n; i++)
518     {
519         if ( (mhash= GatewaysReverseScan(txid,height,oracletxid,OraclesBatontxid(oracletxid,pubkeys[i]))) != zeroid )
520         {
521             if ( merkleroot == zeroid )
522                 merkleroot = mhash, m = 1;
523             else if ( mhash == merkleroot )
524                 m++;
525             publishers.push_back(pubkeys[i]);
526             txids.push_back(txid);
527         }
528     }
529     if ( 0 && (merkleroot == zeroid || m < n/2) )
530     {
531         fprintf(stderr,"couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d\n",height,coin.c_str(),uint256_str(str,oracletxid),m,n);
532         return("");
533     }
534     if ( GatewaysVerify(depositaddr,oracletxid,claimvout,coin,cointxid,deposithex,proof,merkleroot,redeemscript) != amount )
535     {
536         fprintf(stderr,"deposittxid didnt validate\n");
537         return("");
538     }
539     if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
540     {
541         mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk));
542         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,redeemscript,amount)));
543     }
544     fprintf(stderr,"cant find enough inputs\n");
545     return("");
546 }
547
548 std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,std::vector<uint8_t> claimpubkey,int64_t amount)
549 {
550     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,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64];
551     cp = CCinit(&C,EVAL_GATEWAYS);
552     assetscp = CCinit(&C2,EVAL_ASSETS);
553     memcpy(cp->unspendablepriv2,assetscp->CCpriv,32);
554     if ( txfee == 0 )
555         txfee = 10000;
556     mypk = pubkey2pk(Mypubkey());
557     gatewayspk = GetUnspendable(cp,0);
558     if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
559     {
560         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
561         return("");
562     }
563     if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
564     {
565         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
566         return("");
567     }
568     if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
569     {
570         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
571         return("");
572     }
573     if ( (depositamount= GatewaysDepositval(tx)) != amount )
574     {
575         fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN);
576         return("");
577     }
578     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
579     {
580         if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,amount,60)) > 0 )
581         {
582             if ( inputs > amount )
583                 CCchange = (inputs - amount);
584             mtx.vin.push_back(CTxIn(deposittxid,0,CScript()));
585             mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk));
586             if ( CCchange != 0 )
587                 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk));
588             return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
589         }
590     }
591     fprintf(stderr,"cant find enough inputs or mismatched total\n");
592     return("");
593 }
594
595 std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
596 {
597     CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65];
598     cp = CCinit(&C,EVAL_GATEWAYS);
599     assetscp = CCinit(&C2,EVAL_ASSETS);
600     if ( txfee == 0 )
601         txfee = 10000;
602     mypk = pubkey2pk(Mypubkey());
603     gatewayspk = GetUnspendable(cp,0);
604     if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
605     {
606         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
607         return("");
608     }
609     if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
610     {
611         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
612         return("");
613     }
614     if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
615     {
616         if ( (inputs= AddAssetInputs(assetscp,mtx,mypk,assetid,amount,60)) > 0 )
617         {
618             if ( inputs > amount )
619                 CCchange = (inputs - amount);
620             mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,gatewayspk));
621             if ( CCchange != 0 )
622                 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
623             mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG));
624             return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
625         }
626     }
627     fprintf(stderr,"cant find enough inputs or mismatched total\n");
628     return("");
629 }
630
631 // withdrawtxid used on external chain to create baton address, its existence in mempool (along with the withdraw) proof that the withdraw is pending
632
633
This page took 0.06069 seconds and 4 git commands to generate.