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