-
Notifications
You must be signed in to change notification settings - Fork 4
/
MovePrivateCBDCTokenFlow.kt
88 lines (78 loc) · 3.66 KB
/
MovePrivateCBDCTokenFlow.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.example.flow
import co.paralleluniverse.fibers.Suspendable
import com.example.contract.audit.AuditContract
import com.example.contract.token.ExampleTokenContract
import com.example.contract.token.commands.MovePrivate
import com.example.contract.token.ExampleToken
import com.ing.zkflow.client.flows.ZKFinalityFlow
import com.ing.zkflow.client.flows.ZKReceiveFinalityFlow
import com.ing.zkflow.common.transactions.ZKTransactionBuilder
import com.ing.zkflow.common.transactions.signInitialTransaction
import com.ing.zkflow.common.transactions.verification.zkVerify
import net.corda.core.contracts.StateAndRef
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSession
import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.seconds
import java.time.Instant
/**
* Use this flow to move a [ExampleToken] privately.
* Only the current holder and the new holder will be aware of the token's existence,
* and only the new holder will be able to see its private contents in its vault.
*
* This flow should be called by the current holder.
* The token is moved to the holder specified in the output [ExampleToken].
* The holder will receive the token correctly in their vault if they have registered the [MovePrivateExampleTokenFlowFlowHandler].
*
* Optionally, an auditor can be set on this move transaction.
* In that case, an [AuditContract.AuditRecord] will be added to the transaction as a publicly visible output.
* It will contain some metadata about the transaction.
* This auditor will NOT receive the full private transaction data, but only the [ZKVerifierTransaction] with the publicly
* visible components of the transaction.
*/
@InitiatingFlow
class MovePrivateExampleTokenFlow(
private val token: StateAndRef<ExampleToken>,
private val newHolder: AnonymousParty,
private val auditor: Party?
) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val inputState = token.state.data
val builder = ZKTransactionBuilder(serviceHub.networkMapCache.notaryIdentities.single())
.addInputState(token)
.addOutputState(inputState.withNewHolder(newHolder), ExampleTokenContract.ID)
.addCommand(MovePrivate(), inputState.holder.owningKey)
.setTimeWindow(Instant.now(), 100.seconds)
val auditorSessions = mutableListOf<FlowSession>()
if (auditor != null) {
builder.addOutputState(AuditContract.AuditRecord(auditor, "Signer moved less than 25k"), AuditContract.ID)
auditorSessions.add(initiateFlow(auditor))
}
val stx = serviceHub.signInitialTransaction(builder)
stx.zkVerify(serviceHub, checkSufficientSignatures = false)
subFlow(
ZKFinalityFlow(
stx,
// We send the full transaction data, including private data, to the new holder of the token
privateSessions = listOf(initiateFlow(newHolder)),
// If any auditor is set, we send the public transaction data, excluding the private data
publicSessions = auditorSessions
)
)
return stx
}
}
@InitiatedBy(MovePrivateExampleTokenFlow::class)
class MovePrivateExampleTokenFlowFlowHandler(private val otherSession: FlowSession) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
if (!serviceHub.myInfo.isLegalIdentity(otherSession.counterparty)) {
subFlow(ZKReceiveFinalityFlow(otherSession))
}
}
}