Skip to content

Instantly share code, notes, and snippets.

@ayinot
Last active May 20, 2018 02:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayinot/5b27293f8013d65999f5bd9ec151a5bc to your computer and use it in GitHub Desktop.
Save ayinot/5b27293f8013d65999f5bd9ec151a5bc to your computer and use it in GitHub Desktop.
package com.example.contract
import com.example.state.LoanState
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.Contract
import net.corda.core.contracts.requireSingleCommand
import net.corda.core.contracts.requireThat
import net.corda.core.transactions.LedgerTransaction
/**
* A implementation of a basic smart contract for loan example in Corda.
*
* This contract enforces rules regarding the creation of a valid [LoanState], which in turn encapsulates an [Loan].
*
* For a new [Loan] to be issued onto the ledger, a transaction is required which takes:
* - Zero input states.
* - One output state: the new [Loantate].
* - Borrow() command with the public keys of both the lender and the borrower.
*
* All contracts must sub-class the [Contract] interface.
*/
open class LoanContract : Contract {
companion object {
@JvmStatic
val Loan_CONTRACT_ID = "com.example.contract.LoanContract"
}
/**
* The verify() function of all the states' contracts must not throw an exception for a transaction to be
* considered valid.
*/
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<Commands>()
if(command.value is Commands.Borrow ){
requireThat {
// Generic constraints around the IOU transaction.
"No inputs should be consumed when creating a borrow request." using (tx.inputs.isEmpty())
"Only one output state should be created." using (tx.outputs.size == 1)
val out = tx.outputsOfType<LoanState>().single()
"All of the participants must be signers." using (command.signers.containsAll(out.participants.map { it.owningKey }))
// Loan-specific constraints.
"The Loan amount must be non-negative." using (out.loanAmount > 0)
}
} else if(command.value is Commands.Lend) {
requireThat {
// Generic constraints around the IOU transaction.
"Inputs should be consumed when creating a borrow request." using (tx.inputs.isNotEmpty())
val out = tx.outputsOfType<LoanState>().single()
"The lender and the borrower cannot be the same entity." using (out.borrower != out.lender[0])
"The lender and the borrower cannot be the same entity." using (out.borrower != out.lender[1])
"The lender and the borrower cannot be the same entity." using (out.borrower != out.lender[2])
"All of the participants must be signers." using (command.signers.containsAll(out.participants.map { it.owningKey }))
// Loan-specific constraints.
"The Loan amount must be non-negative." using (out.loanAmount > 0)
// Loan-specific constraints.
"The Maximum Interest rate should be 20%" using(out.interestRate <= 20);
}
}else if(command.value is Commands.Confirm){
requireThat {
// Generic constraints around the IOU transaction.
"Inputs should be consumed when creating a borrow request." using (tx.inputs.isNotEmpty())
val out = tx.outputsOfType<LoanState>().single()
"The lender and the borrower cannot be the same entity." using (out.borrower != out.lender[0])
"The lender and the borrower cannot be the same entity." using (out.borrower != out.lender[1])
"The lender and the borrower cannot be the same entity." using (out.borrower != out.lender[2])
"All of the participants must be signers." using (command.signers.containsAll(out.participants.map { it.owningKey }))
// Loan-specific constraints.
"The Loan amount must be non-negative." using (out.loanAmount > 0)
}
}
}
/**
* This contract only implements Borrow, Lend and Confirm.
*/
interface Commands : CommandData {
class Borrow : Commands
class Lend : Commands
class Confirm: Commands
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment