-
Notifications
You must be signed in to change notification settings - Fork 23
/
resend_funds.sh
executable file
·305 lines (268 loc) · 13.9 KB
/
resend_funds.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
#!/bin/bash
# [AJSS] Awesome Join + Split Script by Decker (c) 2019
#
# This will create specific joinsplit (transparent) tx in which:
#
# vins : all your existing utxos except immature or non-spendable in other reasons
# vouts : 1. NOTARYVIN_NUM x P2PK iguana utxos for address corresponding to your pubkey
# 2. 1 x P2SH utxo with 0.01 amount to track using of script (plz, don't remove it, 0.01 KMD is not so much)
# 3. 1 x P2PKH utxo with change for address corresponding to your pubkey
# fee : 4. smart fee calc is not yet implemented, so it will use fixed fee = 0.00077777
#
# Environment variables:
#
# pubkey - your pubkey (pubkey set is important, otherwise it will be use default dev pubkey) [!!!]
# KOMODOD_CONFIGFILE - full path to your komodo.conf or %ac_name%.conf
# NOTARYVIN_NUM - count of notary vins (P2PK) / iguana utxos that needs to be created
#
# AWJS is experimental and a work-in-progress. Use at your own risk!
#
# F.A.Q. (and useful commands)
#
# Q. How can use measure speed improvement after AJSS?
# A. Use the following command(s):
#
# time (~/komodo/src/komodo-cli listunspent | jq '. | { "utxos" : length }' && ~/komodo/src/komodo-cli getwalletinfo | jq '{ "txcount" : .txcount }') | jq -s '.[0] * .[1]'
# time (~/komodo/src/komodo-cli listunspent | jq '. | { "utxos" : length }' && ~/komodo/src/komodo-cli getwalletinfo | jq '{ "txcount" : .txcount }') | jq -s add
#
# Output will be like:
#
# {
# "utxos": 70,
# "txcount": 4022
# }
#
# real 0m0.112s
# user 0m0.032s
# sys 0m0.010s
# --------------------------------------------------------------------------
function init_colors() {
RESET="\033[0m"
BLACK="\033[30m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
BLUE="\033[34m"
MAGENTA="\033[35m"
CYAN="\033[36m"
WHITE="\033[37m"
BRIGHT="\033[1m"
DARKGREY="\033[90m"
}
# --------------------------------------------------------------------------
function log_print() {
datetime=$(date '+%Y-%m-%d %H:%M:%S')
echo -e [$datetime] $1
}
# --------------------------------------------------------------------------
# https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
function checkconfig()
{
if ! grep -qs '^rpcpassword=' "${KOMODOD_CONFIGFILE}" ; then
log_print "Parsing: ${KOMODOD_CONFIGFILE} - ${RED}FAILED${RESET}"
return 1
fi
if ! grep -qs '^rpcuser=' "${KOMODOD_CONFIGFILE}" ; then
log_print "Parsing: ${KOMODOD_CONFIGFILE} - ${RED}FAILED${RESET}"
return 1
fi
grep -qs '^rpcpassword=' "${KOMODOD_CONFIGFILE}"
KOMODOD_RPCPASSWORD=$(grep -s '^rpcpassword=' "${KOMODOD_CONFIGFILE}")
KOMODOD_RPCPASSWORD=${KOMODOD_RPCPASSWORD/rpcpassword=/}
grep -qs '^rpcuser=' "${KOMODOD_CONFIGFILE}"
KOMODOD_RPCUSER=$(grep -s '^rpcuser=' "${KOMODOD_CONFIGFILE}")
KOMODOD_RPCUSER=${KOMODOD_RPCUSER/rpcuser=/}
if ! grep -qs '^rpcport=' "${KOMODOD_CONFIGFILE}" ; then
KOMODO_RPCPORT=7771
else
KOMODO_RPCPORT=$(grep -s '^rpcport=' "${KOMODOD_CONFIGFILE}")
KOMODO_RPCPORT=${KOMODO_RPCPORT/rpcport=/}
fi
log_print "Parsing RPC credentials: ${KOMODOD_CONFIGFILE} - ${GREEN}OK${RESET}"
}
# --------------------------------------------------------------------------
function getbalance() {
res=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getbalance", "params": ["*", 1] }' -H 'content-type: text/plain;' http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/)
if [ "$(echo ${res} | jq .error)" == null ]; then
BALANCE="$(echo ${res} | jq .result)"
else
BALANCE=0
log_print "${RED}ERROR $(echo ${res} | jq .error.code) : $(echo ${res} | jq -r .error.message)${RESET}"
return 1
fi
}
# --------------------------------------------------------------------------
function scriptpub2address() {
# NN_ADDRESS=$(${komodo_cli_binary} decodescript "21${pubkey}ac" | jq -r .addresses[0])
NN_ADDRESS=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "decodescript", "params": ["21'"$1"'ac"] }' -H 'content-type: text/plain;' "http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/")
if [ "$(echo "${NN_ADDRESS}" | jq .error)" == null ]; then
NN_ADDRESS=$(echo "${NN_ADDRESS}" | jq -c .result)
if [ "$(echo "${NN_ADDRESS}" | jq -r .type)" != "pubkey" ]; then
log_print "${RED}ERROR obtaining address from pubkey${RESET}"
return 1;
fi
NN_ADDRESS=$(echo ${NN_ADDRESS} | jq -r .addresses[0])
else
log_print "${RED}ERROR $(echo ${NN_ADDRESS} | jq .error.code) : $(echo ${NN_ADDRESS} | jq -r .error.message)${RESET}"
return 1
fi
}
# --------------------------------------------------------------------------
function listunspent() {
# https://askubuntu.com/questions/714458/bash-script-store-curl-output-in-variable-then-format-against-string-in-va
# https://stackoverflow.com/questions/5076283/shell-variable-capacity
UTXOS=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [1, 9999999, []] }' -H 'content-type: text/plain;' http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/)
if [ "$(echo "${UTXOS}" | jq .error)" == null ]; then
UTXOS=$(echo "${UTXOS}" | jq -c .result)
else
log_print "${RED}ERROR $(echo ${UTXOS} | jq .error.code) : $(echo ${UTXOS} | jq -r .error.message)${RESET}"
return 1
fi
}
# --------------------------------------------------------------------------
function createjoinsplittx() {
NOTARYVIN_NUM=${NOTARYVIN_NUM:-100}
NOTARYVIN_SIZE=0.0001
NOTARYVIN_SUM=$(jq -n "${NOTARYVIN_NUM} * ${NOTARYVIN_SIZE}")
NOTARYVIN_RAW=
log_print "Iguana UTXOs amount: ${NOTARYVIN_SUM}"
for n in $(seq 1 ${NOTARYVIN_NUM})
do
NOTARYVIN_RAW=${NOTARYVIN_RAW}"\"21${NN_PUBKEY}ac\":${NOTARYVIN_SIZE},"
done
NOTARYVIN_RAW=${NOTARYVIN_RAW::-1}
FIXED_FEE=0.00077777 # TODO: add tx fee calculation (!)
TRACK_UTXO_AMOUNT=0.01
CHANGE_AMOUNT=$(jq -n "${UTXOSBALANCE} - ${NOTARYVIN_SUM} - ${FIXED_FEE} - ${TRACK_UTXO_AMOUNT}")
CHANGE_AMOUNT=$(echo ${CHANGE_AMOUNT} | jq 'def round: tostring | (split(".") + ["0"])[:2] | [.[0], "\(.[1])"[:8]] | join(".") | tonumber; . | round')
log_print "Change amount: ${CHANGE_AMOUNT}"
UNSIGNED_RAW_TX=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" \
--data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createrawtransaction", "params": ['"${VINS}"', {"'"${NN_ADDRESS}"'":'"${CHANGE_AMOUNT}"',"a9141cef3747c7894ce843f87f3bf43c8a355321179c87":'"${TRACK_UTXO_AMOUNT}"','"${NOTARYVIN_RAW}"'}] }' -H 'content-type: text/plain;' http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/)
if [ "$(echo "${UNSIGNED_RAW_TX}" | jq .error)" == null ]; then
UNSIGNED_RAW_TX=$(echo "${UNSIGNED_RAW_TX}" | jq -r .result)
UNSIGNED_RAW_TX_SIZE=$((${#UNSIGNED_RAW_TX}/2))
else
log_print "${RED}ERROR $(echo ${UNSIGNED_RAW_TX} | jq .error.code) : $(echo ${UNSIGNED_RAW_TX} | jq -r .error.message)${RESET}"
return 1;
fi
}
# --------------------------------------------------------------------------
function checktxsize() {
MAX_TX_SIZE_BEFORE_SAPLING=100000
MAX_TX_SIZE_AFTER_SAPLING=$((2 * ${MAX_TX_SIZE_BEFORE_SAPLING})) # consensus.h rules
# https://stackoverflow.com/questions/18668556/comparing-numbers-in-bash
if [ "${MAX_TX_SIZE_AFTER_SAPLING}" -gt "${UNSIGNED_RAW_TX_SIZE}" ]; then
log_print "Unsigned raw transaction (Size: ${UNSIGNED_RAW_TX_SIZE} bytes) - ${GREEN}OK${RESET}"
else
log_print "${RED}ERROR MAX_TX_SIZE_AFTER_SAPLING (${MAX_TX_SIZE_AFTER_SAPLING}) exeeded !"
return 1
fi
}
# --------------------------------------------------------------------------
function signrawtransaction {
SIGNED_RAW_TX=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "signrawtransaction", "params": ["'"${UNSIGNED_RAW_TX}"'"] }' -H 'content-type: text/plain;' "http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/")
if [ "$(echo "${SIGNED_RAW_TX}" | jq .error)" == null ]; then
SIGNED_RAW_TX=$(echo "${SIGNED_RAW_TX}" | jq -c .result)
# echo $SIGNED_RAW_TX
SIGNED_RAW_TX_COMPLETE=$(echo "${SIGNED_RAW_TX}" | jq -c .complete)
SIGNED_RAW_TX=$(echo "${SIGNED_RAW_TX}" | jq -r .hex)
# echo ${SIGNED_RAW_TX} ${SIGNED_RAW_TX_COMPLETE}
else
log_print "${RED}ERROR $(echo ${SIGNED_RAW_TX} | jq .error.code) : $(echo ${SIGNED_RAW_TX} | jq -r .error.message)${RESET}"
return 1
fi
}
# --------------------------------------------------------------------------
function sendrawtransaction {
SEND_RAW_TX=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "sendrawtransaction", "params": ["'"${SIGNED_RAW_TX}"'"] }' -H 'content-type: text/plain;' "http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/")
if [ "$(echo "${SEND_RAW_TX}" | jq .error)" == null ]; then
# echo ${SEND_RAW_TX}
SEND_RAW_TX_HASH=$(echo "${SEND_RAW_TX}" | jq -r .result)
else
log_print "${RED}ERROR $(echo ${SEND_RAW_TX} | jq .error.code) : $(echo ${SEND_RAW_TX} | jq -r .error.message)${RESET}"
return 1
fi
}
# --------------------------------------------------------------------------
function waitfortransaction {
wait_counter=0
confirmations=0
while [ "$confirmations" -eq "0" ]
do
GET_TRANSACTION=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "gettransaction", "params": ["'"${SEND_RAW_TX_HASH}"'"] }' -H 'content-type: text/plain;' "http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/")
if [ "$(echo "${GET_TRANSACTION}" | jq .error)" == null ]; then
# echo ${GET_TRANSACTION}
confirmations=$(echo "${GET_TRANSACTION}" | jq -r .result.confirmations)
wait_counter=$((wait_counter+1))
log_print "Waiting for confirmations ($wait_counter).$confirmations"
sleep 10
else
log_print "${RED}ERROR $(echo ${GET_TRANSACTION} | jq .error.code) : $(echo ${GET_TRANSACTION} | jq -r .error.message)${RESET}"
return 1
fi
done
}
# --------------------------------------------------------------------------
function cleanwallettransactions {
CLEAN_WALLWET_TXS=$(curl -s --user "${KOMODOD_RPCUSER}:${KOMODOD_RPCPASSWORD}" --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "cleanwallettransactions", "params": ["'"${SEND_RAW_TX_HASH}"'"] }' -H 'content-type: text/plain;' "http://${KOMODOD_RPCHOST}:${KOMODO_RPCPORT}/")
if [ "$(echo "${CLEAN_WALLWET_TXS}" | jq .error)" == null ]; then
CLEAN_WALLWET_TXS=$(echo "${CLEAN_WALLWET_TXS}" | jq -c .result)
else
log_print "${RED}ERROR $(echo ${CLEAN_WALLWET_TXS} | jq .error.code) : $(echo ${CLEAN_WALLWET_TXS} | jq -r .error.message)${RESET}"
return 1
fi
}
# https://github.com/DeckerSU/chips3/blob/ec2bf830e41087e8d3ded6323703050f9b2846fb/contrib/init/bitcoind.openrc
KOMODOD_DEFAULT_DATADIR=${KOMODOD_DEFAULT_DATADIR:-"$HOME/.komodo"}
KOMODOD_CONFIGFILE=${KOMODOD_CONFIGFILE:-"$KOMODOD_DEFAULT_DATADIR/komodo.conf"}
KOMODOD_RPCHOST=127.0.0.1
init_colors
log_print "Starting ..."
checkconfig || exit
# here we should obtain NN_ADDRESS from NN_PUBKEY via scriptpub2address
source $HOME/komodo/src/pubkey.txt 2> /dev/null
NN_DEFAULT_PUBKEY=02ba1815af3e5068930010c7a79ee7f3f72bbd10980bb0345e7d3c513c7989e1d9
NN_PUBKEY=${pubkey:-${NN_DEFAULT_PUBKEY}}
log_print "Pubkey: ${BLUE}${NN_PUBKEY}${RESET}"
scriptpub2address ${NN_PUBKEY} || exit
log_print "Address: ${BLUE}${NN_ADDRESS}${RESET}"
getbalance || exit
log_print "Balance (getbalance): ${BALANCE}"
listunspent || exit
UTXOSFILTER=".spendable == true" # and (.generated == false or (.generated == true and .confirmations > 100))
# https://www.youtube.com/watch?v=PS_9pyIASvQ // !!Con 2017: Serious Programming with jq?! A Practical and ...! by Charles Chamberlain
VINS=$(echo "${UTXOS}" | jq -c '[.[] | select ('"${UTXOSFILTER}"') | {"txid": .txid, "vout": .vout}]') # for create vins in future raw tx
VINSCOUNT=$(echo ${VINS} | jq '. | length')
if [ "$VINSCOUNT" -eq "0" ]; then
log_print "${RED}ERROR: There is no available utxos to join ...${RESET}"
exit
fi
UTXOSBALANCE=$(echo "${UTXOS}" | jq 'def round: tostring | (split(".") + ["0"])[:2] | [.[0], "\(.[1])"[:8]] | join(".") | tonumber;
[.[] | select ('"${UTXOSFILTER}"') | .amount] | add | round')
log_print "Balance (utxos sum): ${UTXOSBALANCE}"
if [ "${BALANCE}" == "${UTXOSBALANCE}" ]; then
log_print "Balances are ${GREEN}equal${RESET}"
else
log_print "Balances are ${RED}not equal${RESET}"
log_print "This is not a big mistake, can be some small rounding errors"
log_print "or you have some generated coins, that are still immature."
log_print "But you should know, that if you'll do cleanwallettransactions"
log_print "with created txid as an argument - all not included utxos will"
log_print "stay behind your cleaned wallet and for using it you'll need to rescan."
fi
createjoinsplittx || exit
checktxsize || exit
log_print "Transaction info: (vins: ${VINSCOUNT}${RESET}, vouts: ${NOTARYVIN_NUM}+${RESET})"
signrawtransaction || exit
# if you want to auto-broadcast tx just change this condition on true, it's disabled by default to allow
# you to check signed raw transaction before you will setup auto-broadcast.
if false; then
sendrawtransaction || exit
log_print "Broadcasted: ${BLUE}${SEND_RAW_TX_HASH}${RESET} - ${GREEN}OK${RESET}"
sleep 10 # to be sure that the tx appeared in wallet, otherwise gettransaction will fail
waitfortransaction || exit
cleanwallettransactions || exit
log_print "Clean wallet result: ${CLEAN_WALLWET_TXS}"
else
log_print "Signed raw tx: ${SIGNED_RAW_TX}"
fi