18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | Copyright 2016, R3 Limited.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # CorDapp Template - Kotlin
6 |
7 | Welcome to the Kotlin CorDapp template. The CorDapp template is a stubbed-out CorDapp that you can use to bootstrap
8 | your own CorDapps.
9 |
10 | **This is the Kotlin version of the CorDapp template. The Java equivalent is
11 | [here](https://github.com/corda/cordapp-template-java/).**
12 |
13 | # Pre-Requisites
14 |
15 | See https://docs.corda.net/getting-set-up.html.
16 |
17 | # Usage
18 |
19 | ## Running tests inside IntelliJ
20 |
21 | We recommend editing your IntelliJ preferences so that you use the Gradle runner - this means that the quasar utils
22 | plugin will make sure that some flags (like ``-javaagent`` - see below) are
23 | set for you.
24 |
25 | To switch to using the Gradle runner:
26 |
27 | * Navigate to ``Build, Execution, Deployment -> Build Tools -> Gradle -> Runner`` (or search for `runner`)
28 | * Windows: this is in "Settings"
29 | * MacOS: this is in "Preferences"
30 | * Set "Delegate IDE build/run actions to gradle" to true
31 | * Set "Run test using:" to "Gradle Test Runner"
32 |
33 | If you would prefer to use the built in IntelliJ JUnit test runner, you can run ``gradlew installQuasar`` which will
34 | copy your quasar JAR file to the lib directory. You will then need to specify ``-javaagent:lib/quasar.jar``
35 | and set the run directory to the project root directory for each test.
36 |
37 | ## Running the nodes
38 |
39 | See https://docs.corda.net/tutorial-cordapp.html#running-the-example-cordapp.
40 |
41 | ## Interacting with the nodes
42 |
43 | ### Shell
44 |
45 | When started via the command line, each node will display an interactive shell:
46 |
47 | Welcome to the Corda interactive shell.
48 | Useful commands include 'help' to see what is available, and 'bye' to shut down the node.
49 |
50 | Tue Nov 06 11:58:13 GMT 2018>>>
51 |
52 | You can use this shell to interact with your node. For example, enter `run networkMapSnapshot` to see a list of
53 | the other nodes on the network:
54 |
55 | Tue Nov 06 11:58:13 GMT 2018>>> run networkMapSnapshot
56 | [
57 | {
58 | "addresses" : [ "localhost:10002" ],
59 | "legalIdentitiesAndCerts" : [ "O=Notary, L=London, C=GB" ],
60 | "platformVersion" : 3,
61 | "serial" : 1541505484825
62 | },
63 | {
64 | "addresses" : [ "localhost:10005" ],
65 | "legalIdentitiesAndCerts" : [ "O=PartyA, L=London, C=GB" ],
66 | "platformVersion" : 3,
67 | "serial" : 1541505382560
68 | },
69 | {
70 | "addresses" : [ "localhost:10008" ],
71 | "legalIdentitiesAndCerts" : [ "O=PartyB, L=New York, C=US" ],
72 | "platformVersion" : 3,
73 | "serial" : 1541505384742
74 | }
75 | ]
76 |
77 | Tue Nov 06 12:30:11 GMT 2018>>>
78 |
79 | You can find out more about the node shell [here](https://docs.corda.net/shell.html).
80 |
81 | ### Client
82 |
83 | `clients/src/main/kotlin/com/template/Client.kt` defines a simple command-line client that connects to a node via RPC
84 | and prints a list of the other nodes on the network.
85 |
86 | #### Running the client
87 |
88 | ##### Via the command line
89 |
90 | Run the `runTemplateClient` Gradle task. By default, it connects to the node with RPC address `localhost:10006` with
91 | the username `user1` and the password `test`.
92 |
93 | ##### Via IntelliJ
94 |
95 | Run the `Run Template Client` run configuration. By default, it connects to the node with RPC address `localhost:10006`
96 | with the username `user1` and the password `test`.
97 |
98 | ### Webserver
99 |
100 | `clients/src/main/kotlin/com/template/webserver/` defines a simple Spring webserver that connects to a node via RPC and
101 | allows you to interact with the node over HTTP.
102 |
103 | The API endpoints are defined here:
104 |
105 | clients/src/main/kotlin/com/template/webserver/Controller.kt
106 |
107 | And a static webpage is defined here:
108 |
109 | clients/src/main/resources/static/
110 |
111 | #### Running the webserver
112 |
113 | ##### Via the command line
114 |
115 | Run the `runTemplateServer` Gradle task. By default, it connects to the node with RPC address `localhost:10006` with
116 | the username `user1` and the password `test`, and serves the webserver on port `localhost:10050`.
117 |
118 | ##### Via IntelliJ
119 |
120 | Run the `Run Template Server` run configuration. By default, it connects to the node with RPC address `localhost:10006`
121 | with the username `user1` and the password `test`, and serves the webserver on port `localhost:10050`.
122 |
123 | #### Interacting with the webserver
124 |
125 | The static webpage is served on:
126 |
127 | http://localhost:10050
128 |
129 | While the sole template endpoint is served on:
130 |
131 | http://localhost:10050/templateendpoint
132 |
133 | # Extending the template
134 |
135 | You should extend this template as follows:
136 |
137 | * Add your own state and contract definitions under `contracts/src/main/kotlin/`
138 | * Add your own flow definitions under `workflows/src/main/kotlin/`
139 | * Extend or replace the client and webserver under `clients/src/main/kotlin/`
140 |
141 | For a guided example of how to extend this template, see the Hello, World! tutorial
142 | [here](https://docs.corda.net/hello-world-introduction.html).
143 |
--------------------------------------------------------------------------------
/TRADEMARK:
--------------------------------------------------------------------------------
1 | Corda and the Corda logo are trademarks of R3CEV LLC and its affiliates. All rights reserved.
2 |
3 | For R3CEV LLC's trademark and logo usage information, please consult our Trademark Usage Policy at
4 | https://www.r3.com/trademark-policy/.
5 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | import static org.gradle.api.JavaVersion.VERSION_17
2 |
3 | buildscript { //properties that you need to build the project
4 |
5 | Properties constants = new Properties()
6 | file("$projectDir/./constants.properties").withInputStream { constants.load(it) }
7 |
8 | ext {
9 | corda_release_group = constants.getProperty("cordaReleaseGroup")
10 | corda_core_release_group = constants.getProperty("cordaCoreReleaseGroup")
11 | corda_release_version = constants.getProperty("cordaVersion")
12 | corda_core_release_version = constants.getProperty("cordaCoreVersion")
13 | corda_gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
14 | kotlin_version = constants.getProperty("kotlinVersion")
15 | junit_version = constants.getProperty("junitVersion")
16 | quasar_version = constants.getProperty("quasarVersion")
17 | log4j_version = constants.getProperty("log4jVersion")
18 | slf4j_version = constants.getProperty("slf4jVersion")
19 | hibernate_version = constants.getProperty("hibernateVersion")
20 | corda_platform_version = constants.getProperty("platformVersion").toInteger()
21 | snappy_version = constants.getProperty("snappyVersion")
22 | //springboot
23 | spring_boot_version = '3.2.5'
24 | spring_boot_gradle_plugin_version = '3.2.5'
25 |
26 | test_add_opens = ['--add-opens', 'java.base/java.time=ALL-UNNAMED', '--add-opens', 'java.base/java.io=ALL-UNNAMED',
27 | '--add-opens', 'java.base/java.util=ALL-UNNAMED', '--add-opens', 'java.base/java.net=ALL-UNNAMED',
28 | '--add-opens', 'java.base/java.nio=ALL-UNNAMED', '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED',
29 | '--add-opens', 'java.base/java.security.cert=ALL-UNNAMED', '--add-opens', 'java.base/java.security=ALL-UNNAMED',
30 | '--add-opens', 'java.base/javax.net.ssl=ALL-UNNAMED', '--add-opens', 'java.base/java.lang=ALL-UNNAMED',
31 | '--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED', '--add-opens', 'java.sql/java.sql=ALL-UNNAMED',]
32 |
33 | test_add_opens_fx = [ '--add-exports', 'java.base/sun.nio.ch=ALL-UNNAMED',
34 | '--add-exports', 'javafx.base/com.sun.javafx=ALL-UNNAMED',
35 | '--add-exports', 'javafx.base/com.sun.javafx.collections=ALL-UNNAMED']
36 | }
37 |
38 | repositories {
39 | mavenLocal()
40 | mavenCentral()
41 | maven { url 'https://download.corda.net/maven/corda-dependencies' }
42 | maven { url 'https://download.corda.net/maven/corda-releases' }
43 | maven { url 'https://download.corda.net/maven/corda-dev' }
44 | }
45 |
46 | dependencies {
47 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
48 | classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
49 | classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version"
50 | classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version"
51 | classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_gradle_plugin_version"
52 | }
53 | }
54 |
55 | allprojects { //Properties that you need to compile your project (The application)
56 | apply from: "${rootProject.projectDir}/repositories.gradle"
57 | apply plugin: 'kotlin'
58 |
59 | repositories {
60 | mavenLocal()
61 | mavenCentral()
62 | maven { url 'https://download.corda.net/maven/corda-dependencies' }
63 | maven { url 'https://download.corda.net/maven/corda-releases' }
64 | maven { url 'https://jitpack.io' }
65 | }
66 |
67 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
68 | kotlinOptions {
69 | languageVersion = "1.9"
70 | apiVersion = "1.9"
71 | jvmTarget = VERSION_17
72 | javaParameters = true // Useful for reflection.
73 | }
74 | }
75 |
76 | jar {
77 | // This makes the JAR's SHA-256 hash repeatable.
78 | preserveFileTimestamps = false
79 | reproducibleFileOrder = true
80 | }
81 | }
82 |
83 | apply plugin: 'net.corda.plugins.cordapp'
84 | apply plugin: 'net.corda.plugins.cordformation'
85 | apply plugin: 'net.corda.plugins.quasar-utils'
86 |
87 | sourceSets {
88 | main {
89 | resources {
90 | srcDir rootProject.file("config/dev")
91 | }
92 | }
93 | }
94 |
95 | //Module dependencis
96 | dependencies {
97 | // Corda dependencies.
98 | cordaProvided "$corda_core_release_group:corda-core:$corda_core_release_version"
99 | cordaBootstrapper ("$corda_release_group:corda-node-api:$corda_release_version") {
100 | exclude group: "ch.qos.logback", module: "logback-classic"
101 | }
102 | corda "$corda_release_group:corda:$corda_release_version"
103 |
104 | // CorDapp dependencies.
105 | cordapp project(":workflows")
106 | cordapp project(":contracts")
107 |
108 | cordaProvided "org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}"
109 | cordaProvided "org.apache.logging.log4j:log4j-web:${log4j_version}"
110 | cordaProvided "org.slf4j:jul-to-slf4j:$slf4j_version"
111 | cordaDriver "net.corda:corda-shell:$corda_release_version"
112 | }
113 |
114 | cordapp {
115 | targetPlatformVersion corda_platform_version.toInteger()
116 | }
117 |
118 | //Task to deploy the nodes in order to bootstrap a network
119 | task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
120 |
121 | /* This property will load the CorDapps to each of the node by default, including the Notary. You can find them
122 | * in the cordapps folder of the node at build/nodes/Notary/cordapps. However, the notary doesn't really understand
123 | * the notion of cordapps. In production, Notary does not need cordapps as well. This is just a short cut to load
124 | * the Corda network bootstrapper.
125 | */
126 | nodeDefaults {
127 | projectCordapp {
128 | deploy = false
129 | }
130 | cordapp project(':contracts')
131 | cordapp project(':workflows')
132 | runSchemaMigration = true //This configuration is for any CorDapps with custom schema, We will leave this as true to avoid
133 | //problems for developers who are not familiar with Corda. If you are not using custom schemas, you can change
134 | //it to false for quicker project compiling time.
135 | }
136 | node {
137 | name "O=Notary,L=London,C=GB"
138 | notary = [validating : false]
139 | p2pPort 10002
140 | rpcSettings {
141 | address("localhost:10003")
142 | adminAddress("localhost:10043")
143 | }
144 | }
145 | node {
146 | name "O=PartyA,L=London,C=GB"
147 | p2pPort 10005
148 | rpcSettings {
149 | address("localhost:10006")
150 | adminAddress("localhost:10046")
151 | }
152 | rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
153 | }
154 | node {
155 | name "O=PartyB,L=New York,C=US"
156 | p2pPort 10008
157 | rpcSettings {
158 | address("localhost:10009")
159 | adminAddress("localhost:10049")
160 | }
161 | rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/clients/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'org.springframework.boot'
2 |
3 | sourceSets {
4 | main {
5 | resources {
6 | srcDir rootProject.file("config/dev")
7 | }
8 | }
9 | }
10 |
11 | dependencies {
12 | // Corda dependencies.
13 | implementation "$corda_core_release_group:corda-core:$corda_core_release_version"
14 | implementation "$corda_release_group:corda-rpc:$corda_release_version"
15 |
16 | // CorDapp dependencies.
17 | implementation project(":contracts")
18 | implementation project(":workflows")
19 | implementation("org.springframework.boot:spring-boot-starter-websocket:$spring_boot_version") {
20 | exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
21 | }
22 | implementation "org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}"
23 | implementation "org.apache.logging.log4j:log4j-web:${log4j_version}"
24 | implementation "org.slf4j:jul-to-slf4j:$slf4j_version"
25 | }
26 |
27 | springBoot {
28 | mainClass = "com.template.webserver.ServerKt"
29 | }
30 |
31 | /* The Client is the communication channel between the external and the node. This task will help you immediately
32 | * execute your rpc methods in the main method of the client.kt. You can somewhat see this as a quick test of making
33 | * RPC calls to your nodes.
34 | */
35 | task runTemplateClient(type: JavaExec, dependsOn: assemble) {
36 | classpath = sourceSets.main.runtimeClasspath
37 | main = 'com.template.ClientKt'
38 | args 'localhost:10006', 'user1', 'test'
39 | }
40 |
41 | /* This task will start the springboot server that connects to your node (via RPC connection). All of the http requests
42 | * are in the Controller file. You can leave the Server.kt and NodeRPCConnection.kt file untouched for your use.
43 | */
44 | task runTemplateServer(type: JavaExec, dependsOn: assemble) {
45 | classpath = sourceSets.main.runtimeClasspath
46 | main = 'com.template.webserver.ServerKt'
47 | args '--server.port=10050', '--config.rpc.host=localhost', '--config.rpc.port=10006', '--config.rpc.username=user1', '--config.rpc.password=test'
48 | }
--------------------------------------------------------------------------------
/clients/src/main/kotlin/com/template/Client.kt:
--------------------------------------------------------------------------------
1 | package com.template
2 |
3 | import net.corda.client.rpc.CordaRPCClient
4 | import net.corda.core.utilities.NetworkHostAndPort.Companion.parse
5 | import net.corda.core.utilities.loggerFor
6 |
7 | /**
8 | * Connects to a Corda node via RPC and performs RPC operations on the node.
9 | *
10 | * The RPC connection is configured using command line arguments.
11 | */
12 | fun main(args: Array) = Client().main(args)
13 |
14 | private class Client {
15 | companion object {
16 | val logger = loggerFor()
17 | }
18 |
19 | fun main(args: Array) {
20 | // Create an RPC connection to the node.
21 | require(args.size == 3) { "Usage: Client " }
22 | val nodeAddress = parse(args[0])
23 | val rpcUsername = args[1]
24 | val rpcPassword = args[2]
25 | val client = CordaRPCClient(nodeAddress)
26 | val clientConnection = client.start(rpcUsername, rpcPassword)
27 | val proxy = clientConnection.proxy
28 |
29 | // Interact with the node.
30 | // Example #1, here we print the nodes on the network.
31 | val nodes = proxy.networkMapSnapshot()
32 | println("\n-- Here is the networkMap snapshot --")
33 | logger.info("{}", nodes)
34 |
35 | // Example #2, here we print the PartyA's node info
36 | val me = proxy.nodeInfo().legalIdentities.first().name
37 | println("\n-- Here is the node info of the node that the client connected to --")
38 | logger.info("{}", me)
39 |
40 | //Close the client connection
41 | clientConnection.close()
42 | }
43 | }
--------------------------------------------------------------------------------
/clients/src/main/kotlin/com/template/webserver/Controller.kt:
--------------------------------------------------------------------------------
1 | package com.template.webserver
2 |
3 | import org.slf4j.LoggerFactory
4 | import org.springframework.web.bind.annotation.GetMapping
5 | import org.springframework.web.bind.annotation.RequestMapping
6 | import org.springframework.web.bind.annotation.RestController
7 |
8 | /**
9 | * Define your API endpoints here.
10 | */
11 | @RestController
12 | @RequestMapping("/") // The paths for HTTP requests are relative to this base path.
13 | class Controller(rpc: NodeRPCConnection) {
14 |
15 | companion object {
16 | private val logger = LoggerFactory.getLogger(RestController::class.java)
17 | }
18 |
19 | private val proxy = rpc.proxy
20 |
21 | @GetMapping(value = ["/templateendpoint"], produces = ["text/plain"])
22 | private fun templateendpoint(): String {
23 | return "Define an endpoint here."
24 | }
25 | }
--------------------------------------------------------------------------------
/clients/src/main/kotlin/com/template/webserver/NodeRPCConnection.kt:
--------------------------------------------------------------------------------
1 | package com.template.webserver
2 |
3 | import net.corda.client.rpc.CordaRPCClient
4 | import net.corda.client.rpc.CordaRPCConnection
5 | import net.corda.core.messaging.CordaRPCOps
6 | import net.corda.core.utilities.NetworkHostAndPort
7 | import org.springframework.beans.factory.annotation.Value
8 | import org.springframework.stereotype.Component
9 | import jakarta.annotation.PostConstruct
10 | import jakarta.annotation.PreDestroy
11 |
12 | private const val CORDA_USER_NAME = "config.rpc.username"
13 | private const val CORDA_USER_PASSWORD = "config.rpc.password"
14 | private const val CORDA_NODE_HOST = "config.rpc.host"
15 | private const val CORDA_RPC_PORT = "config.rpc.port"
16 |
17 | /**
18 | * Wraps an RPC connection to a Corda node.
19 | *
20 | * The RPC connection is configured using command line arguments.
21 | *
22 | * @param host The host of the node we are connecting to.
23 | * @param rpcPort The RPC port of the node we are connecting to.
24 | * @param username The username for logging into the RPC client.
25 | * @param password The password for logging into the RPC client.
26 | * @property proxy The RPC proxy.
27 | */
28 | @Component
29 | open class NodeRPCConnection(
30 | @Value("\${$CORDA_NODE_HOST}") private val host: String,
31 | @Value("\${$CORDA_USER_NAME}") private val username: String,
32 | @Value("\${$CORDA_USER_PASSWORD}") private val password: String,
33 | @Value("\${$CORDA_RPC_PORT}") private val rpcPort: Int): AutoCloseable {
34 |
35 | lateinit var rpcConnection: CordaRPCConnection
36 | private set
37 | lateinit var proxy: CordaRPCOps
38 | private set
39 |
40 | @PostConstruct
41 | fun initialiseNodeRPCConnection() {
42 | val rpcAddress = NetworkHostAndPort(host, rpcPort)
43 | val rpcClient = CordaRPCClient(rpcAddress)
44 | val rpcConnection = rpcClient.start(username, password)
45 | proxy = rpcConnection.proxy
46 | }
47 |
48 | @PreDestroy
49 | override fun close() {
50 | rpcConnection.notifyServerAndClose()
51 | }
52 | }
--------------------------------------------------------------------------------
/clients/src/main/kotlin/com/template/webserver/Server.kt:
--------------------------------------------------------------------------------
1 | package com.template.webserver
2 |
3 | import org.springframework.boot.Banner
4 | import org.springframework.boot.SpringApplication
5 | import org.springframework.boot.WebApplicationType.SERVLET
6 | import org.springframework.boot.autoconfigure.SpringBootApplication
7 |
8 | /**
9 | * Our Spring Boot application.
10 | */
11 | @SpringBootApplication
12 | private open class Starter
13 |
14 | /**
15 | * Starts our Spring Boot application.
16 | */
17 | fun main(args: Array) {
18 | val app = SpringApplication(Starter::class.java)
19 | app.setBannerMode(Banner.Mode.OFF)
20 | app.webApplicationType = SERVLET
21 | app.run(*args)
22 | }
23 |
--------------------------------------------------------------------------------
/clients/src/main/resources/static/app.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // Define your client-side logic here.
--------------------------------------------------------------------------------
/clients/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Example front-end.
6 |
7 |
8 |
9 |
10 |
CorDapp Template (Kotlin Version)
11 |
Learn more about how to build CorDapps at sample-kotlin