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