-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6b5165f
Showing
3 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2018 Brian Lee | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# avian-wallet-groomer | ||
Collects small transactions in a QT wallet into larger ones. This tool has been updated for Avian, but should work on other coins using a BTC-forked QT wallet. | ||
|
||
## Requirements: | ||
|
||
This tool only works with Python 3. You will need to install the `bitcoinrpc` Python package. This can be done using `pip` by: | ||
|
||
`sudo pip3 install python-bitcoinrpc` | ||
|
||
You will also need to set up your QT wallet to start a RPC server, since this is how the tool interacts with the wallet. You can do so by editing your `avian.conf` file. Feel free to edit the user/pass/port. | ||
|
||
``` | ||
rpcuser=user | ||
rpcpassword=password | ||
rpcallowip=127.0.0.1 | ||
rpcport=7896 | ||
server=1 | ||
``` | ||
|
||
## Usage: | ||
|
||
First, you will need to unlock your wallet. You can do this in the Debug Console by typing: | ||
|
||
`walletpassphrase password 300` | ||
|
||
Replace `password` with your wallet password. `300` is the number of seconds the wallet should stay unlocked for; you will need to finish running the tool within that time (feel free to change it if you'd like). | ||
|
||
You should be able to simply run: | ||
|
||
`python groomer.py "http://user:[email protected]:7896"` | ||
|
||
(replace the user, password, and port if you've changed it from the `avian.conf` example above) | ||
|
||
## Optional Arguments | ||
|
||
Normally, there should be no need to use any of the optional arguments. If you're having trouble with the tool, you can run `python groomer.py -h` to get the help page: | ||
|
||
``` | ||
usage: groomer.py [-h] [-i MAX_AMT_INPUT] [-n MAX_NUM_TX] | ||
[-o MAX_AMT_PER_OUTPUT] [-f FEE] | ||
rpc_server | ||
This script generates transaction(s) to cleanup your wallet. It looks for the | ||
single addresses which have the most small confirmed payments made to them and | ||
merges all those payments, along with those for any addresses which are all | ||
tiny payments, to a single txout. It must connect to raven to inspect your | ||
wallet and to get fresh addresses to pay your coin to. | ||
positional arguments: | ||
rpc_server Wallet RPC server info. Example: | ||
http://user:[email protected]:7896 | ||
optional arguments: | ||
-h, --help show this help message and exit | ||
-i MAX_AMT_INPUT, --max_amt_input MAX_AMT_INPUT | ||
The maximum input amount of a single transaction to | ||
consolidate (default: 25 AVN) | ||
-n MAX_NUM_TX, --max_num_tx MAX_NUM_TX | ||
The maximum number of transactions to consolidate at | ||
once. Lower this if you are getting a tx-size error | ||
(default: 500) | ||
-o MAX_AMT_PER_OUTPUT, --max_amt_per_output MAX_AMT_PER_OUTPUT | ||
The maximum amount (in AVN) to send to a single output | ||
address (default: 10000 AVN) | ||
-f FEE, --fee FEE The amount of fees (in AVN) to use for the transaction | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#!/usr/bin/python | ||
# simple cleanup script, 2012-12-25 <[email protected]> | ||
# 2018: updated by brianmct | ||
# 2022: updated by cdonnachie | ||
import sys | ||
import operator | ||
from decimal import * | ||
from bitcoinrpc.authproxy import AuthServiceProxy | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser(description='This script generates transaction(s) to cleanup your wallet.\n' | ||
'It looks for the single addresses which have the most small confirmed payments made to them and merges\n' | ||
'all those payments, along with those for any addresses which are all tiny payments, to a single txout.\n' | ||
'It must connect to avian to inspect your wallet and to get fresh addresses to pay your coin to.') | ||
parser.add_argument('rpc_server', type=str, help='Wallet RPC server info. ' | ||
'Example: http://user:[email protected]:7896') | ||
parser.add_argument('-i', '--max_amt_input', type=float, default=25, | ||
help='The maximum input amount of a single transaction to consolidate (default: 25 AVN)') | ||
parser.add_argument('-n', '--max_num_tx', type=int, default=500, | ||
help='The maximum number of transactions to consolidate at once. Lower this if you are getting a tx-size error (default: 500)') | ||
parser.add_argument('-o', '--max_amt_per_output', type=float, default=10000, | ||
help='The maximum amount (in AVN) to send to a single output address (default: 10000 AVN)') | ||
parser.add_argument('-f', '--fee', type=float, default=0.001, | ||
help='The amount of fees (in AVN) to use for the transaction') | ||
|
||
args = parser.parse_args() | ||
|
||
try: | ||
b = AuthServiceProxy(args.rpc_server) | ||
b.getblockchaininfo() | ||
except: | ||
print("Couldn't connect to avian") | ||
exit(1) | ||
min_fee=Decimal(args.fee) | ||
|
||
# Loop until wallet is clean | ||
while True: | ||
#Add up the number of small txouts and amounts assigned to each address. | ||
coins=b.listunspent(1,99999999) | ||
scripts={} | ||
for coin in coins: | ||
script=coin['scriptPubKey'] | ||
if script not in scripts: | ||
scripts[script]=(0,Decimal(0),0) | ||
if (coin['amount']<Decimal(args.max_amt_input) and coin['amount']>=Decimal(0.01) and coin['confirmations']>100): | ||
scripts[script]=(scripts[script][0]+1,scripts[script][1]+coin['amount'],scripts[script][0]+1) | ||
else: | ||
scripts[script]=(scripts[script][0],scripts[script][1]+coin['amount'],scripts[script][0]+1) | ||
|
||
#which script has the largest number of well confirmed small but not dust outputs? | ||
most_overused = max(scripts.items(), key=operator.itemgetter(1))[0] | ||
|
||
#If the best we can do doesn't reduce the number of txouts or just moves dust, give up. | ||
if(scripts[most_overused][2]<3 or scripts[most_overused][1]<Decimal(0.01)): | ||
print("Wallet already clean.") | ||
exit(0) | ||
|
||
usescripts=set([most_overused]) | ||
|
||
#Also merge in scripts that are all dust, since they can't be spent without merging with something. | ||
for script in scripts.keys(): | ||
if scripts[script][1]<Decimal(0.00010000): | ||
usescripts.add(script) | ||
|
||
amt=Decimal(0) | ||
txouts=[] | ||
for coin in coins: | ||
if len(txouts) >= args.max_num_tx: | ||
break | ||
if coin['scriptPubKey'] in usescripts: | ||
amt+=coin['amount'] | ||
txout={} | ||
txout['txid']=coin['txid'] | ||
txout['vout']=coin['vout'] | ||
txouts.append(txout) | ||
print('Creating tx from %d inputs of total value %s:'%(len(txouts),amt)) | ||
for script in usescripts: | ||
print(' Script %s has %d txins and %s AVN value.'%(script,scripts[script][2],str(scripts[script][1]))) | ||
|
||
out={} | ||
na=amt-min_fee | ||
#One new output per max_amt_per_output AVN of value to avoid consolidating too much value in too few addresses. | ||
# But don't add an extra output if it would have less than args.max_amt_per_output AVN. | ||
while na>0: | ||
amount=min(Decimal(args.max_amt_per_output),na) | ||
if ((na-amount)<10): | ||
amount=na | ||
addr=b.getnewaddress('consolidate') | ||
if (Decimal(str(float(amount)))>0): | ||
if addr not in out: | ||
out[addr]=float(0) | ||
out[addr]+=float(amount) | ||
na-=Decimal(str(float(amount))) | ||
print('Paying %s AVN (%s fee) to:'%(sum([Decimal(str(out[k])) for k in out.keys()]),amt-sum([Decimal(str(out[k])) for k in out.keys()]))) | ||
for o in out.keys(): | ||
print(' %s %s'%(o,out[o])) | ||
|
||
txn=b.createrawtransaction(txouts,out) | ||
a = input('Sign the transaction? y/[n]: ') | ||
if a != 'y': | ||
exit(0) | ||
|
||
signed_txn=b.signrawtransaction(txn) | ||
#print(signed_txn) | ||
print('Bytes: %d Fee: %s'%(len(signed_txn['hex'])/2,amt-sum([Decimal(str(out[x])) for x in out.keys()]))) | ||
|
||
a = input('Send the transaction? y/[n]: ') | ||
if a != 'y': | ||
exit(0) | ||
|
||
txid = b.sendrawtransaction(signed_txn['hex']) | ||
print('Transaction sent! txid: %s\n' % txid) |