def _from_json_data_object(self, data): self._botid = int(data.get('id', 0) or 0) addresses = data.get('addresses', {}) or {} self._addresses_to_add = [ NetworkAddress.from_json(address) for address in addresses.get('add', []) or [] ] self._addresses_to_remove = [ NetworkAddress.from_json(address) for address in addresses.get('remove', []) or [] ] names = data.get('names', {}) or {} self._names_to_add = [ BotName.from_json(name) for name in names.get('add', []) or [] ] self._names_to_remove = [ BotName.from_json(name) for name in names.get('remove', []) or [] ] self._number_of_months = int(data.get('nrofmonths', 0) or 0) if 'txfee' in data: self._transaction_fee = Currency.from_json(data['txfee']) else: self._transaction_fee = None self._coin_inputs = [ CoinInput.from_json(ci) for ci in data.get('coininputs', []) or [] ] if 'refundcoinoutput' in data: self._refund_coin_output = CoinOutput.from_json( data['refundcoinoutput']) else: self._refund_coin_output = None self._signature = ED25519Signature.from_json( data.get('signature', None) or None)
def fund(self, amount, source=None): """ Fund the specified amount with the available outputs of this wallet's balance. """ # collect addresses and multisig addresses addresses = set() refund = None if source == None: for co in self.outputs_available: addresses.add(co.condition.unlockhash.__str__()) for co in self.outputs_unconfirmed_available: addresses.add(co.condition.unlockhash.__str__()) else: # if only one address is given, transform it into an acceptable list if not isinstance(source, list) and not jsobj.is_js_arr(source): if isinstance(source, str): source = UnlockHash.from_json(source) elif not isinstance(source, UnlockHash): raise TypeError( "cannot add source address from type {}".format( type(source))) source = [source] # add one or multiple personal/multisig addresses for value in source: if isinstance(value, str): value = UnlockHash.from_json(value) elif not isinstance(value, UnlockHash): raise TypeError( "cannot add source address from type {}".format( type(value))) elif value.uhtype.__eq__(UnlockHashType.PUBLIC_KEY): addresses.add(value) else: raise TypeError( "cannot add source address with unsupported UnlockHashType {}" .format(value.uhtype)) if len(source) == 1: if source[0].uhtype.__eq__(UnlockHashType.PUBLIC_KEY): refund = ConditionTypes.unlockhash_new( unlockhash=source[0]) # ensure at least one address is defined if len(addresses) == 0: raise tferrors.InsufficientFunds( "insufficient funds in this wallet") # if personal addresses are given, try to use these first # as these are the easiest kind to deal with if len(addresses) == 0: outputs, collected = ([], Currency()) # start with nothing else: outputs, collected = self._fund_individual(amount, addresses) if collected.greater_than_or_equal_to(amount): # if we already have sufficient, we stop now return ([CoinInput.from_coin_output(co) for co in outputs], collected.minus(amount), refund) raise tferrors.InsufficientFunds( "not enough funds available in the wallet to fund the requested amount" )
def _from_json_data_object(self, data): self._addresses = [ NetworkAddress.from_json(address) for address in data.get('addresses', []) or [] ] self._names = [ BotName.from_json(name) for name in data.get('names', []) or [] ] self._number_of_months = int(data.get('nrofmonths', 0) or 0) if 'txfee' in data: self._transaction_fee = Currency.from_json(data['txfee']) else: self._transaction_fee = None self._coin_inputs = [ CoinInput.from_json(ci) for ci in data.get('coininputs', []) or [] ] if 'refundcoinoutput' in data: self._refund_coin_output = CoinOutput.from_json( data['refundcoinoutput']) else: self._refund_coin_output = None if 'identification' not in data or data['identification'] in (None, {}): self._public_key = None self._signature = None else: identification = data['identification'] self._public_key = PublicKey.from_json(identification['publickey']) self._signature = ED25519Signature.from_json( identification['signature'], as_array=True)
def fund(self, amount, source=None): """ Fund the specified amount with the available outputs of this wallet's balance. """ refund = self.condition address = refund.unlockhash.__str__() if source == None: source = address else: if not isinstance(source, str): raise TypeError("invalid source: {} ({})".format( source, type(source))) if source != address: raise ValueError( "source is of an address different than this multisig' balance' address: {} != {}" .format(source, address)) outputs, collected = self._fund_individual(amount, [source]) if collected.greater_than_or_equal_to(amount): # if we already have sufficient, we stop now return ([CoinInput.from_coin_output(co) for co in outputs], collected.minus(amount), refund) raise tferrors.InsufficientFunds( "not enough funds available in the wallet to fund the requested amount" )
def _from_json_data_object(self, data): # decode public key if 'pubkey' in data: self._public_key = PublicKey.from_json(data['pubkey']) else: self._public_key = None # decode signature if 'signature' in data: self._signature = ED25519Signature.from_json(data['signature']) else: self._signature = None # decode registration fee if 'regfee' in data: self.registration_fee = Currency.from_json(data['regfee']) else: self.registration_fee = None # decode transaction fee if 'txfee' in data: self._transaction_fee = Currency.from_json(data['txfee']) else: self._transaction_fee = None # decode coin inputs self._coin_inputs = [ CoinInput.from_json(ci) for ci in data.get('coininputs', []) or [] ] # decode refund coin output (if it exists) if 'refundcoinoutput' in data: self._refund_coin_output = CoinOutput.from_json( data['refundcoinoutput']) else: self._refund_coin_output = None
def _from_json_data_object(self, data): # decode address if 'address' in data: self._address = ERC20Address.from_json(data['address']) else: self._address = None # decode value if 'value' in data: self._value = Currency.from_json(data['value']) else: self._value = None # decode transaction fee if 'txfee' in data: self._transaction_fee = Currency.from_json(data['txfee']) else: self._transaction_fee = None # decode coin inputs self._coin_inputs = [ CoinInput.from_json(ci) for ci in data.get('coininputs', []) or [] ] # decode refund coin output (if it exists) if 'refundcoinoutput' in data: self._refund_coin_output = CoinOutput.from_json( data['refundcoinoutput']) else: self._refund_coin_output = None
def drain(self, recipient, miner_fee, unconfirmed=False, data=None, lock=None): """ add all available outputs into as many transactions as required, by default only confirmed outputs are used, if unconfirmed=True it will use unconfirmed available outputs as well. Result can be an empty list if no outputs were available. @param recipient: required recipient towards who the drained coins will be sent @param the miner fee to be added to all sent transactions @param unconfirmed: optionally drain unconfirmed (available) outputs as well @param data: optional data that can be attached ot the created transactions (str or bytes), with a max length of 83 @param lock: optional lock that can be attached to the sent coin outputs """ # define recipient recipient = ConditionTypes.from_recipient(recipient, lock=lock) # validate miner fee if not isinstance(miner_fee, Currency): raise TypeError("miner fee has to be a currency") if miner_fee.__eq__(0): raise ValueError("a non-zero miner fee has to be defined") # collect all transactions in one list txns = [] # collect all confirmed (available) outputs outputs = self.outputs_available if unconfirmed: # if also the unconfirmed_avaialble) outputs are desired, let's add them as well outputs += self.outputs_unconfirmed_available # drain all outputs while len(outputs) > 0: txn = transactions.new() txn.data = data txn.miner_fee_add(miner_fee) # select maximum _MAX_RIVINE_TRANSACTION_INPUTS outputs n = min(len(outputs), _MAX_RIVINE_TRANSACTION_INPUTS) used_outputs = outputs[:n] outputs = outputs[ n:] # and update our output list, so we do not double spend # compute amount, minus minimum fee and add our only output amount = sum([co.value for co in used_outputs]) - miner_fee txn.coin_output_add(condition=recipient, value=amount) # add the coin inputs txn.coin_inputs = [ CoinInput.from_coin_output(co) for co in used_outputs ] # append the transaction txns.append(txn) # return all created transactions, if any return txns
def _from_json_data_object(self, data): self._coin_inputs = [CoinInput.from_json( ci) for ci in data.get('coininputs', []) or []] self._coin_outputs = [CoinOutput.from_json( co) for co in data.get('coinoutputs', []) or []] self._blockstake_inputs = [BlockstakeInput.from_json( bsi) for bsi in data.get('blockstakeinputs', []) or []] self._blockstake_outputs = [BlockstakeOutput.from_json( bso) for bso in data.get('blockstakeoutputs', []) or []] self._miner_fees = [Currency.from_json( fee) for fee in data.get('minerfees', []) or []] self._data = BinaryData.from_json( data.get('arbitrarydata', None) or '', strencoding='base64')
def _from_json_data_object(self, data): # decode sender info if 'sender' in data: bot_data = data['sender'] self._sender_botid = int(bot_data.get('id', 0) or 0) self._sender_signature = ED25519Signature.from_json( bot_data.get('signature', None) or None) else: self._sender_botid = None self._sender_signature = None # decode receiver info if 'receiver' in data: bot_data = data['receiver'] self._receiver_botid = int(bot_data.get('id', 0) or 0) self._receiver_signature = ED25519Signature.from_json( bot_data.get('signature', None) or None) else: self._receiver_botid = None self._receiver_signature = None # decode names self._names = [ BotName.from_json(name) for name in data.get('names', []) or [] ] # decode transaction fee if 'txfee' in data: self._transaction_fee = Currency.from_json(data['txfee']) else: self._transaction_fee = None # decode coin inputs self._coin_inputs = [ CoinInput.from_json(ci) for ci in data.get('coininputs', []) or [] ] # decode refund coin output if 'refundcoinoutput' in data: self._refund_coin_output = CoinOutput.from_json( data['refundcoinoutput']) else: self._refund_coin_output = None
def coin_input_add(self, parentid, fulfillment, parent_output=None): ci = CoinInput(parentid=parentid, fulfillment=fulfillment) ci.parent_output = parent_output self._coin_inputs.append(ci)
def legacy_from_json(cls, obj): """ Class method to decode v1 Tx from a legacy v0 Tx. """ tv = obj.get('version', -1) if TransactionVersion.LEGACY != tv: raise ValueError("legacy v0 transaction is expected to be of version {}, not version {}".format( TransactionVersion.LEGACY, tv)) txn = cls() if 'data' not in obj: raise ValueError("no data object found in Legacy Transaction (v{})".format( TransactionVersion.LEGACY)) txn_data = obj['data'] if 'coininputs' in txn_data: for legacy_ci_info in (txn_data['coininputs'] or []): unlocker = legacy_ci_info.get('unlocker', {}) ci_info = { 'parentid': legacy_ci_info.get('parentid', ''), 'fulfillment': { 'type': 1, 'data': { 'publickey': unlocker.get('condition', {}).get('publickey'), 'signature': unlocker.get('fulfillment', {}).get('signature'), } } } ci = CoinInput.from_json(ci_info) txn._coin_inputs.append(ci) if 'coinoutputs' in txn_data: for legacy_co_info in (txn_data['coinoutputs'] or []): co_info = { 'value': legacy_co_info.get('value', '0'), 'condition': { 'type': 1, 'data': { 'unlockhash': legacy_co_info.get('unlockhash', ''), } } } co = CoinOutput.from_json(co_info) txn._coin_outputs.append(co) if 'blockstakeinputs' in txn_data: for legacy_bsi_info in (txn_data['blockstakeinputs'] or []): unlocker = legacy_bsi_info.get('unlocker', {}) bsi_info = { 'parentid': legacy_bsi_info.get('parentid', ''), 'fulfillment': { 'type': 1, 'data': { 'publickey': unlocker.get('condition', {}).get('publickey'), 'signature': unlocker.get('fulfillment', {}).get('signature'), } } } bsi = BlockstakeInput.from_json(bsi_info) txn._blockstake_inputs.append(bsi) if 'blockstakeoutputs' in txn_data: for legacy_bso_info in (txn_data['blockstakeoutputs'] or []): bso_info = { 'value': legacy_bso_info.get('value', '0'), 'condition': { 'type': 1, 'data': { 'unlockhash': legacy_bso_info.get('unlockhash', ''), } } } bso = BlockstakeOutput.from_json(bso_info) txn._blockstake_outputs.append(bso) if 'minerfees' in txn_data: for miner_fee in (txn_data['minerfees'] or []): txn._miner_fees.append(Currency.from_json(miner_fee)) if 'arbitrarydata' in txn_data: txn._data = BinaryData.from_json(txn_data.get( 'arbitrarydata', None) or '', strencoding='base64') txn._legacy = True return txn