1 /******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
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. *
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 *
12 * Removal or modification of this copyright notice is prohibited. *
14 ******************************************************************************/
16 #include "CCGateways.h"
19 prevent duplicate bindtxid via mempool scan
20 wait for notarization for oraclefeed and validation of gatewaysdeposit
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.
31 the potential pubkeys to be used would be based on active oracle data providers with recent activity.
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
37 redeem -> asset to global CC address with withdraw address -> gateway spendable marker utxo
38 spend market utxo and withdraw from gateway deposit address
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
48 GatewayWithdraw coin tokenid withdrawaddr
49 external: do withdraw to withdrawaddr and spend marker, support for partial signatures and autocomplete
51 deposit addr can be 1 to MofN pubkeys
52 1:1 gateway with native coin
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
62 ./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC
63 a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a
65 transfer to gateways pubkey: 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 RDMqGyREkP1Gwub1Nr5Ye8a325LGZsWBCb
66 ./c tokentransfer a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 100000000000000
67 2206fc39c0f384ca79819eb491ddbf889642cbfe4d0796bb6a8010ed53064a56
69 ./c oraclescreate KMD blockheaders Ihh
70 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808
72 ./c oraclesregister 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 1000000
73 83b59eac238cbe54616ee13b2fdde85a48ec869295eb04051671a1727c9eb402
75 ./c oraclessubscribe 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1000
76 f9499d8bb04ffb511fcec4838d72e642ec832558824a2ce5aed87f1f686f8102
78 ./c gatewaysbind a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 KMD 100000000000000 1 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92
79 e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
81 ./c gatewaysinfo e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
85 "pubkey": "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92",
87 "oracletxid": "1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808",
92 "tokenid": "a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a",
93 "totalsupply": "1000000.00000000",
94 "remaining": "1000000.00000000",
95 "issued": "0.00000000"
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.
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
104 ./komodo-cli gettxoutproof '["bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009"]'
105 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b
107 ./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009
108 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b
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
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
117 gatewaysclaim bindtxid coin deposittxid destpub amount
118 ./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
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
123 gatewayswithdraw bindtxid coin withdrawpub amount
124 ./c gatewayswithdraw e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828 1
125 ef3cc452da006eb2edda6b6ed3d3347664be51260f3e91f59ec44ec9701367f0
127 Now there is a withdraw pending, so it needs to be processed by the signing nodes on the KMD side
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
137 int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue)
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);
144 // start of consensus code
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)
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);
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)
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);
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)
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 )
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)
174 std::vector<uint8_t> vopret; uint8_t *script,e,f;
175 GetOpReturnData(scriptPubKey, vopret);
176 script = (uint8_t *)vopret.data();
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 )
183 Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
184 else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
188 fprintf(stderr,"need to generate non-KMD addresses prefix.%d\n",prefix);
191 } else fprintf(stderr,"error decoding bind opret\n");
195 int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
198 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
200 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
201 return(tx.vout[v].nValue);
206 bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
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++)
214 //fprintf(stderr,"vini.%d\n",i);
215 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
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");
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;
230 for (i=0; i<numvouts; i++)
232 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
233 if ( (assetoshis= IsGatewaysvout(cp,tx,i)) != 0 )
234 outputs += assetoshis;
236 if ( inputs != outputs+txfee )
238 fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
239 return eval->Invalid("mismatched inputs != outputs + txfee");
244 bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
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");
250 numvins = tx.vin.size();
251 numvouts = tx.vout.size();
252 preventCCvins = preventCCvouts = -1;
254 return eval->Invalid("no vouts");
257 for (i=0; i<numvins; i++)
259 if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
261 return eval->Invalid("illegal normal vini");
264 //fprintf(stderr,"check amounts\n");
265 if ( GatewaysExactAmounts(cp,eval,tx,1,10000) == false )
267 fprintf(stderr,"Gatewaysget invalid amount\n");
273 memcpy(hash,&txid,sizeof(hash));
274 retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
276 fprintf(stderr,"Gatewaysget validated\n");
277 else fprintf(stderr,"Gatewaysget invalid\n");
282 // end of consensus code
284 // helper functions for rpc calls in rpcwallet.cpp
286 int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
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++)
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 )
299 if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
301 if ( total != 0 && maxinputs != 0 )
302 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
303 nValue = it->second.satoshis;
304 totalinputs += nValue;
306 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
314 int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool!
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++)
323 if ( GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
325 if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' )
327 if ( tokenid == reftokenid )
329 fprintf(stderr,"trying to bind an existing tokenid\n");
338 static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr)
340 int32_t i,n; char destaddr[64];
341 BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
343 const CTransaction &tx = e.GetTx();
344 if ( (n= tx.vout.size()) > 0 )
346 const uint256 &txid = tx.GetHash();
349 Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
350 if ( strcmp(destaddr,coinaddr) == 0 )
352 fprintf(stderr,"found (%s) vout in mempool\n",coinaddr);
361 int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) // dont forget to check mempool!
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++)
371 return(myIs_coinaddr_inmempoolvout(txidaddr));
374 UniValue GatewaysInfo(uint256 bindtxid)
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 )
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 )
389 result.push_back(Pair("M",M));
390 result.push_back(Pair("N",N));
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));
414 UniValue GatewaysList()
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++)
421 txid = it->first.txhash;
422 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
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 )
426 result.push_back(uint256_str(str,txid));
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)
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 )
439 fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
442 if ( strcmp((char *)"KMD",coin.c_str()) != 0 )
444 fprintf(stderr,"only KMD supported for now\n");
450 if ( pubkeys.size() != N )
452 fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
457 Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
458 if ( CCaddress_balance(coinaddr) == 0 )
460 fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i);
466 mypk = pubkey2pk(Mypubkey());
467 gatewayspk = GetUnspendable(cp,0);
468 if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 )
470 fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid));
473 if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply )
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);
478 if ( CCtoken_balance(destaddr,tokenid) != totalsupply )
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);
483 if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
485 fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
488 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
490 fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str());
493 if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 )
495 fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh");
498 if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) // dont forget to check mempool!
500 fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid));
503 if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
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)));
508 fprintf(stderr,"cant find enough inputs\n");
512 uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
514 CTransaction tx; uint256 hash,mhash,hashBlock,oracletxid; int64_t val; int32_t numvouts; int64_t merkleht; CPubKey pk; std::vector<uint8_t>data;
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 )
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 )
522 if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
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 )
529 } else return(zeroid);
537 /* Get the block merkle root for a proof
540 * OUT: transaction IDS
542 uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids)
544 CMerkleBlock merkleBlock;
545 if (!E_UNMARSHAL(proofData, ss >> merkleBlock))
547 return merkleBlock.txn.ExtractMatches(txids);
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)
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 )
555 fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid));
558 if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin )
560 fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str());
563 proofroot = BitcoinGetProofMerkleRoot(proof,txids);
564 if ( proofroot != merkleroot )
566 fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot));
569 if ( DecodeHexTx(tx,deposithex) != 0 )
571 Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey);
572 Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
573 if ( strcmp(claimaddr,destpubaddr) == 0 )
575 for (i=0; i<numvouts; i++)
577 Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
578 if ( strcmp(refdepositaddr,destaddr) == 0 )
581 nValue = tx.vout[i].nValue;
585 } else fprintf(stderr,"claimaddr.(%s) != destpubaddr.(%s)\n",claimaddr,destpubaddr);
587 if ( txid == cointxid )
589 fprintf(stderr,"verify proof for cointxid in merkleroot\n");
591 } else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch\n",refdepositaddr,destaddr,txid != cointxid);
595 int64_t GatewaysDepositval(CTransaction tx)
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 )
600 if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' )
602 // coin, bindtxid, publishers
603 fprintf(stderr,"need to validate deposittxid more\n");
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)
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);
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 )
621 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
624 if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin )
626 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
629 n = (int32_t)pubkeys.size();
631 for (i=m=0; i<n; i++)
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 )
636 if ( merkleroot == zeroid )
637 merkleroot = mhash, m = 1;
638 else if ( mhash == merkleroot )
640 publishers.push_back(pubkeys[i]);
641 txids.push_back(txid);
644 fprintf(stderr,"m.%d of n.%d\n",m,n);
645 if ( merkleroot == zeroid || m < n/2 )
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);
653 if ( GatewaysCointxidExists(cp,cointxid) != 0 )
655 fprintf(stderr,"cointxid.%s already exists\n",uint256_str(str,cointxid));
658 if ( GatewaysVerify(depositaddr,oracletxid,claimvout,coin,cointxid,deposithex,proof,merkleroot,destpub) != amount )
660 fprintf(stderr,"deposittxid didnt validate\n");
663 if ( AddNormalinputs(mtx,mypk,3*txfee,60) > 0 )
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)));
669 fprintf(stderr,"cant find enough inputs\n");
673 std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount)
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);
680 mypk = pubkey2pk(Mypubkey());
681 gatewayspk = GetUnspendable(cp,0);
682 _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
683 CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr);
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 )
689 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
692 if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
694 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
697 if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
699 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
702 if ( (depositamount= GatewaysDepositval(tx)) != amount )
704 fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN);
707 //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2);
708 if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
710 if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,amount,60)) > 0 )
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));
717 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk));
718 return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
721 fprintf(stderr,"cant find enough inputs or mismatched total\n");
725 std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
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);
732 mypk = pubkey2pk(Mypubkey());
733 gatewayspk = GetUnspendable(cp,0);
734 _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
735 CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr);
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 )
741 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
744 if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
746 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
749 if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 )
751 if ( (inputs= AddAssetInputs(assetscp,mtx,mypk,assetid,amount,60)) > 0 )
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));
759 mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
760 return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
763 fprintf(stderr,"cant find enough inputs or mismatched total\n");
767 UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
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 )
777 fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
780 if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
782 fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
785 n = msigpubkeys.size();
788 if ( msigpubkeys[i] == mypk )
793 Getscriptaddress(withmarker,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG);
794 SetCCunspents(unspentOutputs,withmarker);
796 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
798 txid = it->first.txhash;
799 vout = (int32_t)it->first.index;
800 if ( GetTransaction(txid,tx,hashBlock,false) != 0 )
802 Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
803 Getscriptaddress(withaddr,tx.vout[1].scriptPubKey);
804 if ( strcmp(destaddr,coinaddr) == 0 )
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);
816 result.push_back(Pair("coin",refcoin));
817 result.push_back(Pair("pending",pending));
818 result.push_back(Pair("queueflag",queueflag));