Write States
This tutorial guides you through writing the two states
An immutable object representing a fact known by one or more participants at a specific point in time. You can use states to represent any type of data, and any kind of fact.
you need in your CorDapp
Corda Distributed Application. A Java (or any JVM targeting language) application built using the Corda build toolchain and CorDapp API to solve some problem that is best solved in a decentralized manner.
: AppleStamp
and BasketofApples
.
You will create these states in the contracts/src/main/kotlin/com/r3/developers/apples/states
directory.
Learning Objectives
After you have completed this tutorial, you will know how to create and implement states in a CorDapp.
Before You Start
Before you start building states, read more about states.
Create the AppleStamp
State
First, create the AppleStamp
state. This state is the voucher issued to customers.
- Go to the
contracts/src/main/kotlin/com/r3/developers/apples
folder. - Right-click the states folder, select New > Kotlin Class and create a file called
AppleStamp
. - Open the file.
Add Annotations
The first thing you should do when writing a state is add the @BelongsToContract
annotation. This annotation
establishes the relationship between a state and a contract. Without this, your state does not know which contract is used to verify it.
Add the annotation @BelongsToContract(AppleStampContract::class)
to your state. The contract will be defined later.
Your code should now look like:
@BelongsToContract(AppleStampContract::class)
AppleStampContract
yet. Ignore this error for now - you will add the contract class in the Write Contracts tutorial.When naming your CorDapp files, it’s best practice to match your contract and state names. In this case the state is called AppleStamp
, so the contract is called AppleStampContract
. Follow this naming convention when you write your own original CorDapp to avoid confusion.
Implement the State
The next line of code you add defines the type of ContractState
you implement with the AppleStamp
class. Add this line to ensure that Corda recognizes the AppleStamp
as a state.
Add the public class AppleStamp
implementing a ContractState
.
Your code should now look as follows:
@BelongsToContract(AppleStampContract::class)
class AppleStamp : ContractState
Add the Required Properties
Add the properties for the following parameters required for the example:
- The stamp identifier (
id
) - The stamp description (
stampDesc
) - The issuer of the stamp (
issuer
) - The current owner of the stamp (
holder
)
- The stamp identifier (
All
ContractStates
must include a parameter to indicate the participants that store the states. AsContractState
is a Java API, you must store the participants as private members Corda identity that has been granted admission to a membership group. Synonym for a virtual node or group member. . Add this property to theAppleStamp
:private val participants: List<PublicKey>
To expose the
participants
value, override thegetParticipants()
method in theAppleStamp
:override fun getParticipants(): List<PublicKey> = participants
After following these steps, your code should look as follows:
@BelongsToContract(AppleStampContract::class)
class AppleStamp(
val id: UUID,
val stampDesc: String,
val issuer: PublicKey,
val holder: PublicKey,
private val participants: List<PublicKey>
) : ContractState {
override fun getParticipants(): List<PublicKey> = participants
}
PublicKey
s referred to in the participants
property are the ledgerKey
s of the participants expected to store the states.Add Imports
If you are using IntelliJ or another IDE, the IDE automatically adds the imports you need. IntelliJ indicates that an import is missing with red text.
Once you have added all imports, your code should look like this:
package com.r3.developers.apples.states
import com.r3.developers.apples.contracts.AppleStampContract
import net.corda.v5.ledger.utxo.BelongsToContract
import net.corda.v5.ledger.utxo.ContractState
import java.security.PublicKey
import java.util.*
@BelongsToContract(AppleStampContract::class)
class AppleStamp(
val id: UUID,
val stampDesc: String,
val issuer: PublicKey,
val holder: PublicKey,
private val participants: List<PublicKey>
) : ContractState {
override fun getParticipants(): List<PublicKey> = participants
}
Create the BasketOfApples
State
The BasketOfApples
state is the basket of apples that Farmer Bob self-issues to prepare the apples for Dave. Now that you have written your first state, try writing the BasketOfApples
state using the following properties:
description
- The brand or type of apple. Use typeString
.farm
- The origin of the apples. Use typePublicKey
.owner
- The current owner of the basket. Use typePublicKey
.weight
- The weight of the basket of apples. Use typeInt
.
You will also need to define a participants
property and override the getParticipants()
getter method, as you did when creating the AppleStamp
contract.
The BasketOfApples
state is involved in two transactions. In the first transaction
A transaction is a proposal to update the ledger.
, Farmer Bob self-issues the BasketOfApples
.
At this point, Farmer Bob is both the owner
and farm
of the transaction. The second transaction occurs when Dave
wishes to redeem his AppleStamp
for the BasketOfApples
. At this point, the owner changes from Bob to Dave.
To enable this, implement a changeOwner
function within the state. It allows an updated state to be returned with a new owner.
Add the following code to your BasketOfApples
state class:
fun changeOwner(buyer: PublicKey): BasketOfApples {
val participants = listOf(farm, buyer)
return BasketOfApples(description, farm, buyer, weight, participants)
}
Check Your Work
Once you’ve written the BasketOfApples
state, check your code against the sample below. Your code should look something like this:
package com.r3.developers.apples.states
import com.r3.developers.apples.contracts.BasketOfApplesContract
import net.corda.v5.ledger.utxo.BelongsToContract
import net.corda.v5.ledger.utxo.ContractState
import java.security.PublicKey
@BelongsToContract(BasketOfApplesContract::class)
class BasketOfApples(
val description: String,
val farm: PublicKey,
val owner: PublicKey,
val weight: Int,
private val participants: List<PublicKey>
) : ContractState {
override fun getParticipants(): List<PublicKey> = participants
fun changeOwner(buyer: PublicKey): BasketOfApples {
val participants = listOf(farm, buyer)
return BasketOfApples(description, farm, buyer, weight, participants)
}
}
Next Steps
Follow the Write Contracts tutorial to continue on this learning path.
Was this page helpful?
Thanks for your feedback!
Chat with us
Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.
Propose documentation improvements directly
Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.
We're sorry this page wasn't helpful. Let us know how we can make it better!
Chat with us
Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.
Create an issue
Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.
Propose documentation improvements directly
Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.