
net.corda.contracts.clause.AbstractConserveAmount.kt Maven / Gradle / Ivy
package net.corda.contracts.clause
import net.corda.contracts.asset.OnLedgerAsset
import net.corda.core.contracts.*
import net.corda.core.contracts.clauses.Clause
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.loggerFor
import java.security.PublicKey
/**
* Standardised clause for checking input/output balances of fungible assets. Requires that a
* Move command is provided, and errors if absent. Must be the last clause under a grouping clause;
* errors on no-match, ends on match.
*/
abstract class AbstractConserveAmount, C : CommandData, T : Any> : Clause>() {
private companion object {
val log = loggerFor>()
}
/**
* Generate an transaction exiting fungible assets from the ledger.
*
* @param tx transaction builder to add states and commands to.
* @param amountIssued the amount to be exited, represented as a quantity of issued currency.
* @param assetStates the asset states to take funds from. No checks are done about ownership of these states, it is
* the responsibility of the caller to check that they do not attempt to exit funds held by others.
* @return the public key of the assets issuer, who must sign the transaction for it to be valid.
*/
@Deprecated("This function will be removed in a future milestone", ReplaceWith("OnLedgerAsset.generateExit()"))
@Throws(InsufficientBalanceException::class)
fun generateExit(tx: TransactionBuilder, amountIssued: Amount>,
assetStates: List>,
deriveState: (TransactionState, Amount>, PublicKey) -> TransactionState,
generateMoveCommand: () -> CommandData,
generateExitCommand: (Amount>) -> CommandData): PublicKey
= OnLedgerAsset.generateExit(tx, amountIssued, assetStates, deriveState, generateMoveCommand, generateExitCommand)
override fun verify(tx: TransactionForContract,
inputs: List,
outputs: List,
commands: List>,
groupingKey: Issued?): Set {
require(groupingKey != null) { "Conserve amount clause can only be used on grouped states" }
val matchedCommands = commands.filter { command -> command.value is FungibleAsset.Commands.Move || command.value is FungibleAsset.Commands.Exit<*> }
val inputAmount: Amount> = inputs.sumFungibleOrNull() ?: throw IllegalArgumentException("there is at least one asset input for group $groupingKey")
val deposit = groupingKey!!.issuer
val outputAmount: Amount> = outputs.sumFungibleOrZero(groupingKey)
// If we want to remove assets from the ledger, that must be signed for by the issuer and owner.
val exitKeys: Set = inputs.flatMap { it.exitKeys }.toSet()
val exitCommand = matchedCommands.select>(parties = null, signers = exitKeys).filter { it.value.amount.token == groupingKey }.singleOrNull()
val amountExitingLedger: Amount> = exitCommand?.value?.amount ?: Amount(0, groupingKey)
requireThat {
"there are no zero sized inputs" using inputs.none { it.amount.quantity == 0L }
"for reference ${deposit.reference} at issuer ${deposit.party} the amounts balance: ${inputAmount.quantity} - ${amountExitingLedger.quantity} != ${outputAmount.quantity}" using
(inputAmount == outputAmount + amountExitingLedger)
}
verifyMoveCommand(inputs, commands)
// This is safe because we've taken the commands from a collection of C objects at the start
@Suppress("UNCHECKED_CAST")
return matchedCommands.map { it.value }.toSet()
}
override fun toString(): String = "Conserve amount between inputs and outputs"
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy