diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..6d799a05
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt
index 78b27a93..c0319e4f 100644
--- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt
+++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt
@@ -72,18 +72,21 @@ object IssueToken {
@Suspendable
override fun call(): SignedTransaction {
// This is the identity which will be used to issue tokens.
- // We also need a session for the other side.
val me: Party = ourIdentity
- val ownerSession = initiateFlow(owner)
-
- // Notify the recipient that we'll be issuing them a tokens and advise them of anything they must do, e.g.
- // generate a confidential identity for the issuer or sign up for updates for evolvable tokens.
- ownerSession.send(TokenIssuanceNotification(anonymous = anonymous))
-
+
+ // We also need a session for the other side.
+ var ownerSession : FlowSession? = if(me != owner) {
+ // Notify the recipient that we'll be issuing them a tokens and advise them of anything they must do, e.g.
+ // generate a confidential identity for the issuer or sign up for updates for evolvable tokens.
+ val session = initiateFlow(owner)
+ session.send(TokenIssuanceNotification(anonymous = anonymous))
+ session
+ } else null
+
// This is the recipient of the tokens identity.
- val owningParty: AbstractParty = if (anonymous) {
+ val owningParty: AbstractParty = if(ownerSession != null )
subFlow(RequestConfidentialIdentity.Initiator(ownerSession)).party.anonymise()
- } else owner
+ else owner
// Create the issued token. We add this to the commands for grouping.
val issuedToken: IssuedTokenType = token issuedBy me
@@ -118,7 +121,11 @@ object IssueToken {
// Sign the transaction. Only Concrete Parties should be used here.
val stx: SignedTransaction = serviceHub.signInitialTransaction(utx)
// No need to pass in a session as there's no counterparty involved.
- return subFlow(FinalityFlow(transaction = stx, sessions = listOf(ownerSession)))
+ return if(me != owner) {
+ subFlow(FinalityFlow(transaction = stx, sessions = listOf(ownerSession!!)))
+ } else {
+ subFlow(FinalityFlow(transaction = stx, sessions = emptyList()))
+ }
}
}
diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt
index 2e97d38b..4cdcc5e3 100644
--- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt
+++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt
@@ -2,6 +2,7 @@ package com.r3.corda.sdk.token.workflow.flows
import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.sdk.token.contracts.commands.MoveTokenCommand
+import com.r3.corda.sdk.token.contracts.types.TokenPointer
import com.r3.corda.sdk.token.contracts.types.TokenType
import com.r3.corda.sdk.token.contracts.utilities.withNotary
import com.r3.corda.sdk.token.workflow.selection.TokenSelection
@@ -40,7 +41,11 @@ object MoveToken {
val owningParty: AbstractParty = if (anonymous) {
subFlow(RequestConfidentialIdentity.Initiator(ownerSession)).party.anonymise()
} else owner
-
+
+ if (ownedToken is TokenPointer<*>) {
+ subFlow(AddPartyToDistributionList(owner, ownedToken.pointer.pointer))
+ }
+
val (builder, keys) = if (amount == null) {
// The assumption here is that there is only one owned token of a particular type at any one time.
// Double clarify this in the docs to ensure that it is used properly. Either way, this code likely
diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt
index 810ae266..295c681f 100644
--- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt
+++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt
@@ -33,8 +33,15 @@ class UpdateEvolvableToken(
val stx: SignedTransaction = serviceHub.signInitialTransaction(utx)
// Get the list of parties on the distribution list for this evolvable token.
val updateSubscribers: List = getDistributionList(serviceHub, new.linearId)
- val sessions = updateSubscribers.map { initiateFlow(it.party) }
- // Send to all on the list. This could take a while if there are many subscribers!
- return subFlow(FinalityFlow(transaction = stx, sessions = sessions))
+ // If the token is self-issued, subscribers list will contain ourIdentity.
+ // Remove ourIdentity to avoid initiating a session to itself.
+ val filteredList = updateSubscribers.filter { it.party != ourIdentity }
+
+ return if(filteredList.isNotEmpty()){
+ val sessions = filteredList.map { initiateFlow(it.party) }
+ // Send to all on the list. This could take a while if there are many subscribers!
+ subFlow(FinalityFlow(transaction = stx, sessions = sessions))
+ } else
+ subFlow(FinalityFlow(transaction = stx, sessions = emptyList()))
}
}
\ No newline at end of file
diff --git a/workflow/src/test/kotlin/com/r3/corda/sdk/token/workflow/TokenFlowTests.kt b/workflow/src/test/kotlin/com/r3/corda/sdk/token/workflow/TokenFlowTests.kt
index 2ff12e36..3b080130 100644
--- a/workflow/src/test/kotlin/com/r3/corda/sdk/token/workflow/TokenFlowTests.kt
+++ b/workflow/src/test/kotlin/com/r3/corda/sdk/token/workflow/TokenFlowTests.kt
@@ -6,10 +6,12 @@ import com.r3.corda.sdk.token.money.GBP
import com.r3.corda.sdk.token.workflow.statesAndContracts.House
import com.r3.corda.sdk.token.workflow.utilities.getDistributionList
import com.r3.corda.sdk.token.workflow.utilities.getLinearStateById
+import com.r3.corda.sdk.token.workflow.utilities.tokenBalance
import net.corda.core.contracts.LinearState
import net.corda.core.contracts.StateAndRef
import net.corda.core.node.services.queryBy
import net.corda.core.utilities.getOrThrow
+import net.corda.finance.AMOUNT
import net.corda.testing.node.StartedMockNode
import org.junit.Before
import org.junit.Test
@@ -140,5 +142,42 @@ class TokenFlowTests : MockNetworkTest(numberOfNodes = 3) {
val issueTokenB = I.issueTokens(housePointer, A, NOTARY, 50 of housePointer).getOrThrow()
A.watchForTransaction(issueTokenB.id).toCompletableFuture().getOrThrow()
}
-
+
+ @Test
+ fun `create evolvable token, then self issue`() {
+ //This is to test the self issue flow, as the counter party session is not created
+ val house = House("24 Leinster Gardens, Bayswater, London", 900_000.GBP, listOf(I.legalIdentity()))
+ val createTokenTx = I.createEvolvableToken(house, NOTARY.legalIdentity()).getOrThrow()
+ val houseToken: StateAndRef = createTokenTx.singleOutput()
+ val housePointer: TokenPointer = house.toPointer()
+ I.issueTokens(housePointer, I, NOTARY, 1000 of housePointer).getOrThrow()
+ val houseTokenState = I.services.vaultService.queryBy().states.single()
+ assertEquals(houseToken, houseTokenState)
+ val moveTokenTx = I.moveTokens(housePointer, A, 250 of housePointer, anonymous = true).getOrThrow()
+ A.watchForTransaction(moveTokenTx.id).getOrThrow()
+ val issuerTokenBalance = I.services.vaultService.tokenBalance(housePointer)
+ assertEquals(issuerTokenBalance, AMOUNT(750, housePointer))
+ val aPartyTokenBalance = A.services.vaultService.tokenBalance(housePointer)
+ assertEquals(aPartyTokenBalance, AMOUNT(250, housePointer))
+ }
+
+ @Test
+ fun `create evolvable token, then self issue, move and update`() {
+ //This is to test the self issue flow, as the counter party session is not created
+ val house = House("24 Leinster Gardens, Bayswater, London", 900_000.GBP, listOf(I.legalIdentity()))
+ val createTokenTx = I.createEvolvableToken(house, NOTARY.legalIdentity()).getOrThrow()
+ val houseToken: StateAndRef = createTokenTx.singleOutput()
+ val housePointer: TokenPointer = house.toPointer()
+ I.issueTokens(housePointer, I, NOTARY, 1000 of housePointer).getOrThrow()
+ val houseTokenState = I.services.vaultService.queryBy().states.single()
+ assertEquals(houseToken, houseTokenState)
+ val moveTokenTx = I.moveTokens(housePointer, A, 250 of housePointer, anonymous = true).getOrThrow()
+ A.watchForTransaction(moveTokenTx.id).getOrThrow()
+ val proposedToken = house.copy(valuation = 950_000.GBP)
+ val updateTx = I.updateEvolvableToken(houseToken, proposedToken).getOrThrow()
+ A.watchForTransaction(updateTx.id).getOrThrow()
+ val houseQuery= A.services.vaultService.queryBy().states
+ val updatedHouse = houseQuery.single().state.data
+ assertEquals(updatedHouse.valuation, proposedToken.valuation)
+ }
}
\ No newline at end of file