11package com .template .contracts ;
22
3+ import com .google .common .collect .ImmutableList ;
4+ import com .template .states .Avatar ;
5+ import com .template .states .Expiry ;
6+ import net .corda .core .identity .CordaX500Name ;
7+ import net .corda .testing .core .TestIdentity ;
38import net .corda .testing .node .MockServices ;
49import org .junit .Test ;
510
11+ import java .time .Duration ;
12+ import java .time .Instant ;
13+ import java .time .temporal .ChronoUnit ;
14+
15+ import static net .corda .testing .node .NodeTestUtils .ledger ;
16+
617public class ContractTests {
7- private final MockServices ledgerServices = new MockServices ();
818
19+ static private final MockServices ledgerServices = new MockServices ();
20+ static private final TestIdentity seller = new TestIdentity (new CordaX500Name ("MegaCorp" , "London" , "GB" ));
21+ static private final TestIdentity buyer = new TestIdentity (new CordaX500Name ("MiniCorp" , "London" , "GB" ));
22+
23+
24+ //Both the encumbrance and the encumbered state must be added to the transaction
25+ @ Test
26+ public void thereMustBeTwoOutputs () {
27+ ledger (ledgerServices , (ledger -> {
28+ ledger .transaction (tx -> {
29+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , new Avatar (seller .getParty (), "1" ));
30+ tx .command (ImmutableList .of (seller .getPublicKey ()), new AvatarContract .Commands .Create ());
31+ tx .fails ();
32+ return null ;
33+ });
34+ return null ;
35+ }));
36+ }
37+
38+
39+ @ Test
40+ public void encumbranceIndexMustBeSpecified () {
41+ //not specifying the encumbrance index fails the contract
42+ ledger (ledgerServices , (ledger -> {
43+ ledger .transaction (tx -> {
44+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , new Avatar (seller .getParty (), "1" ));
45+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID ,
46+ new Expiry (Instant .now ().plus (2 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
47+ tx .command (ImmutableList .of (seller .getPublicKey ()), new AvatarContract .Commands .Create ());
48+ tx .timeWindow (Instant .now (), Duration .ofMinutes (1 ));
49+ tx .failsWith ("Avatar needs to be encumbered" );
50+
51+ return null ;
52+ });
53+ return null ;
54+ }));
55+
56+ //specifying the encumbrance index while adding output states passes the contract
57+ ledger (ledgerServices , (ledger -> {
58+ ledger .transaction (tx -> {
59+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , 1 , new Avatar (seller .getParty (), "1" ));
60+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID , 0 ,
61+ new Expiry (Instant .now ().plus (2 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
62+ tx .command (ImmutableList .of (seller .getPublicKey ()), new AvatarContract .Commands .Create ());
63+ tx .timeWindow (Instant .now (), Duration .ofMinutes (1 ));
64+ tx .verifies ();
65+ return null ;
66+ });
67+ return null ;
68+ }));
69+ }
70+
71+ //Specifying time window is mandatory. This is checked in the encumbrance Expiry state.
972 @ Test
10- public void dummyTest () {
73+ public void specifyTimeWindow () {
74+ ledger (ledgerServices , (ledger -> {
75+ ledger .transaction (tx -> {
76+ //this fails as time window is not specified
77+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , new Avatar (seller .getParty (), "1" ));
78+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID ,
79+ new Expiry (Instant .now ().plus (2 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
80+ tx .command (ImmutableList .of (seller .getPublicKey ()), new AvatarContract .Commands .Create ());
81+ tx .fails ();
1182
83+ //this will pass once we specify time window
84+ tx .timeWindow (Instant .now (), Duration .ofMinutes (1 ));
85+ return tx .verifies ();
86+ });
87+ return null ;
88+ }));
89+ }
90+
91+ //For selling, the Expiry of avatar must be greater than the time window
92+ @ Test
93+ public void avatarIsRejectedIfItIsExpired () {
94+ ledger (ledgerServices , (ledger -> {
95+ ledger .transaction (tx -> {
96+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , new Avatar (seller .getParty (), "1" ));
97+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID ,
98+ new Expiry (Instant .now ().plus (2 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
99+ tx .command (ImmutableList .of (seller .getPublicKey ()), new AvatarContract .Commands .Create ());
100+ tx .timeWindow (Instant .now (), Duration .ofMinutes (3 ));
101+ tx .fails ();
102+ return null ;
103+ });
104+ return null ;
105+ }));
106+ }
107+
108+ //For selling, the Expiry of avatar must be greater than the time window
109+ @ Test
110+ public void expirationDateShouldBeAfterTheTimeWindow () {
111+ ledger (ledgerServices , (ledger -> {
112+ ledger .transaction (tx -> {
113+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , new Avatar (seller .getParty (), "1" ));
114+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID ,
115+ new Expiry (Instant .now ().plus (3 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
116+ tx .command (ImmutableList .of (seller .getPublicKey ()), new AvatarContract .Commands .Create ());
117+ tx .timeWindow (Instant .now (), Duration .ofMinutes (2 ));
118+ tx .verifies ();
119+ return null ;
120+ });
121+ return null ;
122+ }));
123+ }
124+
125+ //test transaction which has encumbered states as inputs
126+ @ Test
127+ public void transferAvatar () {
128+ ledger (ledgerServices , ledger -> {
129+ ledger .unverifiedTransaction (tx -> {
130+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , "avatarLabel" , 1 ,
131+ new Avatar (seller .getParty (), "1" ));
132+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID , "expiryLabel" , 0 ,
133+ new Expiry (Instant .now ().plus (3 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
134+ return null ;
135+ });
136+ ledger .transaction (tx -> {
137+ tx .input ("avatarLabel" );
138+ tx .input ("expiryLabel" );
139+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , "avatarLabel2" , 1 ,
140+ new Avatar (buyer .getParty (), "1" ));
141+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID , "expiryLabel2" , 0 ,
142+ new Expiry (Instant .now ().plus (3 , ChronoUnit .MINUTES ), "1" , buyer .getParty ()));
143+ tx .command (ImmutableList .of (seller .getPublicKey (), buyer .getPublicKey ()), new AvatarContract .Commands .Transfer ());
144+ tx .command (ImmutableList .of (seller .getPublicKey (), buyer .getPublicKey ()), new ExpiryContract .Commands .Pass ());
145+ tx .timeWindow (Instant .now (), Duration .ofMinutes (2 ));
146+ tx .verifies ();
147+ return null ;
148+ });
149+ return null ;
150+ });
151+ }
152+
153+
154+ @ Test
155+ public void avatarCannotBeSpentWithoutExpiry () {
156+ ledger (ledgerServices , ledger -> {
157+ ledger .unverifiedTransaction (tx -> {
158+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , "avatarLabel" , 1 ,
159+ new Avatar (seller .getParty (), "1" ));
160+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID , "expiryLabel" , 0 ,
161+ new Expiry (Instant .now ().plus (3 , ChronoUnit .MINUTES ), "1" , seller .getParty ()));
162+ return null ;
163+ });
164+ ledger .transaction (tx -> {
165+ tx .input ("avatarLabel" );
166+ // tx.input(expiryLabel);
167+ tx .output (AvatarContract .AVATAR_CONTRACT_ID , "avatarLabel2" , 1 ,
168+ new Avatar (buyer .getParty (), "1" ));
169+ tx .output (ExpiryContract .EXPIRY_CONTRACT_ID , "expiryLabel2" , 0 ,
170+ new Expiry (Instant .now ().plus (3 , ChronoUnit .MINUTES ), "1" , buyer .getParty ()));
171+ tx .command (ImmutableList .of (seller .getPublicKey (), buyer .getPublicKey ()), new AvatarContract .Commands .Transfer ());
172+ tx .command (ImmutableList .of (seller .getPublicKey (), buyer .getPublicKey ()), new ExpiryContract .Commands .Pass ());
173+ tx .timeWindow (Instant .now (), Duration .ofMinutes (2 ));
174+ tx .fails ();
175+ return null ;
176+ });
177+ return null ;
178+ });
12179 }
13180}
0 commit comments