]> Git Repo - VerusCoin.git/blob - src/cc/gateways.cpp
6450b3c90606ddf4bb75f237f4b6f299128d8877
[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  prevent duplicate bindtxid via mempool scan
20  wait for notarization for oraclefeed and validation of gatewaysdeposit
21  gatewayswithdraw
22  
23  validation
24  
25 string oracles
26  */
27
28 /*
29  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.
30  
31  the potential pubkeys to be used would be based on active oracle data providers with recent activity.
32  
33  bind asset <-> KMD gateway deposit address
34  KMD deposit -> globally spendable marker utxo
35  spend marker utxo and spend linked/locked asset to user's CC address
36  
37  redeem -> asset to global CC address with withdraw address -> gateway spendable marker utxo
38  spend market utxo and withdraw from gateway deposit address
39  
40  rpc calls:
41  GatewayList
42  GatewayInfo bindtxid
43  GatewayBind coin tokenid M N pubkey(s)
44  external: deposit to depositaddr with claimpubkey
45  GatewayDeposit coin tokenid external.deposittxid -> markertxid
46  GatewayClaim coin tokenid external.deposittxid markertxid -> spend marker and deposit asset
47  
48  GatewayWithdraw coin tokenid withdrawaddr
49  external: do withdraw to withdrawaddr and spend marker, support for partial signatures and autocomplete
50  
51  deposit addr can be 1 to MofN pubkeys
52  1:1 gateway with native coin
53  
54  In order to create a new gateway it is necessary to follow some strict steps.
55  1. create a token with the max possible supply that will be issued
56  2. transfer 100% of them to the gateways CC's global pubkey's asset CC address. (yes it is a bit confusing)
57  3. create an oracle with the identical name, ie. KMD and format must start with Ihh (height, blockhash, merkleroot)
58  4. register a publisher and fund it with a subscribe. there will be a special client app that will automatically publish the merkleroots.
59  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
60  
61  usage:
62   ./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC
63  a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a
64  
65  transfer to gateways pubkey: 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 RDMqGyREkP1Gwub1Nr5Ye8a325LGZsWBCb
66  ./c tokentransfer a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 100000000000000
67  2206fc39c0f384ca79819eb491ddbf889642cbfe4d0796bb6a8010ed53064a56
68  
69  ./c oraclescreate KMD blockheaders Ihh
70  1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808
71  
72  ./c oraclesregister 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 1000000
73  83b59eac238cbe54616ee13b2fdde85a48ec869295eb04051671a1727c9eb402
74  
75  ./c oraclessubscribe 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1000
76  f9499d8bb04ffb511fcec4838d72e642ec832558824a2ce5aed87f1f686f8102
77  
78  ./c gatewaysbind a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 KMD 100000000000000 1 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92
79  e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
80  
81  ./c gatewaysinfo e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
82  {
83  "result": "success",
84  "name": "Gateways",
85  "pubkey": "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92",
86  "coin": "KMD",
87  "oracletxid": "1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808",
88  "taddr": 0,
89  "prefix": 60,
90  "prefix2": 85,
91  "deposit": "",
92  "tokenid": "a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a",
93  "totalsupply": "1000000.00000000",
94  "remaining": "1000000.00000000",
95  "issued": "0.00000000"
96  }
97
98  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.
99  
100  0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 pubkey for RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha
101  ./komodo-cli z_sendmany "<funding addr>" '[{"address":"RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha","amount":0.0001},{"address":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","amount":7.6999}]'
102  bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 height.1003776 merkle.90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f
103  
104  ./komodo-cli gettxoutproof '["bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009"]'
105  04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b
106  
107  ./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009
108  010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b
109
110  gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount
111 ./komodo-cli -ac_name=AT5 gatewaysdeposit e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e 1003776 KMD bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 0 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999 
112  -> 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6
113  
114  to get the merkleroots onchain, from the multisig signers nodes run the oraclefeed program with acname oracletxid pubkey Ihh
115  ./oraclefeed AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh
116  
117  gatewaysclaim bindtxid coin deposittxid destpub amount
118 ./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
119  
120  now the asset is in the pubkey's asset address!
121  it can be used, traded freely and any node who has the asset can do a gatewayswithdraw
122  
123  gatewayswithdraw bindtxid coin withdrawpub amount
124  ./c gatewayswithdraw e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828 1
125  ef3cc452da006eb2edda6b6ed3d3347664be51260f3e91f59ec44ec9701367f0
126  
127  Now there is a withdraw pending, so it needs to be processed by the signing nodes on the KMD side
128  
129  gatewayspending bindtxid coin 
130  gatewayspending will display all pending withdraws and if it is done on one of the msigpubkeys, then it will queue it for processing
131  ./c gatewayspending e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD
132  
133
134 */
135
136
137 int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue)
138 {
139     char destaddr[64],str[65];
140     Getscriptaddress(destaddr,scriptPubKey);
141     fprintf(stderr,"GatewaysAddQueue: %s %s %s %.8f\n",coin.c_str(),uint256_str(str,txid),destaddr,(double)nValue/COIN);
142 }
143
144 // start of consensus code
145
146 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)
147 {
148     CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
149     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys << oracletxid);
150     return(opret);
151 }
152
153 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,CPubKey destpub,int64_t amount)
154 {
155     CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
156     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << deposithex << proof << destpub << amount);
157     return(opret);
158 }
159
160 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,CPubKey &destpub,int64_t &amount)
161 {
162     std::vector<uint8_t> vopret; uint8_t *script,e,f;
163     GetOpReturnData(scriptPubKey, vopret);
164     script = (uint8_t *)vopret.data();
165     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 >> destpub; ss >> amount) != 0 )
166     {
167         return(f);
168     }
169     return(0);
170 }
171
172 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)
173 {
174     std::vector<uint8_t> vopret; uint8_t *script,e,f;
175     GetOpReturnData(scriptPubKey, vopret);
176     script = (uint8_t *)vopret.data();
177     depositaddr[0] = 0;
178     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 )
179     {
180         if ( prefix == 60 )
181         {
182             if ( N > 1 )
183                 Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
184             else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
185         }
186         else
187         {
188             fprintf(stderr,"need to generate non-KMD addresses prefix.%d\n",prefix);
189         }
190         return(f);
191     } else fprintf(stderr,"error decoding bind opret\n");
192     return(0);
193 }
194
195 int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
196 {
197     char destaddr[64];
198     if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
199     {
200         if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
201             return(tx.vout[v].nValue);
202     }
203     return(0);
204 }
205
206 bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
207 {
208     static uint256 zerohash;
209     CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
210     numvins = tx.vin.size();
211     numvouts = tx.vout.size();
212     for (i=0; i<numvins; i++)
213     {
214         //fprintf(stderr,"vini.%d\n",i);
215         if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
216         {
217             //fprintf(stderr,"vini.%d check mempool\n",i);
218             if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
219                 return eval->Invalid("cant find vinTx");
220             else
221             {
222                 //fprintf(stderr,"vini.%d check hash and vout\n",i);
223                 if ( hashBlock == zerohash )
224                     return eval->Invalid("cant Gateways from mempool");
225                 if ( (assetoshis= IsGatewaysvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
226                     inputs += assetoshis;
227             }
228         }
229     }
230     for (i=0; i<numvouts; i++)
231     {
232         //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
233         if ( (assetoshis= IsGatewaysvout(cp,tx,i)) != 0 )
234             outputs += assetoshis;
235     }
236     if ( inputs != outputs+txfee )
237     {
238         fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
239         return eval->Invalid("mismatched inputs != outputs + txfee");
240     }
241     else return(true);
242 }
243
244 bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
245 {
246     int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
247     std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
248     fprintf(stderr,"return true without gateways validation\n");
249     return(true);
250     numvins = tx.vin.size();
251     numvouts = tx.vout.size();
252     preventCCvins = preventCCvouts = -1;
253     if ( numvouts < 1 )
254         return eval->Invalid("no vouts");
255     else
256     {
257         for (i=0; i<numvins; i++)
258         {
259             if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
260             {
261                 return eval->Invalid("illegal normal vini");
262             }
263         }
264         //fprintf(stderr,"check amounts\n");
265         if ( GatewaysExactAmounts(cp,eval,tx,1,10000) == false )
266         {
267             fprintf(stderr,"Gatewaysget invalid amount\n");
268             return false;
269         }
270         else
271         {
272             txid = tx.GetHash();
273             memcpy(hash,&txid,sizeof(hash));
274             retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
275             if ( retval != 0 )
276                 fprintf(stderr,"Gatewaysget validated\n");
277             else fprintf(stderr,"Gatewaysget invalid\n");
278             return(retval);
279         }
280     }
281 }
282 // end of consensus code
283
284 // helper functions for rpc calls in rpcwallet.cpp
285
286 int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
287 {
288     char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
289     std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
290     GetCCaddress(cp,coinaddr,pk);
291     SetCCunspents(unspentOutputs,coinaddr);
292     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
293     {
294         txid = it->first.txhash;
295         vout = (int32_t)it->first.index;
296         // no need to prevent dup
297         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
298         {
299             if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
300             {
301                 if ( total != 0 && maxinputs != 0 )
302                     mtx.vin.push_back(CTxIn(txid,vout,CScript()));
303                 nValue = it->second.satoshis;
304                 totalinputs += nValue;
305                 n++;
306                 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
307                     break;
308             }
309         }
310     }
311     return(totalinputs);
312 }
313
314 int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool!
315 {
316     char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; uint8_t M,N,taddr,prefix,prefix2; std::vector<CPubKey> pubkeys; CTransaction tx;
317     std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
318     _GetCCaddress(markeraddr,EVAL_GATEWAYS,gatewayspk);
319     fprintf(stderr,"bind markeraddr.(%s) need to scan mempool also\n",markeraddr);
320     SetCCtxids(addressIndex,markeraddr);
321     for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
322     {
323         if ( GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
324         {
325             if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' )
326             {
327                 if ( tokenid == reftokenid )
328                 {
329                     fprintf(stderr,"trying to bind an existing tokenid\n");
330                     return(1);
331                 }
332             }
333         }
334     }
335     return(0);
336 }
337
338 static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr)
339 {
340     int32_t i,n; char destaddr[64];
341     BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
342     {
343         const CTransaction &tx = e.GetTx();
344         if ( (n= tx.vout.size()) > 0 )
345         {
346             const uint256 &txid = tx.GetHash();
347             for (i=0; i<n; i++)
348             {
349                 Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
350                 if ( strcmp(destaddr,coinaddr) == 0 )
351                 {
352                     fprintf(stderr,"found (%s) vout in mempool\n",coinaddr);
353                     return(1);
354                 }
355             }
356         }
357     }
358     return(0);
359 }
360
361 int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) // dont forget to check mempool!
362 {
363     char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock;
364     std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
365     CCtxidaddr(txidaddr,cointxid);
366     SetCCtxids(addressIndex,txidaddr);
367     for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
368     {
369         return(-1);
370     }
371     return(myIs_coinaddr_inmempoolvout(txidaddr));
372 }
373
374 UniValue GatewaysInfo(uint256 bindtxid)
375 {
376     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;
377     result.push_back(Pair("result","success"));
378     result.push_back(Pair("name","Gateways"));
379     cp = CCinit(&C,EVAL_GATEWAYS);
380     Gatewayspk = GetUnspendable(cp,0);
381     _GetCCaddress(gatewaysassets,EVAL_ASSETS,Gatewayspk);
382     if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
383     {
384         depositaddr[0] = 0;
385         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 )
386         {
387             if ( N > 1 )
388             {
389                 result.push_back(Pair("M",M));
390                 result.push_back(Pair("N",N));
391                 for (i=0; i<N; i++)
392                     a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i]));
393                 result.push_back(Pair("pubkeys",a));
394             } else result.push_back(Pair("pubkey",pubkey33_str(str,(uint8_t *)&pubkeys[0])));
395             result.push_back(Pair("coin",coin));
396             result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
397             result.push_back(Pair("taddr",taddr));
398             result.push_back(Pair("prefix",prefix));
399             result.push_back(Pair("prefix2",prefix2));
400             result.push_back(Pair("deposit",depositaddr));
401             result.push_back(Pair("tokenid",uint256_str(str,tokenid)));
402             sprintf(numstr,"%.8f",(double)totalsupply/COIN);
403             result.push_back(Pair("totalsupply",numstr));
404             remaining = CCaddress_balance(gatewaysassets);
405             sprintf(numstr,"%.8f",(double)remaining/COIN);
406             result.push_back(Pair("remaining",numstr));
407             sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN);
408             result.push_back(Pair("issued",numstr));
409         }
410     }
411     return(result);
412 }
413
414 UniValue GatewaysList()
415 {
416     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;
417     cp = CCinit(&C,EVAL_GATEWAYS);
418     SetCCtxids(addressIndex,cp->unspendableCCaddr);
419     for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
420     {
421         txid = it->first.txhash;
422         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
423         {
424             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 )
425             {
426                 result.push_back(uint256_str(str,txid));
427             }
428         }
429     }
430     return(result);
431 }
432
433 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)
434 {
435     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;
436     cp = CCinit(&C,EVAL_GATEWAYS);
437     if ( N == 0 || N > 15 || M > N )
438     {
439         fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
440         return("");
441     }
442     if ( strcmp((char *)"KMD",coin.c_str()) != 0 )
443     {
444         fprintf(stderr,"only KMD supported for now\n");
445         return("");
446     }
447     taddr = 0;
448     prefix = 60;
449     prefix2 = 85;
450     if ( pubkeys.size() != N )
451     {
452         fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
453         return("");
454     }
455     for (i=0; i<N; i++)
456     {
457         Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
458         if ( CCaddress_balance(coinaddr) == 0 )
459         {
460             fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i);
461             return("");
462         }
463     }
464     if ( txfee == 0 )
465         txfee = 10000;
466     mypk = pubkey2pk(Mypubkey());
467     gatewayspk = GetUnspendable(cp,0);
468     if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 )
469     {
470         fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid));
471         return("");
472     }
473     if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply )
474     {
475         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);
476         return("");
477     }
478     if ( CCtoken_balance(destaddr,tokenid) != totalsupply )
479     {
480         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);
481         return("");
482     }
483     if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
484     {
485         fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
486         return("");
487     }
488     if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
489     {
490         fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str());
491         return("");
492     }
493     if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 )
494     {
495         fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh");
496         return("");
497     }
498     if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) // dont forget to check mempool!
499     {
500         fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid));
501         return("");
502     }
503     if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
504     {
505         mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk));
506         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2)));
507     }
508     fprintf(stderr,"cant find enough inputs\n");
509     return("");
510 }
511
512 uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
513 {
514     CTransaction tx; uint256 hash,mhash,hashBlock,oracletxid; int64_t val; int32_t numvouts; int64_t merkleht; CPubKey pk; std::vector<uint8_t>data;
515     txid = zeroid;
516     char str[65]; fprintf(stderr,"reverse scan %s\n",uint256_str(str,batontxid));
517     while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
518     {
519         fprintf(stderr,"reverse scan %s\n",uint256_str(str,batontxid));
520         if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,hash,pk,data) == 'D' && oracletxid == reforacletxid )
521         {
522             if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
523             {
524                 if ( oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()) == sizeof(hash) &&
525                 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 )
526                 {
527                     txid = batontxid;
528                     return(mhash);
529                 } else return(zeroid);
530             }
531             batontxid = hash;
532         } else break;
533     }
534     return(zeroid);
535 }
536
537 /* Get the block merkle root for a proof
538  * IN: proofData
539  * OUT: merkle root
540  * OUT: transaction IDS
541  */
542 uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids)
543 {
544     CMerkleBlock merkleBlock;
545     if (!E_UNMARSHAL(proofData, ss >> merkleBlock))
546         return uint256();
547     return merkleBlock.txn.ExtractMatches(txids);
548 }
549
550 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,CPubKey destpub)
551 {
552     std::vector<uint256> txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0;
553     if ( GetTransaction(oracletxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
554     {
555         fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid));
556         return(0);
557     }
558     if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin )
559     {
560         fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str());
561         return(0);
562     }
563     proofroot = BitcoinGetProofMerkleRoot(proof,txids);
564     if ( proofroot != merkleroot )
565     {
566         fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot));
567         return(0);
568     }
569     if ( DecodeHexTx(tx,deposithex) != 0 )
570     {
571         Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey);
572         Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
573         if ( strcmp(claimaddr,destpubaddr) == 0 )
574         {
575             for (i=0; i<numvouts; i++)
576             {
577                 Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
578                 if ( strcmp(refdepositaddr,destaddr) == 0 )
579                 {
580                     txid = tx.GetHash();
581                     nValue = tx.vout[i].nValue;
582                     break;
583                 }
584             }
585         } else fprintf(stderr,"claimaddr.(%s) != destpubaddr.(%s)\n",claimaddr,destpubaddr);
586     }
587     if ( txid == cointxid )
588     {
589         fprintf(stderr,"verify proof for cointxid in merkleroot\n");
590         return(nValue);
591     } else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch\n",refdepositaddr,destaddr,txid != cointxid);
592     return(0);
593 }
594
595 int64_t GatewaysDepositval(CTransaction tx)
596 {
597     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; CPubKey claimpubkey;
598     if ( (numvouts= tx.vout.size()) > 0 )
599     {
600         if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' )
601         {
602             // coin, bindtxid, publishers
603             fprintf(stderr,"need to validate deposittxid more\n");
604             return(amount);
605         }
606     }
607     return(0);
608 }
609
610 std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount)
611 {
612     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> pubkeys,publishers; std::vector<uint256>txids; char str[67],depositaddr[64],txidaddr[64];
613     cp = CCinit(&C,EVAL_GATEWAYS);
614     if ( txfee == 0 )
615         txfee = 10000;
616     mypk = pubkey2pk(Mypubkey());
617     gatewayspk = GetUnspendable(cp,0);
618     //fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size());
619     if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 )
620     {
621         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
622         return("");
623     }
624     if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin )
625     {
626         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
627         return("");
628     }
629     n = (int32_t)pubkeys.size();
630     merkleroot = zeroid;
631     for (i=m=0; i<n; i++)
632     {
633         fprintf(stderr,"pubkeys[%d] %s\n",i,pubkey33_str(str,(uint8_t *)&pubkeys[i]));
634         if ( (mhash= GatewaysReverseScan(txid,height,oracletxid,OraclesBatontxid(oracletxid,pubkeys[i]))) != zeroid )
635         {
636             if ( merkleroot == zeroid )
637                 merkleroot = mhash, m = 1;
638             else if ( mhash == merkleroot )
639                 m++;
640             publishers.push_back(pubkeys[i]);
641             txids.push_back(txid);
642         }
643     }
644     fprintf(stderr,"m.%d of n.%d\n",m,n);
645     if ( merkleroot == zeroid || m < n/2 )
646     {
647         //uint256 tmp;
648         //decode_hex((uint8_t *)&tmp,32,(char *)"90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f");
649         //merkleroot = revuint256(tmp);
650         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);
651         return("");
652     }
653     if ( GatewaysCointxidExists(cp,cointxid) != 0 )
654     {
655         fprintf(stderr,"cointxid.%s already exists\n",uint256_str(str,cointxid));
656         return("");
657     }
658     if ( GatewaysVerify(depositaddr,oracletxid,claimvout,coin,cointxid,deposithex,proof,merkleroot,destpub) != amount )
659     {
660         fprintf(stderr,"deposittxid didnt validate\n");
661         return("");
662     }
663     if ( AddNormalinputs(mtx,mypk,3*txfee,60) > 0 )
664     {
665         mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk));
666         mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG));
667         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,destpub,amount)));
668     }
669     fprintf(stderr,"cant find enough inputs\n");
670     return("");
671 }
672
673 std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount)
674 {
675     CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint8_t M,N,taddr,prefix,prefix2,mypriv[32]; 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],coinaddr[64];
676     cp = CCinit(&C,EVAL_GATEWAYS);
677     assetscp = CCinit(&C2,EVAL_ASSETS);
678     if ( txfee == 0 )
679         txfee = 10000;
680     mypk = pubkey2pk(Mypubkey());
681     gatewayspk = GetUnspendable(cp,0);
682     _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
683     CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr);
684     Myprivkey(mypriv);
685     _GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk);
686     CCaddr3set(assetscp,EVAL_GATEWAYS,mypk,mypriv,coinaddr);
687     if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
688     {
689         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
690         return("");
691     }
692     if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
693     {
694         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
695         return("");
696     }
697     if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
698     {
699         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
700         return("");
701     }
702     if ( (depositamount= GatewaysDepositval(tx)) != amount )
703     {
704         fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN);
705         return("");
706     }
707     //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2);
708     if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
709     {
710         if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,amount,60)) > 0 )
711         {
712             if ( inputs > amount )
713                 CCchange = (inputs - amount);
714             mtx.vin.push_back(CTxIn(deposittxid,0,CScript()));
715             mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk));
716             if ( CCchange != 0 )
717                 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk));
718             return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
719         }
720     }
721     fprintf(stderr,"cant find enough inputs or mismatched total\n");
722     return("");
723 }
724
725 std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
726 {
727     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,mypriv[32]; std::string coin; std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65],coinaddr[64];
728     cp = CCinit(&C,EVAL_GATEWAYS);
729     assetscp = CCinit(&C2,EVAL_ASSETS);
730     if ( txfee == 0 )
731         txfee = 10000;
732     mypk = pubkey2pk(Mypubkey());
733     gatewayspk = GetUnspendable(cp,0);
734     _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
735     CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr);
736     Myprivkey(mypriv);
737     _GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk);
738     CCaddr3set(assetscp,EVAL_GATEWAYS,mypk,mypriv,coinaddr);
739     if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
740     {
741         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
742         return("");
743     }
744     if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
745     {
746         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
747         return("");
748     }
749     if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 )
750     {
751         if ( (inputs= AddAssetInputs(assetscp,mtx,mypk,assetid,amount,60)) > 0 )
752         {
753             if ( inputs > amount )
754                 CCchange = (inputs - amount);
755             mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,gatewayspk));
756             mtx.vout.push_back(CTxOut(txfee,CScript() << withdrawpub << OP_CHECKSIG));
757             mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG));
758             if ( CCchange != 0 )
759                 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
760             return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
761         }
762     }
763     fprintf(stderr,"cant find enough inputs or mismatched total\n");
764     return("");
765 }
766
767 UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
768 {
769     UniValue result(UniValue::VOBJ),pending(UniValue::VARR),obj(UniValue::VOBJ); CTransaction tx; std::string coin; CPubKey mypk,gatewayspk; std::vector<CPubKey> msigpubkeys; uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32]; int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply; struct CCcontract_info *cp,C;
770     std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
771     cp = CCinit(&C,EVAL_GATEWAYS);
772     mypk = pubkey2pk(Mypubkey());
773     gatewayspk = GetUnspendable(cp,0);
774     _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
775     if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
776     {
777         fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
778         return(result);
779     }
780     if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
781     {
782         fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
783         return(result);
784     }
785     n = msigpubkeys.size();
786     queueflag = 0;
787     for (i=0; i<n; i++)
788         if ( msigpubkeys[i] == mypk )
789         {
790             queueflag = 1;
791             break;
792         }
793     Getscriptaddress(withmarker,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG);
794     SetCCunspents(unspentOutputs,withmarker);
795     numqueued = 0;
796     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
797     {
798         txid = it->first.txhash;
799         vout = (int32_t)it->first.index;
800         if ( GetTransaction(txid,tx,hashBlock,false) != 0 )
801         {
802             Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
803             Getscriptaddress(withaddr,tx.vout[1].scriptPubKey);
804             if ( strcmp(destaddr,coinaddr) == 0 )
805             {
806                 obj.push_back(Pair("txid",uint256_str(str,txid)));
807                 obj.push_back(Pair("withdrawaddr",withaddr));
808                 sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN);
809                 obj.push_back(Pair("amount",numstr));
810                 pending.push_back(obj);
811                 if ( queueflag != 0 )
812                     numqueued += GatewaysAddQueue(refcoin,txid,tx.vout[1].scriptPubKey,tx.vout[0].nValue);
813             }
814         }
815     }
816     result.push_back(Pair("coin",refcoin));
817     result.push_back(Pair("pending",pending));
818     result.push_back(Pair("queueflag",queueflag));
819     return(result);
820 }
821
This page took 0.062315 seconds and 2 git commands to generate.