Introduction to Corda contract
What is Contract
Contract is verification logic for change to state. Contract verify logic which is independent of related parties and deterministic. Flow verify logic which is independent of parties and can be non-deterministic.
How to define your contract.
You define your Contract class by inheriting Contract class and overriding verify function
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
}
}
Verify function
If verify don't throw, contract is valid. If verify throw, contract is invalid. Verify doesn't return any value. Verify function can access to only tx: LedgerTransaction
object.
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
return
}
}
verify function can access below data
-
tx.inputs
, which lists the inputs -
tx.outputs
, which lists the outputs -
tx.commands
, which lists the commands and their associated signers -
tx.outputsOfType<T>
, which lists state object of Type T
Code Example
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
const inputs = tx.inputs
const outputs = tx.outputs
const commands = tx.commands
val output = tx.outputsOfType<IOUState>().single()
}
}
How to define command in Contract.
We can define command class inside your Contract Class. And your Command should inherit from CommandData class.
class MyContract : Contract {
class Create : CommandData
}
Command constraint
Transaction can contain more than two commands.
In this case, we check that transaction has only one Create Command.
class MyContract : Contract {
class Create : CommandData
override fun verify(tx: LedgerTransaction) {
val command = requireSingleCommand<Create>()
}
}
Signer Constraints
You should verify that required signs are collected.
You use output.borrower.owningKey, and output.lender.owningKey, command.signers.
class MyContract : Contract {
class Create : CommandData
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<Create>()
requireThat {
val output = tx.outputsOfType<IOUState>().single()
// Constraints on the signers.
val expectedSigners = listOf(output.borrower.owningKey, output.lender.owningKey)
"There must be two signers." using (command.signers.toSet().size == 2)
"The borrower and lender must be signers." using (command.signers.containsAll(expectedSigners))
}
}
}
Discussion