Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ee8c155
ENT-14906 - Sample for Enabling Proof-Free Transactions
filipesoliveira Mar 31, 2026
ba481a2
Fixed typo.
filipesoliveira Apr 7, 2026
2b2f551
Update.
filipesoliveira Apr 20, 2026
910d66d
Added comments explaining the code changes.
filipesoliveira Apr 30, 2026
d95a18c
Added commentss about the `ProposalFlow`.
filipesoliveira Apr 30, 2026
42935dc
Updated the acceptance flow.
filipesoliveira Apr 30, 2026
264c8cc
Reverted changes
filipesoliveira Sep 25, 2026
f131b5a
Added the module negotiation-cordapp-key-rotation-support.
filipesoliveira Sep 25, 2026
816ccfa
Added the module negotiation-cordapp-key-rotation-support.
filipesoliveira Sep 25, 2026
aa8be30
Update
filipesoliveira Sep 25, 2026
2ec2b98
Corrected the folder name.
filipesoliveira Sep 25, 2026
27fa965
Corrections.
filipesoliveira Sep 25, 2026
6c3029d
Fix.
filipesoliveira Sep 28, 2026
067e30c
Reverted changes made to Advanced/constants.properties
filipesoliveira Sep 29, 2026
ff4505f
Pointed the cordapp to enterprise.
filipesoliveira Sep 29, 2026
f064aae
Added tests.
filipesoliveira Sep 30, 2026
1c127f3
Update.
filipesoliveira Sep 30, 2026
6af4a37
Removed the dependency on net.corda.core.internal
filipesoliveira Oct 14, 2026
7750e62
Updated the comments in ModificationFlow
filipesoliveira Oct 14, 2026
6a57bf0
Updated message in ProposalAndTradeContract
filipesoliveira Oct 14, 2026
c7ed9c1
Update. Remove the spaces.
filipesoliveira Oct 14, 2026
603b7a1
Updated the README file to contain an short explanation about the dep…
filipesoliveira Oct 14, 2026
95e038a
ENT-16775 - Updated README file, sql.xml, and bootstrapp.sh to point …
filipesoliveira Oct 15, 2026
e8320fe
Update
filipesoliveira Oct 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Advanced/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ An capital market themed app that depicts an ideal shareable due diligence proce
An application that depicts the businsess negotiation and communication process over a distributed ledger system.
It consists of the proposing, negotiating, and settling a corda transaction.

### [Negotiation Cordapp (Key Rotation Proof-Free)](./negotiation-cordapp-key-rotation-proof-free):
An application that depicts the business negotiation and communication process over a distributed ledger system.
It consists of the proposing, negotiating, and settling a corda transaction.
This is a modified version of the Negotiation CorDapp that demonstrates how to update a CorDapp to support proof-free
key rotation.

### [Obligation Cordapp](./obligation-cordapp):
A simple i-owe-you application illustrates all of the steps of creating an obligation for a resource to change owners.

Expand Down
3 changes: 3 additions & 0 deletions Advanced/constants.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
cordaReleaseGroup=net.corda
cordaCoreReleaseGroup=net.corda
cordaEnterpriseReleaseGroup=com.r3.corda
cordaVersion=4.15-SNAPSHOT
cordaCoreVersion=4.15-SNAPSHOT
cordaShellVersion=4.15-SNAPSHOT
Expand All @@ -9,6 +10,8 @@ junitVersion=4.12
quasarVersion=0.9.0_r3
log4jVersion=2.23.1
platformVersion=140
# Platform version declared by the key rotation samples: they use Corda 4.15 APIs and need a network minimum platform version of 170.
keyRotationPlatformVersion=170
slf4jVersion=2.0.12
nettyVersion=4.1.77.Final
snappyVersion=0.4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
13 changes: 13 additions & 0 deletions Advanced/negotiation-cordapp-key-rotation-proof-free/LICENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2016, R3 Limited.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
81 changes: 81 additions & 0 deletions Advanced/negotiation-cordapp-key-rotation-proof-free/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Negotiation Cordapp Proof-Free Transactions

This CorDapp shows how multi-party negotiation is handled on the Corda ledger, in the absence of an API for user
interaction. This version of the CorDapp demonstrates how to implement a negotiation flow with key rotation support
that only requires the key rotation proof to be provided when consuming a state signed by the old key.

## Concepts

A flow is provided that allows a node to propose a trade to a counterparty. The counterparty has two options:

* Accepting the proposal, converting the `ProposalState` into a `TradeState` with identical attributes
* Modifying the proposal, consuming the existing `ProposalState` and replacing it with a new `ProposalState` for a new
amount

Only the recipient of the proposal has the ability to accept it or modify it. If the sender of the proposal tries to
accept or modify the proposal, this attempt will be rejected automatically at the flow level.

### Flows

We start with the proposal flow implemented in `ProposalFlow.java`.


The modification of the proposal is implemented in `ModificationFlow.java`.


In the `AcceptanceFlow.java`, we receive the modified ProposalState and it's converted into a TradeState.



## Usage

### Pre-Requisites
For development environment setup, please refer to: [Setup Guide](https://docs.corda.net/getting-set-up.html).

This sample requires **Corda Enterprise 4.15**: key rotation is a Corda Enterprise feature (see
[Cross-provider key rotation](https://docs.r3.com/en/platform/corda/4.15/enterprise/node/cross-provider-key-rotation/cross-provider-key-rotation.html)).
The Corda Enterprise artifacts (`com.r3.corda:*`) are only available to Corda Enterprise customers, so point Gradle at the
repository your organisation downloads them from by setting, in `~/.gradle/gradle.properties`:

cordaEnterpriseRepositoryUrl=<repository URL>
cordaEnterpriseRepositoryUsername=<username>
cordaEnterpriseRepositoryPassword=<password or access token>

or the environment variables `CORDA_ENTERPRISE_REPOSITORY_URL`, `CORDA_ENTERPRISE_REPOSITORY_USERNAME` and
`CORDA_ENTERPRISE_REPOSITORY_PASSWORD`. See `repositories.gradle`.



### Running the nodes:

Open a terminal and go to the project root directory and type: (to deploy the nodes using bootstrapper)
```
./gradlew clean deployNodes
```
Then type: (to run the nodes)
```
./build/nodes/runnodes
```

We will interact with this CorDapp via the nodes' [CRaSH](https://docs.corda.net/docs/corda-os/shell.html) shells.

First, go the the shell of PartyA, and propose a deal with yourself as buyer and a value of 10 to PartyB:

flow start ProposalFlow$Initiator isBuyer: true, amount: 10, counterparty: PartyB

We can now look at the proposals in the PartyA's vault:

run vaultQuery contractStateType: ProposalState

If we note down the state's `linearId.id`, we can now modify the proposal from the shell of PartyB by running:

flow start ModificationFlow$Initiator proposalId: <YOUR-NEWLY-GENERATED-PROPOSAL-ID>, newAmount: 8

Finally, let's have PartyA accept the proposal:

flow start AcceptanceFlow$Initiator proposalId: <YOUR-NEWLY-GENERATED-PROPOSAL-ID>

We can now see the accepted trade in our vault with the new value by running the command (note we are now querying for
`TradeState`s, not `ProposalState`s):

run vaultQuery contractStateType: TradeState
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Corda and the Corda logo are trademarks of R3CEV LLC and its affiliates. All rights reserved.

For R3CEV LLC's trademark and logo usage information, please consult our Trademark Usage Policy at
https://www.r3.com/trademark-policy/.
192 changes: 192 additions & 0 deletions Advanced/negotiation-cordapp-key-rotation-proof-free/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import static org.gradle.api.JavaVersion.VERSION_17

buildscript {
Properties constants = new Properties()
file("$projectDir/../constants.properties").withInputStream { constants.load(it) }

ext {
corda_release_group = constants.getProperty("cordaReleaseGroup")
corda_core_release_group = constants.getProperty("cordaCoreReleaseGroup")
// This sample runs on Corda ENTERPRISE: its node, driver, shell and test artifacts come from cordaEnterpriseReleaseGroup
// (com.r3.corda). Enterprise builds on Corda OS's corda-core, which stays under cordaCoreReleaseGroup.
corda_enterprise_release_group = constants.getProperty("cordaEnterpriseReleaseGroup")
corda_release_version = constants.getProperty("cordaVersion")
corda_core_release_version = constants.getProperty("cordaCoreVersion")
corda_gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
kotlin_version = constants.getProperty("kotlinVersion")
junit_version = constants.getProperty("junitVersion")
quasar_version = constants.getProperty("quasarVersion")
quasar_exclusions = [
'co.paralleluniverse**',
'groovy**',
'com.esotericsoftware.**',
'jdk**',
'junit**',
'kotlin**',
'net.rubygrapefruit.**',
'org.gradle.**',
'org.apache.**',
'org.jacoco.**',
'org.junit**',
'org.slf4j**',
'worker.org.gradle.**',
'org.mockito.kotlin**',
'org.assertj**',
'org.hamcrest**',
'org.mockito**',
'org.opentest4j**',
'org.springframework**'
]
log4j_version = constants.getProperty("log4jVersion")
slf4j_version = constants.getProperty("slf4jVersion")
corda_platform_version = constants.getProperty("keyRotationPlatformVersion").toInteger()
//springboot
spring_boot_version = '3.2.5'
spring_boot_gradle_plugin_version = '3.2.5'

testJvmArgs = ['--add-opens', 'java.base/java.time=ALL-UNNAMED', '--add-opens', 'java.base/java.io=ALL-UNNAMED',
'--add-opens', 'java.base/java.util=ALL-UNNAMED', '--add-opens', 'java.base/java.net=ALL-UNNAMED',
'--add-opens', 'java.base/java.nio=ALL-UNNAMED', '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED',
'--add-opens', 'java.base/java.security.cert=ALL-UNNAMED', '--add-opens', 'java.base/java.security=ALL-UNNAMED',
'--add-opens', 'java.base/javax.net.ssl=ALL-UNNAMED', '--add-opens', 'java.base/java.lang=ALL-UNNAMED',
'--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED', '--add-opens', 'java.sql/java.sql=ALL-UNNAMED',]
}

repositories {
mavenLocal()
mavenCentral()

maven { url 'https://download.corda.net/maven/corda-dependencies' }
maven { url 'https://download.corda.net/maven/corda-releases' }
}

dependencies {
classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version"
classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version"
classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_gradle_plugin_version"
}
}

allprojects {
apply from: "${rootProject.projectDir}/repositories.gradle"
apply plugin: 'java'

tasks.withType(Test) {
jvmArgs = rootProject.ext.testJvmArgs
}

repositories {
mavenLocal()

mavenCentral()
maven { url 'https://download.corda.net/maven/corda-dependencies' }
// Can be removed post-release - used to get nightly snapshot build.
maven { url 'https://download.corda.net/maven/corda-releases' }
maven { url 'https://download.corda.net/maven/corda-lib' }
maven { url 'https://download.corda.net/maven/corda-lib-dev' }
maven { url 'https://jitpack.io' }
maven { url "https://repo.gradle.org/gradle/libs-releases-local" }
}

java {
sourceCompatibility = VERSION_17
targetCompatibility = VERSION_17
}

compileJava {
options.compilerArgs << '-parameters'
}

jar {
// This makes the JAR's SHA-256 hash repeatable.
preserveFileTimestamps = false
reproducibleFileOrder = true
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}

apply plugin: 'net.corda.plugins.cordapp'
apply plugin: 'net.corda.plugins.cordformation'
apply plugin: 'net.corda.plugins.quasar-utils'

sourceSets {
main {
resources {
srcDir rootProject.file("config/dev")
}
}
}

dependencies {
// Corda dependencies.
cordaProvided "$corda_core_release_group:corda-core:$corda_core_release_version"
cordaBootstrapper ("$corda_enterprise_release_group:corda-node-api:$corda_release_version") {
exclude group: "ch.qos.logback", module: "logback-classic"
}
corda "$corda_enterprise_release_group:corda:$corda_release_version"

// CorDapp dependencies.
cordapp project(":workflows")
cordapp project(":contracts")

cordaProvided "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
cordaProvided "org.apache.logging.log4j:log4j-web:${log4j_version}"
cordaProvided "org.slf4j:jul-to-slf4j:$slf4j_version"
cordaDriver "$corda_enterprise_release_group:corda-shell:$corda_release_version"
}

cordapp {
targetPlatformVersion corda_platform_version.toInteger()
minimumPlatformVersion corda_platform_version.toInteger()
workflow {
name "Negotiation CorDapp"
vendor "Corda Open Source"
licence "Apache License, Version 2.0"
versionId 1
}
}

task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {

nodeDefaults {
cordapp project(':contracts')
cordapp project(':workflows')
runSchemaMigration = true
}

node {
name "O=Notary,L=London,C=GB"
notary = [validating: false]
p2pPort 10002
rpcSettings {
address("localhost:10003")
adminAddress("localhost:10043")
}
}
node {
name "O=PartyA,L=London,C=GB"
p2pPort 10005
rpcSettings {
address("localhost:10006")
adminAddress("localhost:10046")
}
rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]
}
node {
name "O=PartyB,L=New York,C=US"
p2pPort 10008
rpcSettings {
address("localhost:10009")
adminAddress("localhost:10049")
}
rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]
}
}

task installQuasar(type: Copy) {
destinationDir rootProject.file("lib")
from(configurations.quasar) {
rename 'quasar-core(.*).jar', 'quasar.jar'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">

<Properties>
<Property name="log-path">logs</Property>
<Property name="log-name">node-${hostName}</Property>
<Property name="archive">${log-path}/archive</Property>
</Properties>

<ThresholdFilter level="trace"/>

<Appenders>
<Console name="Console-Appender" target="SYSTEM_OUT">
<PatternLayout>
<pattern>
%highlight{%level{length=1} %d{HH:mm:ss} %T %c{1}.%M - %msg%n}{INFO=white,WARN=red,FATAL=bright red blink}
</pattern>>
</PatternLayout>
</Console>

<!-- Will generate up to 10 log files for a given day. During every rollover it will delete
those that are older than 60 days, but keep the most recent 10 GB -->
<RollingFile name="RollingFile-Appender"
fileName="${log-path}/${log-name}.log"
filePattern="${archive}/${log-name}.%d{yyyy-MM-dd}-%i.log.gz">

<PatternLayout pattern="[%-5level] %d{ISO8601}{GMT+0} [%t] %c{1} - %msg%n"/>

<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>

<DefaultRolloverStrategy min="1" max="10">
<Delete basePath="${archive}" maxDepth="1">
<IfFileName glob="${log-name}*.log.gz"/>
<IfLastModified age="60d">
<IfAny>
<IfAccumulatedFileSize exceeds="10 GB"/>
</IfAny>
</IfLastModified>
</Delete>
</DefaultRolloverStrategy>

</RollingFile>
</Appenders>

<Loggers>
<Root level="info">
<AppenderRef ref="Console-Appender"/>
<AppenderRef ref="RollingFile-Appender"/>
</Root>
<Logger name="net.corda" level="info" additivity="false">
<AppenderRef ref="Console-Appender"/>
<AppenderRef ref="RollingFile-Appender"/>
</Logger>
</Loggers>

</Configuration>
Loading