You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
6.1 KiB
150 lines
6.1 KiB
#! /usr/bin/env python |
|
from __future__ import absolute_import, print_function |
|
|
|
import datetime |
|
import os |
|
import time |
|
import abc |
|
from optparse import OptionParser |
|
|
|
from jmclient import (Maker, jm_single, get_network, load_program_config, get_log, |
|
SegwitWallet, sync_wallet, JMClientProtocolFactory, |
|
start_reactor) |
|
|
|
jlog = get_log() |
|
|
|
MAX_MIX_DEPTH = 5 |
|
|
|
# is a maker for the purposes of generating a yield from held |
|
# bitcoins |
|
class YieldGenerator(Maker): |
|
__metaclass__ = abc.ABCMeta |
|
statement_file = os.path.join('logs', 'yigen-statement.csv') |
|
|
|
def __init__(self, wallet): |
|
Maker.__init__(self, wallet) |
|
self.tx_unconfirm_timestamp = {} |
|
if not os.path.isfile(self.statement_file): |
|
self.log_statement( |
|
['timestamp', 'cj amount/satoshi', 'my input count', |
|
'my input value/satoshi', 'cjfee/satoshi', 'earned/satoshi', |
|
'confirm time/min', 'notes']) |
|
|
|
timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") |
|
self.log_statement([timestamp, '', '', '', '', '', '', 'Connected']) |
|
|
|
def log_statement(self, data): |
|
data = [str(d) for d in data] |
|
self.income_statement = open(self.statement_file, 'a') |
|
self.income_statement.write(','.join(data) + '\n') |
|
self.income_statement.close() |
|
|
|
@abc.abstractmethod |
|
def create_my_orders(self): |
|
"""Must generate a set of orders to be displayed |
|
according to the contents of the wallet + some algo. |
|
(Note: should be called "create_my_offers") |
|
""" |
|
|
|
@abc.abstractmethod |
|
def oid_to_order(self, cjorder, oid, amount): |
|
"""Must convert an order with an offer/order id |
|
into a set of utxos to fill the order. |
|
Also provides the output addresses for the Taker. |
|
""" |
|
|
|
@abc.abstractmethod |
|
def on_tx_unconfirmed(self, cjorder, txid, removed_utxos): |
|
"""Performs action on receipt of transaction into the |
|
mempool in the blockchain instance (e.g. announcing orders) |
|
""" |
|
|
|
@abc.abstractmethod |
|
def on_tx_confirmed(self, cjorder, confirmations, txid): |
|
"""Performs actions on receipt of 1st confirmation of |
|
a transaction into a block (e.g. announce orders) |
|
""" |
|
|
|
|
|
def ygmain(ygclass, txfee=1000, cjfee_a=200, cjfee_r=0.002, ordertype='swreloffer', |
|
nickserv_password='', minsize=100000, gaplimit=6): |
|
import sys |
|
|
|
parser = OptionParser(usage='usage: %prog [options] [wallet file]') |
|
parser.add_option('-o', '--ordertype', action='store', type='string', |
|
dest='ordertype', default=ordertype, |
|
help='type of order; can be either reloffer or absoffer') |
|
parser.add_option('-t', '--txfee', action='store', type='int', |
|
dest='txfee', default=txfee, |
|
help='minimum miner fee in satoshis') |
|
parser.add_option('-c', '--cjfee', action='store', type='string', |
|
dest='cjfee', default='', |
|
help='requested coinjoin fee in satoshis or proportion') |
|
parser.add_option('-p', '--password', action='store', type='string', |
|
dest='password', default=nickserv_password, |
|
help='irc nickserv password') |
|
parser.add_option('-s', '--minsize', action='store', type='int', |
|
dest='minsize', default=minsize, |
|
help='minimum coinjoin size in satoshis') |
|
parser.add_option('-g', '--gap-limit', action='store', type="int", |
|
dest='gaplimit', default=gaplimit, |
|
help='gap limit for wallet, default='+str(gaplimit)) |
|
parser.add_option('--fast', |
|
action='store_true', |
|
dest='fastsync', |
|
default=False, |
|
help=('choose to do fast wallet sync, only for Core and ' |
|
'only for previously synced wallet')) |
|
(options, args) = parser.parse_args() |
|
if len(args) < 1: |
|
parser.error('Needs a wallet') |
|
sys.exit(0) |
|
wallet_name = args[0] |
|
ordertype = options.ordertype |
|
txfee = options.txfee |
|
if ordertype == 'swreloffer': |
|
if options.cjfee != '': |
|
cjfee_r = options.cjfee |
|
# minimum size is such that you always net profit at least 20% |
|
#of the miner fee |
|
minsize = max(int(1.2 * txfee / float(cjfee_r)), options.minsize) |
|
elif ordertype == 'swabsoffer': |
|
if options.cjfee != '': |
|
cjfee_a = int(options.cjfee) |
|
minsize = options.minsize |
|
else: |
|
parser.error('You specified an incorrect order type which ' +\ |
|
'can be either reloffer or absoffer') |
|
sys.exit(0) |
|
nickserv_password = options.password |
|
|
|
load_program_config() |
|
if not os.path.exists(os.path.join('wallets', wallet_name)): |
|
wallet = SegwitWallet(wallet_name, None, max_mix_depth=MAX_MIX_DEPTH, |
|
gaplimit=options.gaplimit) |
|
else: |
|
while True: |
|
try: |
|
pwd = get_password("Enter wallet decryption passphrase: ") |
|
wallet = SegwitWallet(wallet_name, pwd, |
|
max_mix_depth=MAX_MIX_DEPTH, |
|
gaplimit=options.gaplimit) |
|
except WalletError: |
|
print("Wrong password, try again.") |
|
continue |
|
except Exception as e: |
|
print("Failed to load wallet, error message: " + repr(e)) |
|
sys.exit(0) |
|
break |
|
sync_wallet(wallet, fast=options.fastsync) |
|
|
|
maker = ygclass(wallet, [options.txfee, cjfee_a, cjfee_r, |
|
options.ordertype, options.minsize]) |
|
jlog.info('starting yield generator') |
|
clientfactory = JMClientProtocolFactory(maker, proto_type="MAKER") |
|
nodaemon = jm_single().config.getint("DAEMON", "no_daemon") |
|
daemon = True if nodaemon == 1 else False |
|
start_reactor(jm_single().config.get("DAEMON", "daemon_host"), |
|
jm_single().config.getint("DAEMON", "daemon_port"), |
|
clientfactory, daemon=daemon) |
|
|
|
|