class Ngccc(apigen.Definition): """Next-Generation Colored Coin Client interface.""" def __init__(self, wallet=None, testnet=False): # sanitize inputs testnet = sanitize.flag(testnet) if not wallet: wallet = "%s.wallet" % ("testnet" if testnet else "mainnet") self.wallet = PersistentWallet(wallet, testnet) self.model_is_initialized = False def __getattribute__(self, name): if name in ['controller', 'model']: if not self.model_is_initialized: self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.model) slef.model_is_initialized = True return object.__getattribute__(self, name) @apigen.command() def setconfigval(self, key, value): # FIXME behaviour ok? """Sets a value in the configuration. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) value = sanitize.cfgvalue(value) kpath = key.split('.') value = json.loads(value) # traverse the path until we get to the value we need to set if len(kpath) > 1: branch = self.wallet.wallet_config[kpath[0]] cdict = branch for k in kpath[1:-1]: cdict = cdict[k] cdict[kpath[-1]] = value value = branch if kpath[0] in self.wallet.wallet_config: self.wallet.wallet_config[kpath[0]] = value else: raise KeyNotFound(key) @apigen.command() def getconfigval(self, key): """Returns the value for a given key in the config. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) if not key: raise KeyNotFound(key) keys = key.split('.') config = self.wallet.wallet_config # traverse the path until we get the value for key in keys: config = config[key] return _print(config) @apigen.command() def dumpconfig(self): """Returns a dump of the current configuration.""" dict_config = dict(self.wallet.wallet_config.iteritems()) return _print(dict_config) @apigen.command() def importconfig(self, path): # FIXME what about subkeys and removed keys? """Import JSON config.""" with open(path, 'r') as fp: config = json.loads(fp.read()) wallet_config = self.wallet.wallet_config for k in config: wallet_config[k] = config[k] @apigen.command() def issueasset(self, moniker, quantity, unit="100000000", scheme="epobc"): """ Issue <quantity> of asset with name <moniker> and <unit> atoms, based on <scheme (epobc|obc)>.""" # sanitize inputs moniker = sanitize.moniker(moniker) quantity = sanitize.quantity(quantity) unit = sanitize.unit(unit) scheme = sanitize.scheme(scheme) self.controller.issue_coins(moniker, scheme, quantity, unit) return self.getasset(moniker) @apigen.command() def addassetjson(self, data): """Add a json asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs data = sanitize.jsonasset(data) self.controller.add_asset_definition(data) return self.getasset(data['monikers'][0]) @apigen.command() def addasset(self, moniker, color_description, unit=100000000): """Add a asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs moniker = sanitize.moniker(moniker) color_description = sanitize.colordesc(color_description) unit = sanitize.unit(unit) self.controller.add_asset_definition({ "monikers": [moniker], "color_set": [color_description], "unit" : unit }) return self.getasset(moniker) @apigen.command() def getasset(self, moniker): """Get the asset associated with the moniker.""" return _print(sanitize.asset(self.model, moniker).get_data()) @apigen.command() def listassets(self): """Lists all assets/colors registered.""" assets = self.controller.get_all_assets() return _print(map(lambda asset: asset.get_data(), assets)) def _getbalance(self, asset, unconfirmed, available): if unconfirmed: balance = self.controller.get_unconfirmed_balance(asset) elif available: balance = self.controller.get_available_balance(asset) else: balance = self.controller.get_total_balance(asset) return (asset.get_monikers()[0], asset.format_value(balance)) @apigen.command() def getbalance(self, moniker, unconfirmed=False, available=False): """Returns the balance for a particular asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) balance = dict([self._getbalance(asset, unconfirmed, available)]) return _print(balance) @apigen.command() def getbalances(self, unconfirmed=False, available=False): """Returns the balances for all assets/colors.""" # sanitize inputs unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) assets = self.controller.get_all_assets() func = lambda asset: self._getbalance(asset, unconfirmed, available) balances = dict(map(func, assets)) return _print(balances) @apigen.command() def newaddress(self, moniker): """Creates a new coloraddress for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecord = self.controller.get_new_address(asset) coloraddress = addressrecord.get_color_address() return _print(coloraddress) @apigen.command() def listaddresses(self, moniker): """Lists all addresses for a given asset""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print([ao.get_color_address() for ao in addressrecords]) @apigen.command() def send(self, moniker, coloraddress, amount): """Send <coloraddress> given <amount> of an asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) amount = sanitize.assetamount(asset, amount) txid = self.controller.send_coins(asset, [coloraddress], [amount]) return _print(txid) @apigen.command() def sendmanyjson(self, data): """Send amounts given in json fromatted data. Format [{'moniker':"val",'amount':"val",'coloraddress':"val"}] All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanyjson(self.model, data) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def sendmanycsv(self, path): """Send amounts in csv file with format 'moniker,coloraddress,amount'. All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanycsv(self.model, path) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def scan(self): """Update the database of transactions.""" sleep(5) self.controller.scan_utxos() @apigen.command() def fullrescan(self): """Rebuild database of wallet transactions.""" self.controller.full_rescan() @apigen.command() def history(self, moniker): """Show the history of transactions for given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) return _print(self.controller.get_history(asset)) @apigen.command() def received(self, moniker): """Returns total received amount for each coloraddress of a given asset. """ # sanitize inputs asset = sanitize.asset(self.model, moniker) received = {} def reformat(data): coloraddress = data['color_address'] colorvalue = data['value'].get_value() return (coloraddress, asset.format_value(colorvalue)) data = self.controller.get_received_by_address(asset) return _print(dict(map(reformat, data))) @apigen.command() def coinlog(self): """Returns the coin transaction log for this wallet.""" log = defaultdict(list) for coin in self.controller.get_coinlog(): moniker = coin.asset.get_monikers()[0] moniker = 'bitcoin' if moniker == '' else moniker log[moniker].append({ 'address' : coin.get_address(), 'txid' : coin.txhash, 'out' : coin.outindex, 'colorvalue' : coin.colorvalues[0].get_value(), 'value' : coin.value, 'confirmed' : coin.is_confirmed(), 'spendingtxs' : coin.get_spending_txs(), }) return _print(log) @apigen.command() def dumpprivkey(self, moniker, coloraddress): """Private key for a given coloraddress.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) wam = self.model.get_address_manager() for addressrecord in wam.get_all_addresses(): if coloraddress == addressrecord.get_color_address(): return _print(addressrecord.get_private_key()) raise AddressNotFound(coloraddress) @apigen.command() def dumpprivkeys(self, moniker): """Lists all private keys for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print(map(lambda ar: ar.get_private_key(), addressrecords)) def _init_p2ptrade(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm(config, 'http://p2ptrade.btx.udoidio.info/messages') return EAgent(ewctrl, config, comm) def _p2ptrade_make_offer(self, we_sell, moniker, value, price, wait): # sanitize inputs asset = sanitize.asset(self.model, moniker) bitcoin = sanitize.asset(self.model, 'bitcoin') value = sanitize.assetamount(asset, value) price = sanitize.assetamount(bitcoin, price) wait = sanitize.integer(wait) total = int(Decimal(value)/Decimal(asset.unit)*Decimal(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} agent = self._init_p2ptrade() if we_sell: agent.register_my_offer(MyEOffer(None, sell_side, buy_side)) else: agent.register_my_offer(MyEOffer(None, buy_side, sell_side)) self._p2ptrade_wait(agent, wait) def _p2ptrade_wait(self, agent, wait): if wait and wait > 0: for _ in xrange(wait): agent.update() sleep(1) else: for _ in xrange(4*6): agent.update() sleep(0.25) @apigen.command() def p2porders(self, moniker="", sellonly=False, buyonly=False): """Show peer to peer trade orders""" # sanitize inputs sellonly = sanitize.flag(sellonly) buyonly = sanitize.flag(buyonly) asset = None if moniker and moniker != 'bitcoin': asset = sanitize.asset(self.model, moniker) # get offers agent = self._init_p2ptrade() agent.update() offers = agent.their_offers.values() offers = map(lambda offer: offer.get_data(), offers) # filter asset if given if asset: descs = asset.get_color_set().color_desc_list def func(offer): return (offer["A"]["color_spec"] in descs or offer["B"]["color_spec"] in descs) offers = filter(func, offers) # filter sellonly if given if sellonly: offers = filter(lambda o: o["A"]["color_spec"] != "", offers) # filter buyonly if given if buyonly: offers = filter(lambda o: o["A"]["color_spec"] == "", offers) return _print(offers) @apigen.command() def p2psell(self, moniker, assetamount, btcprice, wait=30): """Sell <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(True, moniker, assetamount, btcprice, wait) @apigen.command() def p2pbuy(self, moniker, assetamount, btcprice, wait=30): """Buy <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(False, moniker, assetamount, btcprice, wait)
class Wallet(object): thread_comm = None def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self.wallet.get_model().get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if asset: return asset else: raise Exception("asset not found") def get_asset_definition_by_color_set(self, color_set): adm = self.wallet.get_model().get_asset_definition_manager() for asset in adm.get_all_assets(): if color_set in asset.get_color_set().get_data(): return asset raise Exception("asset not found") def add_asset(self, params): self.controller.add_asset_definition({ "monikers": [params['moniker']], "color_set": [params['color_desc']], "unit": params['unit'] }) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_asset(self): return self.wallet.wallet_config['asset_definitions'] def issue(self, params): self.controller.issue_coins( params['moniker'], params['coloring_scheme'], params['units'], params['atoms']) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_monikers(self): monikers = [asset.get_monikers()[0] for asset in self.model.get_asset_definition_manager().get_all_assets()] monikers.remove('bitcoin') monikers = ['bitcoin'] + monikers return monikers def get_balance(self, color): return self.controller.get_balance(self.get_asset_definition(color)) def get_all_addresses(self, color): return [addr.get_color_address() for addr in self.controller.get_all_addresses(self.get_asset_definition(color))] def get_address_balance(self, color): asset = self.get_asset_definition(color) return self.controller.get_address_balance(asset) def get_some_address(self, color): wam = self.model.get_address_manager() cs = self.get_asset_definition(color).get_color_set() ar = wam.get_some_address(cs) return ar.get_color_address() def get_new_address(self, color): return self.controller. \ get_new_address(self.get_asset_definition(color)).get_color_address() def scan(self): self.controller.scan_utxos() def send_coins(self, items): if isinstance(items, dict): items = [items] for item in items: self.controller.send_coins( item['asset'] if 'asset' in item \ else self.get_asset_definition(item['moniker']), [item['address']], [item['value']]) def p2ptrade_init(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm( config, 'http://p2ptrade.btx.udoidio.info/messages') self.thread_comm = ThreadedComm(comm) self.p2p_agent = EAgent(ewctrl, config, self.thread_comm) self.thread_comm.start() def p2ptrade_stop(self): if self.thread_comm is not None: self.thread_comm.stop() def p2ptrade_make_offer(self, we_sell, params): asset = self.get_asset_definition(params['moniker']) value = asset.parse_value(params['value']) bitcoin = self.get_asset_definition('bitcoin') price = bitcoin.parse_value(params['price']) total = int(float(value)/float(asset.unit)*float(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} if we_sell: return MyEOffer(None, sell_side, buy_side) else: return MyEOffer(None, buy_side, sell_side) def p2ptrade_make_mirror_offer(self, offer): data = offer.get_data() return MyEOffer(None, data['B'], data['A'], False)
class Wallet(object): thread_comm = None def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parser.add_argument("--testnet", action='store_true') parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path'), parsed_args.get('testnet')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) self.async_utxo_fetcher = AsyncUTXOFetcher( self.model, self.wallet.wallet_config.get('utxo_fetcher', {})) def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self.wallet.get_model().get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if asset: return asset else: raise Exception("asset not found") def get_asset_definition_by_color_set(self, color_set): adm = self.wallet.get_model().get_asset_definition_manager() for asset in adm.get_all_assets(): if color_set in asset.get_color_set().get_data(): return asset raise Exception("asset not found") def add_asset(self, params): self.controller.add_asset_definition({ "monikers": [params['moniker']], "color_set": [params['color_desc']], "unit": params['unit'] }) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_asset(self): return self.wallet.wallet_config['asset_definitions'] def issue(self, params): self.controller.issue_coins( params['moniker'], params['coloring_scheme'], params['units'], params['atoms']) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_monikers(self): monikers = [asset.get_monikers()[0] for asset in self.model.get_asset_definition_manager().get_all_assets()] monikers.remove('bitcoin') monikers = ['bitcoin'] + monikers return monikers def get_available_balance(self, color): return self.controller.get_available_balance( self.get_asset_definition(color)) def get_total_balance(self, color): return self.controller.get_total_balance( self.get_asset_definition(color)) def get_unconfirmed_balance(self, color): return self.controller.get_unconfirmed_balance( self.get_asset_definition(color)) def get_all_addresses(self, color): return [addr.get_color_address() for addr in self.controller.get_all_addresses(self.get_asset_definition(color))] def get_received_by_address(self, color): asset = self.get_asset_definition(color) return self.controller.get_received_by_address(asset) def get_some_address(self, color): wam = self.model.get_address_manager() cs = self.get_asset_definition(color).get_color_set() ar = wam.get_some_address(cs) return ar.get_color_address() def get_new_address(self, color): return self.controller. \ get_new_address(self.get_asset_definition(color)).get_color_address() def scan(self): self.controller.scan_utxos() def send_coins(self, items): if isinstance(items, dict): items = [items] for item in items: self.controller.send_coins( item['asset'] if 'asset' in item \ else self.get_asset_definition(item['moniker']), [item['address']], [item['value']]) def p2ptrade_init(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm( config, 'http://p2ptrade.btx.udoidio.info/messages') self.thread_comm = ThreadedComm(comm) self.p2p_agent = EAgent(ewctrl, config, self.thread_comm) self.thread_comm.start() def p2ptrade_stop(self): if self.thread_comm is not None: self.thread_comm.stop() def p2ptrade_make_offer(self, we_sell, params): asset = self.get_asset_definition(params['moniker']) value = asset.parse_value(params['value']) bitcoin = self.get_asset_definition('bitcoin') price = bitcoin.parse_value(params['price']) total = int(float(value)/float(asset.unit)*float(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} if we_sell: return MyEOffer(None, sell_side, buy_side) else: return MyEOffer(None, buy_side, sell_side) def p2ptrade_make_mirror_offer(self, offer): data = offer.get_data() return MyEOffer(None, data['B'], data['A'], False) def stop_all(self): self.async_utxo_fetcher.stop() self.p2ptrade_stop() if hasattr(self.model.txdb, 'vbs'): self.model.txdb.vbs.stop()
class Ngccc(apigen.Definition): """Next-Generation Colored Coin Client interface.""" def __init__(self, wallet=None, testnet=False): # sanitize inputs testnet = sanitize.flag(testnet) if not wallet: wallet = "%s.wallet" % ("testnet" if testnet else "mainnet") self.wallet = PersistentWallet(wallet, testnet) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.model) @apigen.command() def setconfigval(self, key, value): # FIXME behaviour ok? """Sets a value in the configuration. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) value = sanitize.cfgvalue(value) kpath = key.split('.') value = json.loads(value) # traverse the path until we get to the value we need to set if len(kpath) > 1: branch = self.wallet.wallet_config[kpath[0]] cdict = branch for k in kpath[1:-1]: cdict = cdict[k] cdict[kpath[-1]] = value value = branch if kpath[0] in self.wallet.wallet_config: self.wallet.wallet_config[kpath[0]] = value else: raise KeyNotFound(key) @apigen.command() def getconfigval(self, key): """Returns the value for a given key in the config. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) if not key: raise KeyNotFound(key) keys = key.split('.') config = self.wallet.wallet_config # traverse the path until we get the value for key in keys: config = config[key] return _print(config) @apigen.command() def dumpconfig(self): """Returns a dump of the current configuration.""" dict_config = dict(self.wallet.wallet_config.iteritems()) return _print(dict_config) @apigen.command() def importconfig(self, path): # FIXME what about subkeys and removed keys? """Import JSON config.""" with open(path, 'r') as fp: config = json.loads(fp.read()) wallet_config = self.wallet.wallet_config for k in config: wallet_config[k] = config[k] @apigen.command() def issueasset(self, moniker, quantity, unit="100000000", scheme="epobc"): """ Issue <quantity> of asset with name <moniker> and <unit> atoms, based on <scheme (epobc|obc)>.""" # sanitize inputs moniker = sanitize.moniker(moniker) quantity = sanitize.quantity(quantity) unit = sanitize.unit(unit) scheme = sanitize.scheme(scheme) self.controller.issue_coins(moniker, scheme, quantity, unit) return self.getasset(moniker) @apigen.command() def addassetjson(self, data): """Add a json asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs data = sanitize.jsonasset(data) self.controller.add_asset_definition(data) return self.getasset(data['monikers'][0]) @apigen.command() def addasset(self, moniker, color_description, unit=100000000): """Add a asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs moniker = sanitize.moniker(moniker) color_description = sanitize.colordesc(color_description) unit = sanitize.unit(unit) self.controller.add_asset_definition({ "monikers": [moniker], "color_set": [color_description], "unit": unit }) return self.getasset(moniker) @apigen.command() def getasset(self, moniker): """Get the asset associated with the moniker.""" return _print(sanitize.asset(self.model, moniker).get_data()) @apigen.command() def listassets(self): """Lists all assets/colors registered.""" assets = self.controller.get_all_assets() return _print(map(lambda asset: asset.get_data(), assets)) def _getbalance(self, asset, unconfirmed, available): if unconfirmed: balance = self.controller.get_unconfirmed_balance(asset) elif available: balance = self.controller.get_available_balance(asset) else: balance = self.controller.get_total_balance(asset) return (asset.get_monikers()[0], asset.format_value(balance)) @apigen.command() def getbalance(self, moniker, unconfirmed=False, available=False): """Returns the balance for a particular asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) balance = dict([self._getbalance(asset, unconfirmed, available)]) return _print(balance) @apigen.command() def getbalances(self, unconfirmed=False, available=False): """Returns the balances for all assets/colors.""" # sanitize inputs unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) assets = self.controller.get_all_assets() func = lambda asset: self._getbalance(asset, unconfirmed, available) balances = dict(map(func, assets)) return _print(balances) @apigen.command() def newaddress(self, moniker): """Creates a new coloraddress for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecord = self.controller.get_new_address(asset) coloraddress = addressrecord.get_color_address() return _print(coloraddress) @apigen.command() def listaddresses(self, moniker): """Lists all addresses for a given asset""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print([ao.get_color_address() for ao in addressrecords]) @apigen.command() def send(self, moniker, coloraddress, amount): """Send <coloraddress> given <amount> of an asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) amount = sanitize.assetamount(asset, amount) txid = self.controller.send_coins(asset, [coloraddress], [amount]) return _print(txid) @apigen.command() def sendmanyjson(self, data): """Send amounts given in json fromatted data. Format [{'moniker':"val",'amount':"val",'coloraddress':"val"}] All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanyjson(self.model, data) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def sendmanycsv(self, path): """Send amounts in csv file with format 'moniker,coloraddress,amount'. All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanycsv(self.model, path) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def scan(self): """Update the database of transactions.""" sleep(5) self.controller.scan_utxos() @apigen.command() def fullrescan(self): """Rebuild database of wallet transactions.""" self.controller.full_rescan() @apigen.command() def history(self, moniker): """Show the history of transactions for given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) return _print(self.controller.get_history(asset)) @apigen.command() def received(self, moniker): """Returns total received amount for each coloraddress of a given asset. """ # sanitize inputs asset = sanitize.asset(self.model, moniker) received = {} def reformat(data): coloraddress = data['color_address'] colorvalue = data['value'].get_value() return (coloraddress, asset.format_value(colorvalue)) data = self.controller.get_received_by_address(asset) return _print(dict(map(reformat, data))) @apigen.command() def coinlog(self): """Returns the coin transaction log for this wallet.""" log = defaultdict(list) for coin in self.controller.get_coinlog(): moniker = coin.asset.get_monikers()[0] moniker = 'bitcoin' if moniker == '' else moniker log[moniker].append({ 'address': coin.get_address(), 'txid': coin.txhash, 'out': coin.outindex, 'colorvalue': coin.colorvalues[0].get_value(), 'value': coin.value, 'confirmed': coin.is_confirmed(), 'spendingtxs': coin.get_spending_txs(), }) return _print(log) @apigen.command() def dumpprivkey(self, moniker, coloraddress): """Private key for a given coloraddress.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) wam = self.model.get_address_manager() for addressrecord in wam.get_all_addresses(): if coloraddress == addressrecord.get_color_address(): return _print(addressrecord.get_private_key()) raise AddressNotFound(coloraddress) @apigen.command() def dumpprivkeys(self, moniker): """Lists all private keys for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print(map(lambda ar: ar.get_private_key(), addressrecords)) def _init_p2ptrade(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm(config, 'http://p2ptrade.btx.udoidio.info/messages') return EAgent(ewctrl, config, comm) def _p2ptrade_make_offer(self, we_sell, moniker, value, price, wait): # sanitize inputs asset = sanitize.asset(self.model, moniker) bitcoin = sanitize.asset(self.model, 'bitcoin') value = sanitize.assetamount(asset, value) price = sanitize.assetamount(bitcoin, price) wait = sanitize.integer(wait) total = int(Decimal(value) / Decimal(asset.unit) * Decimal(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} agent = self._init_p2ptrade() if we_sell: agent.register_my_offer(MyEOffer(None, sell_side, buy_side)) else: agent.register_my_offer(MyEOffer(None, buy_side, sell_side)) self._p2ptrade_wait(agent, wait) def _p2ptrade_wait(self, agent, wait): if wait and wait > 0: for _ in xrange(wait): agent.update() sleep(1) else: for _ in xrange(4 * 6): agent.update() sleep(0.25) @apigen.command() def p2porders(self, moniker="", sellonly=False, buyonly=False): """Show peer to peer trade orders""" # sanitize inputs sellonly = sanitize.flag(sellonly) buyonly = sanitize.flag(buyonly) asset = None if moniker and moniker != 'bitcoin': asset = sanitize.asset(self.model, moniker) # get offers agent = self._init_p2ptrade() agent.update() offers = agent.their_offers.values() offers = map(lambda offer: offer.get_data(), offers) # filter asset if given if asset: descs = asset.get_color_set().color_desc_list def func(offer): return (offer["A"]["color_spec"] in descs or offer["B"]["color_spec"] in descs) offers = filter(func, offers) # filter sellonly if given if sellonly: offers = filter(lambda o: o["A"]["color_spec"] != "", offers) # filter buyonly if given if buyonly: offers = filter(lambda o: o["A"]["color_spec"] == "", offers) return _print(offers) @apigen.command() def p2psell(self, moniker, assetamount, btcprice, wait=30): """Sell <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(True, moniker, assetamount, btcprice, wait) @apigen.command() def p2pbuy(self, moniker, assetamount, btcprice, wait=30): """Buy <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(False, moniker, assetamount, btcprice, wait)
class TestWalletController(unittest.TestCase): def setUp(self): self.path = ":memory:" self.config = { 'dw_master_key': 'test', 'testnet': True, 'ccc': { 'colordb_path': self.path }, 'bip0032': False } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, ['']) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c' self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7' script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD('test') def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = 'test' self.wc.issue_coins(self.moniker, 'obc', 10000, 1) self.asset = self.model.get_asset_definition_manager( ).get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager( ).get_asset_by_moniker('bitcoin') self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash) def test_issue(self): self.assertRaises(InvalidColorDefinitionError, self.wc.issue_coins, self.moniker, 'nonexistent', 10000, 1) item = self.wc.get_history(self.asset)[0] self.assertEqual(item['action'], 'issued') self.assertEqual(item['value'], 10000) self.wc.scan_utxos() item = self.wc.get_history(self.asset)[0] self.assertEqual(item['action'], 'issued') self.assertEqual(item['value'], 10000) def test_new_address(self): addr = self.wc.get_new_address(self.asset) addrs = self.wc.get_all_addresses(self.asset) self.assertEqual(len(addr.get_address()), 34) self.assertTrue(addr in addrs) for d in self.wc.get_received_by_address(self.asset): if d['address'] == addr.get_address(): self.assertEqual(d['value'], 0) def test_get_all_assets(self): self.assertTrue(self.asset in self.wc.get_all_assets()) def test_get_balance(self): self.assertEqual(self.wc.get_total_balance(self.asset), 10000) def test_add_asset(self): moniker = 'addtest' params = { "monikers": [moniker], "color_set": ['obc:aaaaaaaaaaaaaaaaa:0:0'], "unit": 1 } self.wc.add_asset_definition(params) asset = self.model.get_asset_definition_manager().get_asset_by_moniker( moniker) self.assertEqual(self.wc.get_total_balance(asset), 0) self.assertEqual(self.wc.get_history(asset), []) def test_send(self): addr1 = self.wc.get_new_address(self.asset) addr2 = self.wc.get_new_address(self.asset) color_addrs = [addr1.get_color_address(), addr2.get_color_address()] self.wc.send_coins(self.asset, color_addrs, [1000, 2000]) self.assertRaises(AssetMismatchError, self.wc.send_coins, self.basset, color_addrs, [1000, 2000])
class TestWalletController(unittest.TestCase): def setUp(self): self.path = ":memory:" self.config = {"dw_master_key": "test", "testnet": True, "ccc": {"colordb_path": self.path}, "bip0032": False} self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, [""]) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = "00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c" self.txhash = "4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7" script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format(self.baddress.rawPubkey().encode("hex")) ).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format(self.baddress.rawPubkey().encode("hex")) ).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD("test") def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = "test" self.wc.issue_coins(self.moniker, "obc", 10000, 1) self.asset = self.model.get_asset_definition_manager().get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager().get_asset_by_moniker("bitcoin") self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash) def test_issue(self): self.assertRaises(InvalidColorDefinitionError, self.wc.issue_coins, self.moniker, "nonexistent", 10000, 1) item = self.wc.get_history(self.asset)[0] self.assertEqual(item["action"], "issued") self.assertEqual(item["value"], 10000) self.wc.scan_utxos() item = self.wc.get_history(self.asset)[0] self.assertEqual(item["action"], "issued") self.assertEqual(item["value"], 10000) def test_new_address(self): addr = self.wc.get_new_address(self.asset) addrs = self.wc.get_all_addresses(self.asset) self.assertEqual(len(addr.get_address()), 34) self.assertTrue(addr in addrs) for d in self.wc.get_address_balance(self.asset): if d["address"] == addr.get_address(): self.assertEqual(d["value"], 0) def test_get_all_assets(self): self.assertTrue(self.asset in self.wc.get_all_assets()) def test_get_balance(self): self.assertEqual(self.wc.get_total_balance(self.asset), 10000) def test_add_asset(self): moniker = "addtest" params = {"monikers": [moniker], "color_set": ["obc:aaaaaaaaaaaaaaaaa:0:0"], "unit": 1} self.wc.add_asset_definition(params) asset = self.model.get_asset_definition_manager().get_asset_by_moniker(moniker) self.assertEqual(self.wc.get_total_balance(asset), 0) self.assertEqual(self.wc.get_history(asset), []) def test_send(self): addr1 = self.wc.get_new_address(self.asset) addr2 = self.wc.get_new_address(self.asset) color_addrs = [addr1.get_color_address(), addr2.get_color_address()] self.wc.send_coins(self.asset, color_addrs, [1000, 2000]) self.assertRaises(AssetMismatchError, self.wc.send_coins, self.basset, color_addrs, [1000, 2000])
class Wallet(object): thread_comm = None def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parser.add_argument("--testnet", action='store_true') parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path'), parsed_args.get('testnet')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) self.async_utxo_fetcher = AsyncUTXOFetcher( self.model, self.wallet.wallet_config.get('utxo_fetcher', {})) self.update_connected_thread = TimedAsyncTask(self.update_connected, 2.5) self.update_connected_thread.start() self.update_connected() def connected(self): return self.is_connected def update_connected(self): try: for moniker in self.get_all_monikers(): asset = self.get_asset_definition(moniker) address = self.get_some_address(asset) total_balance = self.get_total_balance(asset) self.is_connected = self.async_utxo_fetcher.interface.connected() except: raise self.is_connected = False def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self.wallet.get_model().get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if asset: return asset else: raise Exception("Asset '%s' not found!" % moniker) def get_asset_definition_by_color_set(self, color_set): adm = self.wallet.get_model().get_asset_definition_manager() for asset in adm.get_all_assets(): if color_set in asset.get_color_set().get_data(): return asset raise Exception("Asset not found!") def add_asset(self, params): self.controller.add_asset_definition({ "monikers": [params['moniker']], "color_set": [params['color_desc']], "unit": params['unit'] }) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_asset(self): return self.wallet.wallet_config['asset_definitions'] def issue(self, params): self.controller.issue_coins( params['moniker'], params['coloring_scheme'], params['units'], params['atoms']) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_monikers(self): monikers = [asset.get_monikers()[0] for asset in self.model.get_asset_definition_manager().get_all_assets()] monikers.remove('bitcoin') monikers = ['bitcoin'] + monikers return monikers def get_available_balance(self, color): return self.controller.get_available_balance( self.get_asset_definition(color)) def get_total_balance(self, color): return self.controller.get_total_balance( self.get_asset_definition(color)) def get_unconfirmed_balance(self, color): return self.controller.get_unconfirmed_balance( self.get_asset_definition(color)) def get_all_addresses(self, color): return [addr.get_color_address() for addr in self.controller.get_all_addresses(self.get_asset_definition(color))] def get_received_by_address(self, color): asset = self.get_asset_definition(color) return self.controller.get_received_by_address(asset) def get_some_address(self, color): wam = self.model.get_address_manager() cs = self.get_asset_definition(color).get_color_set() ar = wam.get_some_address(cs) return ar.get_color_address() def get_new_address(self, color): return self.controller. \ get_new_address(self.get_asset_definition(color)).get_color_address() def scan(self): self.controller.scan_utxos() def send_coins(self, items): if isinstance(items, dict): items = [items] for item in items: self.controller.send_coins( item['asset'] if 'asset' in item \ else self.get_asset_definition(item['moniker']), [item['address']], [item['value']]) def p2ptrade_init(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} self.thread_comm = ThreadedComm( config, 'http://p2ptrade.btx.udoidio.info/messages' ) self.p2p_agent = EAgent(ewctrl, config, self.thread_comm) self.thread_comm.start() def p2ptrade_stop(self): if self.thread_comm is not None: self.thread_comm.stop() def p2ptrade_make_offer(self, we_sell, params): asset = self.get_asset_definition(params['moniker']) value = asset.parse_value(params['value']) bitcoin = self.get_asset_definition('bitcoin') price = bitcoin.parse_value(params['price']) total = int(Decimal(value)/Decimal(asset.unit)*Decimal(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} if we_sell: return MyEOffer(None, sell_side, buy_side) else: return MyEOffer(None, buy_side, sell_side) def p2ptrade_make_mirror_offer(self, offer): data = offer.get_data() return MyEOffer(None, data['B'], data['A']) def stop_all(self): self.update_connected_thread.stop() self.update_connected_thread.join() self.async_utxo_fetcher.stop() self.p2ptrade_stop() if hasattr(self.model.txdb, 'vbs'): self.model.txdb.vbs.stop()