1
+ package com .algorand .algosdk .example ;
2
+
3
+ import com .algorand .algosdk .account .Account ;
4
+ import com .algorand .algosdk .builder .transaction .ApplicationCallTransactionBuilder ;
5
+ import com .algorand .algosdk .builder .transaction .ApplicationBaseTransactionBuilder ;
6
+ import com .algorand .algosdk .crypto .Address ;
7
+ import com .algorand .algosdk .transaction .AppBoxReference ;
8
+ import com .algorand .algosdk .transaction .ResourceRef ;
9
+ import com .algorand .algosdk .transaction .Transaction ;
10
+ import com .algorand .algosdk .util .Encoder ;
11
+
12
+ import java .math .BigInteger ;
13
+ import java .util .Arrays ;
14
+ import java .util .List ;
15
+
16
+ /**
17
+ * Demonstrates the useAccess flag for handling consensus upgrade compatibility.
18
+ *
19
+ * The useAccess flag controls how foreign references are handled:
20
+ * - useAccess=false: Uses legacy fields (accounts, foreignApps, foreignAssets, boxReferences)
21
+ * - useAccess=true: Translates the same references into a unified access field
22
+ *
23
+ * Key insight: You use the SAME builder methods in both modes - just add .useAccess(true)!
24
+ * No API changes needed for migration, making upgrades simple and safe.
25
+ */
26
+ public class UseAccessFlagExample {
27
+
28
+ public static void main (String [] args ) throws Exception {
29
+ Account sender = new Account ();
30
+ Account otherAccount = new Account ();
31
+
32
+ System .out .println ("=== useAccess Flag Examples ===\n " );
33
+ System .out .println ("Shows how easy it is to migrate to access field mode:" );
34
+ System .out .println ("Just add .useAccess(true) - no other code changes needed!\n " );
35
+
36
+ // Example 1: Legacy mode (useAccess=false, default)
37
+ demonstrateLegacyMode (sender , otherAccount );
38
+
39
+ System .out .println ("\n " + "=" .repeat (50 ) + "\n " );
40
+
41
+ // Example 2: Same code with useAccess=true - easy migration!
42
+ demonstrateEasyMigration (sender , otherAccount );
43
+
44
+ System .out .println ("\n " + "=" .repeat (50 ) + "\n " );
45
+
46
+ System .out .println ("\n 🎉 That's it! Migration to access field mode is just one line." );
47
+ System .out .println ("Advanced features like holdings() and locals() are also available with useAccess=true." );
48
+ }
49
+
50
+ private static void demonstrateLegacyMode (Account sender , Account otherAccount ) throws Exception {
51
+ System .out .println ("Example 1: Legacy Mode (useAccess=false)" );
52
+ System .out .println ("-----------------------------------------" );
53
+ System .out .println ("Using standard foreign reference methods with legacy field output" );
54
+
55
+ // Build transaction using foreign reference methods (default behavior)
56
+ Transaction txn = ApplicationCallTransactionBuilder .Builder ()
57
+ .sender (sender .getAddress ())
58
+ .applicationId (12345L )
59
+ .useAccess (false ) // Default mode - puts references in separate fields
60
+ .accounts (Arrays .asList (otherAccount .getAddress ()))
61
+ .foreignApps (Arrays .asList (67890L ))
62
+ .foreignAssets (Arrays .asList (999L ))
63
+ .firstValid (BigInteger .valueOf (1000 ))
64
+ .lastValid (BigInteger .valueOf (2000 ))
65
+ .genesisHash (Encoder .decodeFromBase64 ("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=" ))
66
+ .build ();
67
+
68
+ // Show how references are stored in separate legacy fields
69
+ System .out .printf ("Result: References stored in separate fields%n" );
70
+ System .out .printf (" - accounts: %d entries%n" , txn .accounts .size ());
71
+ System .out .printf (" - foreignApps: %d entries%n" , txn .foreignApps .size ());
72
+ System .out .printf (" - foreignAssets: %d entries%n" , txn .foreignAssets .size ());
73
+ System .out .printf (" - access field: %d entries (empty)%n" , txn .access .size ());
74
+ System .out .println ("✓ Compatible with pre-consensus upgrade networks" );
75
+ }
76
+
77
+ private static void demonstrateEasyMigration (Account sender , Account otherAccount ) throws Exception {
78
+ System .out .println ("Example 2: Easy Migration (useAccess=true)" );
79
+ System .out .println ("-------------------------------------------" );
80
+ System .out .println ("SAME CODE as Example 1 - just add .useAccess(true)!" );
81
+
82
+ // Build transaction using the EXACT SAME builder method calls as Example 1
83
+ // The only difference is useAccess=true, which translates these into access field
84
+ Transaction txn = ApplicationCallTransactionBuilder .Builder ()
85
+ .sender (sender .getAddress ())
86
+ .applicationId (12345L )
87
+ .accounts (Arrays .asList (otherAccount .getAddress ())) // Same as Example 1
88
+ .foreignApps (Arrays .asList (67890L )) // Same as Example 1
89
+ .foreignAssets (Arrays .asList (999L )) // Same as Example 1
90
+ .firstValid (BigInteger .valueOf (1000 ))
91
+ .lastValid (BigInteger .valueOf (2000 ))
92
+ .genesisHash (Encoder .decodeFromBase64 ("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=" ))
93
+ .useAccess (true ) // 🔥 ONLY CHANGE: Add this one line!
94
+ .build ();
95
+
96
+ // Show how the same references are now translated to access field
97
+ System .out .printf ("Result: Same references, different internal format%n" );
98
+ System .out .printf (" - accounts: %d entries (empty - translated to access)%n" , txn .accounts .size ());
99
+ System .out .printf (" - foreignApps: %d entries (empty - translated to access)%n" , txn .foreignApps .size ());
100
+ System .out .printf (" - foreignAssets: %d entries (empty - translated to access)%n" , txn .foreignAssets .size ());
101
+ System .out .printf (" - access field: %d entries (contains all references)%n" , txn .access .size ());
102
+
103
+ System .out .println ("\n 🚀 Migration is just one line: .useAccess(true)" );
104
+ System .out .println ("✓ No API changes required" );
105
+ System .out .println ("✓ Same builder methods work in both modes" );
106
+ System .out .println ("✓ Ready for post-consensus upgrade networks" );
107
+ }
108
+
109
+
110
+
111
+ private static String formatAccessEntry (ResourceRef ref ) {
112
+ if (ref .address != null ) {
113
+ return "Address: " + ref .address .toString ().substring (0 , 10 ) + "..." ;
114
+ }
115
+ if (ref .asset != null ) {
116
+ return "Asset: " + ref .asset ;
117
+ }
118
+ if (ref .app != null ) {
119
+ return "App: " + ref .app ;
120
+ }
121
+ if (ref .holding != null ) {
122
+ return String .format ("Holding: addr_idx=%d, asset_idx=%d" ,
123
+ ref .holding .addressIndex , ref .holding .assetIndex );
124
+ }
125
+ if (ref .locals != null ) {
126
+ return String .format ("Locals: addr_idx=%d, app_idx=%d" ,
127
+ ref .locals .addressIndex , ref .locals .appIndex );
128
+ }
129
+ if (ref .box != null ) {
130
+ return String .format ("Box: app_idx=%d, name='%s'" ,
131
+ ref .box .index , new String (ref .box .name ));
132
+ }
133
+ return "Empty" ;
134
+ }
135
+ }
0 commit comments