]>
Commit | Line | Data |
---|---|---|
c926780f | 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 | ||
7f9283e5 | 18 | /* |
5955955d | 19 | prevent duplicate bindtxid via mempool scan |
3f4351c9 | 20 | wait for notarization for oraclefeed and validation of gatewaysdeposit |
3f4351c9 | 21 | |
22 | validation | |
23 | ||
7f9283e5 | 24 | string oracles |
25 | */ | |
26 | ||
c926780f | 27 | /* |
366625ca | 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 | ||
3515c101 | 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 | |
366625ca | 52 | |
2e338e79 | 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. | |
9a63c0cf | 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 |
2e338e79 | 59 | |
77fad432 | 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 | |
98c80286 | 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 | ||
d73f18f5 | 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 | ||
e2d99d8d | 99 | 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 pubkey for RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha |
d73f18f5 | 100 | ./komodo-cli z_sendmany "<funding addr>" '[{"address":"RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha","amount":0.0001},{"address":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","amount":7.6999}]' |
7f9283e5 | 101 | bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 height.1003776 merkle.90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f |
d73f18f5 | 102 | |
103 | ./komodo-cli gettxoutproof '["bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009"]' | |
104 | 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b | |
105 | ||
106 | ./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 | |
107 | 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b | |
108 | ||
e5a5dadb | 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 | |
0b62b807 | 111 | -> 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 |
f81291ae | 112 | |
c434b250 | 113 | to get the merkleroots onchain, from the multisig signers nodes run the oraclefeed program with acname oracletxid pubkey Ihh |
114 | ./oraclefeed AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh | |
115 | ||
7f9283e5 | 116 | gatewaysclaim bindtxid coin deposittxid destpub amount |
0b62b807 | 117 | ./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999 |
9d860bd9 | 118 | |
119 | now the asset is in the pubkey's asset address! | |
120 | it can be used, traded freely and any node who has the asset can do a gatewayswithdraw | |
121 | ||
122 | gatewayswithdraw bindtxid coin withdrawpub amount | |
123 | ./c gatewayswithdraw e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828 1 | |
5955955d | 124 | ef3cc452da006eb2edda6b6ed3d3347664be51260f3e91f59ec44ec9701367f0 |
125 | ||
126 | Now there is a withdraw pending, so it needs to be processed by the signing nodes on the KMD side | |
e3cd34a4 | 127 | |
128 | gatewayspending bindtxid coin | |
129 | gatewayspending will display all pending withdraws and if it is done on one of the msigpubkeys, then it will queue it for processing | |
130 | ./c gatewayspending e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD | |
131 | ||
c926780f | 132 | */ |
133 | ||
5955955d | 134 | |
1e7f6843 D |
135 | /* |
136 | int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue) // commented, bcz unused | |
5955955d | 137 | { |
138 | char destaddr[64],str[65]; | |
d808ad8e | 139 | Getscriptaddress(destaddr,scriptPubKey); |
5955955d | 140 | fprintf(stderr,"GatewaysAddQueue: %s %s %s %.8f\n",coin.c_str(),uint256_str(str,txid),destaddr,(double)nValue/COIN); |
141 | } | |
1e7f6843 | 142 | */ |
5955955d | 143 | |
c926780f | 144 | // start of consensus code |
145 | ||
3515c101 | 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; | |
2e338e79 | 149 | opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys << oracletxid); |
3515c101 | 150 | return(opret); |
151 | } | |
152 | ||
7f9283e5 | 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) |
3515c101 | 154 | { |
155 | CScript opret; uint8_t evalcode = EVAL_GATEWAYS; | |
7f9283e5 | 156 | opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << deposithex << proof << destpub << amount); |
3515c101 | 157 | return(opret); |
158 | } | |
159 | ||
7f9283e5 | 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) |
3515c101 | 161 | { |
162 | std::vector<uint8_t> vopret; uint8_t *script,e,f; | |
163 | GetOpReturnData(scriptPubKey, vopret); | |
164 | script = (uint8_t *)vopret.data(); | |
7f9283e5 | 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 ) |
3515c101 | 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; | |
2e338e79 | 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 ) |
3515c101 | 179 | { |
180 | if ( prefix == 60 ) | |
181 | { | |
182 | if ( N > 1 ) | |
183 | Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys)); | |
cd936644 | 184 | else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG); |
3515c101 | 185 | } |
186 | else | |
187 | { | |
9a63c0cf | 188 | fprintf(stderr,"need to generate non-KMD addresses prefix.%d\n",prefix); |
3515c101 | 189 | } |
190 | return(f); | |
9a63c0cf | 191 | } else fprintf(stderr,"error decoding bind opret\n"); |
3515c101 | 192 | return(0); |
193 | } | |
194 | ||
c926780f | 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 | ||
4ecaf167 | 244 | bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn, bool fulfilled) |
c926780f | 245 | { |
246 | int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; | |
c926780f | 247 | std::vector<std::pair<CAddressIndexKey, CAmount> > txids; |
48bde33c | 248 | fprintf(stderr,"return true without gateways validation\n"); |
c742ef4c | 249 | return(true); |
c926780f | 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 | { | |
3515c101 | 299 | if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 ) |
c926780f | 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 | ||
612f676a | 314 | int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool! |
315 | { | |
8c4abc12 | 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; |
612f676a | 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 | { | |
8c4abc12 | 325 | if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' ) |
612f676a | 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 | ||
5955955d | 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 | { | |
d808ad8e | 349 | Getscriptaddress(destaddr,tx.vout[i].scriptPubKey); |
5955955d | 350 | if ( strcmp(destaddr,coinaddr) == 0 ) |
351 | { | |
d808ad8e | 352 | fprintf(stderr,"found (%s) vout in mempool\n",coinaddr); |
5955955d | 353 | return(1); |
354 | } | |
355 | } | |
356 | } | |
357 | } | |
358 | return(0); | |
359 | } | |
360 | ||
612f676a | 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); | |
612f676a | 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 | } | |
5955955d | 371 | return(myIs_coinaddr_inmempoolvout(txidaddr)); |
612f676a | 372 | } |
373 | ||
3515c101 | 374 | UniValue GatewaysInfo(uint256 bindtxid) |
375 | { | |
5fca6e7e | 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; |
3515c101 | 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); | |
5fca6e7e | 381 | _GetCCaddress(gatewaysassets,EVAL_ASSETS,Gatewayspk); |
3515c101 | 382 | if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) |
383 | { | |
9a63c0cf | 384 | depositaddr[0] = 0; |
3515c101 | 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 | { | |
3515c101 | 387 | if ( N > 1 ) |
388 | { | |
389 | result.push_back(Pair("M",M)); | |
390 | result.push_back(Pair("N",N)); | |
2e338e79 | 391 | for (i=0; i<N; i++) |
434e600c | 392 | a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i])); |
2e338e79 | 393 | result.push_back(Pair("pubkeys",a)); |
434e600c | 394 | } else result.push_back(Pair("pubkey",pubkey33_str(str,(uint8_t *)&pubkeys[0]))); |
3515c101 | 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)); | |
2e338e79 | 404 | remaining = CCaddress_balance(gatewaysassets); |
3515c101 | 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 | { | |
ea21fde9 | 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; |
3515c101 | 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) | |
c926780f | 434 | { |
ea21fde9 | 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; |
c926780f | 436 | cp = CCinit(&C,EVAL_GATEWAYS); |
3515c101 | 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 | { | |
cd936644 | 457 | Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG); |
ea21fde9 | 458 | if ( CCaddress_balance(coinaddr) == 0 ) |
3515c101 | 459 | { |
460 | fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i); | |
461 | return(""); | |
462 | } | |
463 | } | |
c926780f | 464 | if ( txfee == 0 ) |
465 | txfee = 10000; | |
c926780f | 466 | mypk = pubkey2pk(Mypubkey()); |
3515c101 | 467 | gatewayspk = GetUnspendable(cp,0); |
468 | if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 ) | |
469 | { | |
f9e754a8 | 470 | fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid)); |
3515c101 | 471 | return(""); |
472 | } | |
ea21fde9 | 473 | if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply ) |
3515c101 | 474 | { |
382b39e2 | 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); |
3515c101 | 476 | return(""); |
477 | } | |
ea21fde9 | 478 | if ( CCtoken_balance(destaddr,tokenid) != totalsupply ) |
3515c101 | 479 | { |
382b39e2 | 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); |
3515c101 | 481 | return(""); |
482 | } | |
f9e754a8 | 483 | if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 ) |
3515c101 | 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 | { | |
8096afff | 490 | fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str()); |
3515c101 | 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 | } | |
612f676a | 498 | if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) // dont forget to check mempool! |
3515c101 | 499 | { |
8096afff | 500 | fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid)); |
3515c101 | 501 | return(""); |
612f676a | 502 | } |
3515c101 | 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 | { | |
db6b7e17 | 514 | CTransaction tx; uint256 hash,mhash,hashBlock,oracletxid; int64_t val; int32_t numvouts; int64_t merkleht; CPubKey pk; std::vector<uint8_t>data; |
3515c101 | 515 | txid = zeroid; |
20007e86 | 516 | char str[65]; fprintf(stderr,"reverse scan %s\n",uint256_str(str,batontxid)); |
3515c101 | 517 | while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) |
518 | { | |
20007e86 | 519 | fprintf(stderr,"reverse scan %s\n",uint256_str(str,batontxid)); |
3515c101 | 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 ) | |
c926780f | 523 | { |
3515c101 | 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 ) | |
c926780f | 526 | { |
3515c101 | 527 | txid = batontxid; |
528 | return(mhash); | |
529 | } else return(zeroid); | |
c926780f | 530 | } |
3515c101 | 531 | batontxid = hash; |
532 | } else break; | |
533 | } | |
534 | return(zeroid); | |
535 | } | |
536 | ||
7f9283e5 | 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) | |
3515c101 | 551 | { |
159a3dfa | 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; |
3515c101 | 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 | { | |
db6b7e17 | 560 | fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str()); |
3515c101 | 561 | return(0); |
562 | } | |
7f9283e5 | 563 | proofroot = BitcoinGetProofMerkleRoot(proof,txids); |
159a3dfa | 564 | if ( proofroot != merkleroot ) |
7f9283e5 | 565 | { |
566 | fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot)); | |
567 | return(0); | |
568 | } | |
3515c101 | 569 | if ( DecodeHexTx(tx,deposithex) != 0 ) |
570 | { | |
7f9283e5 | 571 | Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey); |
572 | Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); | |
573 | if ( strcmp(claimaddr,destpubaddr) == 0 ) | |
3515c101 | 574 | { |
7f9283e5 | 575 | for (i=0; i<numvouts; i++) |
3515c101 | 576 | { |
7f9283e5 | 577 | Getscriptaddress(destaddr,tx.vout[i].scriptPubKey); |
578 | if ( strcmp(refdepositaddr,destaddr) == 0 ) | |
a609fa64 | 579 | { |
580 | txid = tx.GetHash(); | |
581 | nValue = tx.vout[i].nValue; | |
582 | break; | |
3242301d | 583 | } |
7f9283e5 | 584 | } |
585 | } else fprintf(stderr,"claimaddr.(%s) != destpubaddr.(%s)\n",claimaddr,destpubaddr); | |
3515c101 | 586 | } |
587 | if ( txid == cointxid ) | |
588 | { | |
589 | fprintf(stderr,"verify proof for cointxid in merkleroot\n"); | |
590 | return(nValue); | |
4ada5219 | 591 | } else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch\n",refdepositaddr,destaddr,txid != cointxid); |
3515c101 | 592 | return(0); |
593 | } | |
594 | ||
595 | int64_t GatewaysDepositval(CTransaction tx) | |
596 | { | |
8571958e | 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; |
3515c101 | 598 | if ( (numvouts= tx.vout.size()) > 0 ) |
599 | { | |
4df0d20a | 600 | if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' ) |
3515c101 | 601 | { |
602 | // coin, bindtxid, publishers | |
603 | fprintf(stderr,"need to validate deposittxid more\n"); | |
604 | return(amount); | |
c926780f | 605 | } |
3515c101 | 606 | } |
607 | return(0); | |
608 | } | |
609 | ||
e5a5dadb | 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) |
3515c101 | 611 | { |
20007e86 | 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]; |
3515c101 | 613 | cp = CCinit(&C,EVAL_GATEWAYS); |
614 | if ( txfee == 0 ) | |
615 | txfee = 10000; | |
616 | mypk = pubkey2pk(Mypubkey()); | |
617 | gatewayspk = GetUnspendable(cp,0); | |
e1529dc1 | 618 | //fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size()); |
3515c101 | 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)); | |
c926780f | 622 | return(""); |
3515c101 | 623 | } |
e5a5dadb | 624 | if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) |
3515c101 | 625 | { |
857346ef | 626 | fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); |
3515c101 | 627 | return(""); |
628 | } | |
629 | n = (int32_t)pubkeys.size(); | |
630 | merkleroot = zeroid; | |
631 | for (i=m=0; i<n; i++) | |
632 | { | |
8b60ad59 | 633 | fprintf(stderr,"pubkeys[%d] %s\n",i,pubkey33_str(str,(uint8_t *)&pubkeys[i])); |
c66988d0 | 634 | if ( (mhash= GatewaysReverseScan(txid,height,oracletxid,OraclesBatontxid(oracletxid,pubkeys[i]))) != zeroid ) |
3515c101 | 635 | { |
636 | if ( merkleroot == zeroid ) | |
637 | merkleroot = mhash, m = 1; | |
638 | else if ( mhash == merkleroot ) | |
639 | m++; | |
4df0d20a | 640 | publishers.push_back(pubkeys[i]); |
641 | txids.push_back(txid); | |
3515c101 | 642 | } |
643 | } | |
20007e86 | 644 | fprintf(stderr,"m.%d of n.%d\n",m,n); |
7f9283e5 | 645 | if ( merkleroot == zeroid || m < n/2 ) |
3515c101 | 646 | { |
b4df8470 | 647 | //uint256 tmp; |
648 | //decode_hex((uint8_t *)&tmp,32,(char *)"90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f"); | |
649 | //merkleroot = revuint256(tmp); | |
857346ef | 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); |
b4df8470 | 651 | return(""); |
3515c101 | 652 | } |
87904dc9 | 653 | if ( GatewaysCointxidExists(cp,cointxid) != 0 ) |
654 | { | |
655 | fprintf(stderr,"cointxid.%s already exists\n",uint256_str(str,cointxid)); | |
656 | return(""); | |
657 | } | |
7f9283e5 | 658 | if ( GatewaysVerify(depositaddr,oracletxid,claimvout,coin,cointxid,deposithex,proof,merkleroot,destpub) != amount ) |
3515c101 | 659 | { |
660 | fprintf(stderr,"deposittxid didnt validate\n"); | |
661 | return(""); | |
662 | } | |
612f676a | 663 | if ( AddNormalinputs(mtx,mypk,3*txfee,60) > 0 ) |
3515c101 | 664 | { |
665 | mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); | |
612f676a | 666 | mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); |
7f9283e5 | 667 | return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,destpub,amount))); |
3515c101 | 668 | } |
669 | fprintf(stderr,"cant find enough inputs\n"); | |
c926780f | 670 | return(""); |
671 | } | |
672 | ||
7f9283e5 | 673 | std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount) |
c926780f | 674 | { |
23e0b80b | 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]; |
c926780f | 676 | cp = CCinit(&C,EVAL_GATEWAYS); |
3515c101 | 677 | assetscp = CCinit(&C2,EVAL_ASSETS); |
c926780f | 678 | if ( txfee == 0 ) |
679 | txfee = 10000; | |
680 | mypk = pubkey2pk(Mypubkey()); | |
3515c101 | 681 | gatewayspk = GetUnspendable(cp,0); |
dfac32e4 | 682 | _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk); |
683 | CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr); | |
23e0b80b | 684 | Myprivkey(mypriv); |
685 | _GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk); | |
686 | CCaddr3set(assetscp,EVAL_GATEWAYS,mypk,mypriv,coinaddr); | |
3515c101 | 687 | if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) |
c926780f | 688 | { |
3515c101 | 689 | fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); |
690 | return(""); | |
c926780f | 691 | } |
3515c101 | 692 | if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) |
693 | { | |
857346ef | 694 | fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); |
3515c101 | 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 | } | |
2f51e8fa | 702 | if ( (depositamount= GatewaysDepositval(tx)) != amount ) |
3515c101 | 703 | { |
2f51e8fa | 704 | fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN); |
3515c101 | 705 | return(""); |
706 | } | |
bb81559f | 707 | //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); |
3515c101 | 708 | if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) |
709 | { | |
23e0b80b | 710 | if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,amount,60)) > 0 ) |
3515c101 | 711 | { |
c66988d0 | 712 | if ( inputs > amount ) |
713 | CCchange = (inputs - amount); | |
3515c101 | 714 | mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); |
2f51e8fa | 715 | mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); |
3515c101 | 716 | if ( CCchange != 0 ) |
717 | mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk)); | |
23e0b80b | 718 | return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey()))); |
3515c101 | 719 | } |
720 | } | |
721 | fprintf(stderr,"cant find enough inputs or mismatched total\n"); | |
c926780f | 722 | return(""); |
723 | } | |
724 | ||
3515c101 | 725 | std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount) |
c926780f | 726 | { |
f978cd48 | 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]; |
c926780f | 728 | cp = CCinit(&C,EVAL_GATEWAYS); |
3515c101 | 729 | assetscp = CCinit(&C2,EVAL_ASSETS); |
730 | if ( txfee == 0 ) | |
731 | txfee = 10000; | |
732 | mypk = pubkey2pk(Mypubkey()); | |
733 | gatewayspk = GetUnspendable(cp,0); | |
3f4351c9 | 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); | |
3515c101 | 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 | { | |
857346ef | 746 | fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); |
3515c101 | 747 | return(""); |
748 | } | |
5955955d | 749 | if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 ) |
3515c101 | 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)); | |
3f4351c9 | 756 | mtx.vout.push_back(CTxOut(txfee,CScript() << withdrawpub << OP_CHECKSIG)); |
5955955d | 757 | mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG)); |
3515c101 | 758 | if ( CCchange != 0 ) |
759 | mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); | |
2f51e8fa | 760 | return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey()))); |
3515c101 | 761 | } |
762 | } | |
763 | fprintf(stderr,"cant find enough inputs or mismatched total\n"); | |
764 | return(""); | |
c926780f | 765 | } |
766 | ||
6bde696a | 767 | std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid) |
768 | { | |
b31844cb | 769 | CMutableTransaction mtx; CScript opret; CPubKey mypk; struct CCcontract_info *cp,C; |
6bde696a | 770 | cp = CCinit(&C,EVAL_GATEWAYS); |
771 | if ( txfee == 0 ) | |
9f72c41a | 772 | txfee = 5000; |
6bde696a | 773 | mypk = pubkey2pk(Mypubkey()); |
774 | mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript())); | |
9f72c41a | 775 | mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); |
6bde696a | 776 | return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); |
777 | } | |
778 | ||
e3cd34a4 | 779 | UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) |
5955955d | 780 | { |
62f0cedd | 781 | 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],txidaddr[64],signeraddr[64]; int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply; struct CCcontract_info *cp,C; |
5955955d | 782 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; |
783 | cp = CCinit(&C,EVAL_GATEWAYS); | |
784 | mypk = pubkey2pk(Mypubkey()); | |
785 | gatewayspk = GetUnspendable(cp,0); | |
786 | _GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk); | |
787 | if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) | |
788 | { | |
789 | fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); | |
790 | return(result); | |
791 | } | |
792 | if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) | |
793 | { | |
794 | fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); | |
795 | return(result); | |
796 | } | |
797 | n = msigpubkeys.size(); | |
798 | queueflag = 0; | |
799 | for (i=0; i<n; i++) | |
800 | if ( msigpubkeys[i] == mypk ) | |
801 | { | |
802 | queueflag = 1; | |
803 | break; | |
804 | } | |
805 | Getscriptaddress(withmarker,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG); | |
806 | SetCCunspents(unspentOutputs,withmarker); | |
807 | numqueued = 0; | |
808 | for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) | |
809 | { | |
810 | txid = it->first.txhash; | |
811 | vout = (int32_t)it->first.index; | |
812 | if ( GetTransaction(txid,tx,hashBlock,false) != 0 ) | |
813 | { | |
814 | Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); | |
815 | Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); | |
816 | if ( strcmp(destaddr,coinaddr) == 0 ) | |
817 | { | |
4f61de87 | 818 | obj.push_back(Pair("txid",uint256_str(str,txid))); |
2d16b4db | 819 | CCtxidaddr(txidaddr,txid); |
820 | obj.push_back(Pair("txidaddr",txidaddr)); | |
4f61de87 | 821 | obj.push_back(Pair("withdrawaddr",withaddr)); |
5955955d | 822 | sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN); |
4f61de87 | 823 | obj.push_back(Pair("amount",numstr)); |
62f0cedd | 824 | if ( queueflag != 0 ) |
825 | { | |
826 | obj.push_back(Pair("depositaddr",depositaddr)); | |
827 | Getscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG); | |
828 | obj.push_back(Pair("signeraddr",signeraddr)); | |
829 | // numqueued += GatewaysAddQueue(refcoin,txid,tx.vout[1].scriptPubKey,tx.vout[0].nValue); | |
830 | } | |
f602ac98 | 831 | pending.push_back(obj); |
5955955d | 832 | } |
833 | } | |
834 | } | |
835 | result.push_back(Pair("coin",refcoin)); | |
836 | result.push_back(Pair("pending",pending)); | |
837 | result.push_back(Pair("queueflag",queueflag)); | |
838 | return(result); | |
839 | } | |
3515c101 | 840 |