code: function composeMinimalIndivisibleAssetPaymentJoint(params){
  	if (!ValidationUtils.isNonemptyArray(params.available_paying_addresses))
  		throw Error('no available_paying_addresses');
  	if (!ValidationUtils.isNonemptyArray(params.available_fee_paying_addresses))
  		throw Error('no available_fee_paying_addresses');
  	var target_amount;
  	if (params.amount)
  		target_amount = params.amount;
  	else if (params.asset_outputs)
  		target_amount = params.asset_outputs.reduce(function(accumulator, output){ return accumulator + output.amount; }, 0);
  	if (!target_amount)
  		throw Error("no target amount");
  	readFundedAddresses(
  		params.asset, target_amount, params.available_paying_addresses, params.available_fee_paying_addresses, params.spend_unconfirmed || 'own',
  		function(arrFundedPayingAddresses, arrFundedFeePayingAddresses){
  			if (arrFundedPayingAddresses.length === 0)
  				return params.callbacks.ifNotEnoughFunds("either the amount you entered can't be composed using available denominations or all paying addresses are unfunded in asset, make sure all your funds are confirmed");
  			var minimal_params = _.clone(params);
  			delete minimal_params.available_paying_addresses;
  			delete minimal_params.available_fee_paying_addresses;
  			minimal_params.minimal = true;
  			minimal_params.paying_addresses = arrFundedPayingAddresses;
  			minimal_params.fee_paying_addresses = arrFundedFeePayingAddresses;
  			composeIndivisibleAssetPaymentJoint(minimal_params);
  		}
  	);
  }
docs: {asset: asset, available_paying_addresses: arrAvailablePayingAddresses, available_fee_paying_addresses: arrAvailableFeePayingAddresses, to_address: to_address, change_address: change_address, amount: amount, tolerance_plus: tolerance_plus, tolerance_minus: tolerance_minus, signer: signer, callbacks: callbacks}