def MakeTransaction(self, tx, change_address=None, fee=Fixed8(0), from_addr=None, use_standard=False, watch_only_val=0, exclude_vin=None, use_vins_for_asset=None): """ This method is used to to calculate the necessary TransactionInputs (CoinReferences) and TransactionOutputs to be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc ) Args: tx: (Transaction) The Transaction to be used change_address: (UInt160) The address any change for the transaction should be returned to fee: (Fixed8) A fee to be attached to the Transaction for network processing purposes from_addr: (UInt160) If present, all CoinReferences selected will only come from this address use_standard: (bool) If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used watch_only_val: (int) 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address exclude_vin: (list) A list of CoinReferences to NOT use in the making of this tx use_vins_for_asset: (list) A list of CoinReferences to use Returns: tx: (Transaction) Returns the transaction with oupdated inputs and outputs """ tx.ResetReferences() if not tx.outputs: tx.outputs = [] if not tx.inputs: tx.inputs = [] fee = fee + (tx.SystemFee() * Fixed8.FD()) # pdb.set_trace() paytotal = {} if tx.Type != int.from_bytes(TransactionType.IssueTransaction, 'little'): for key, group in groupby(tx.outputs, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Value paytotal[key] = sum else: paytotal = {} if fee > Fixed8.Zero(): if Blockchain.SystemCoin().Hash in paytotal.keys(): paytotal[Blockchain.SystemCoin(). Hash] = paytotal[Blockchain.SystemCoin().Hash] + fee else: paytotal[Blockchain.SystemCoin().Hash] = fee paycoins = {} self._vin_exclude = exclude_vin for assetId, amount in paytotal.items(): if use_vins_for_asset is not None and len( use_vins_for_asset ) > 0 and use_vins_for_asset[1] == assetId: paycoins[assetId] = self.FindCoinsByVins(use_vins_for_asset[0]) else: paycoins[assetId] = self.FindUnspentCoinsByAssetAndTotal( assetId, amount, from_addr=from_addr, use_standard=use_standard, watch_only_val=watch_only_val) self._vin_exclude = None for key, unspents in paycoins.items(): if unspents is None: print("insufficient funds for asset id: %s " % key) return None input_sums = {} for assetId, unspents in paycoins.items(): sum = Fixed8(0) for coin in unspents: sum = sum + coin.Output.Value input_sums[assetId] = sum if not change_address: change_address = self.GetChangeAddress(from_addr=from_addr) new_outputs = [] for assetId, sum in input_sums.items(): if sum > paytotal[assetId]: difference = sum - paytotal[assetId] output = TransactionOutput(AssetId=assetId, Value=difference, script_hash=change_address) new_outputs.append(output) inputs = [] for item in paycoins.values(): for ref in item: inputs.append(ref.Reference) tx.inputs = inputs tx.outputs = tx.outputs + new_outputs return tx
def SystemFee(self): return self.Gas // Fixed8.FD()