5757
5858public class PublishExistingCredential {
5959
60- // ------- Constants ------- //
6160 private static final String REGISTRY_NAME = "CredentialRegistry" ;
62-
63- // Required: Passcode from CreateRandomIdentifier.java
64- private static final String IDENTIFIER_BRAN = System .getenv ("IDENTIFIER_BRAN" );
65-
66- // Required: Identifier name from CreateRandomIdentifier.java
6761 private static final String IDENTIFIER_NAME = "GTReeveClient" ;
68-
62+
6963 public static final String QVI_SCHEMA_SAID = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao" ;
7064 public static final String LE_SCHEMA_SAID = "ENPXp1vQzRF6JwIuS-mp2U8Uf1MoADoP_GqQ62VsDZWY" ;
7165 private static final String VLEI_CARDANO_METADATA_SIGNER_SCHEMA_SAID = "EKU2UWx115nPv1JqWVMCFRn0_EMaME08HrUK5cLuTP89" ;
7266
7367 public static final String SCHEMA_SERVER_URL = "https://cred-issuance.demo.idw-sandboxes.cf-deployments.org/oobi" ;
74- public static final String KERI_URL = "http ://127.0.0.1:3901 " ;
75- public static final String KERI_BOOT_URL = "http ://127.0.0.1:3903 " ;
68+ public static final String KERI_URL = "https ://keria.staging.cardano-foundation.app.reeve.technology " ;
69+ public static final String KERI_BOOT_URL = "https ://keria-boot.staging.cardano-foundation.app.reeve.technology " ;
7670
77- // Schemas
7871 public static final String VLEI_CARDANO_METADATA_SIGNER_SCHEMA_URL = SCHEMA_SERVER_URL + "/" + VLEI_CARDANO_METADATA_SIGNER_SCHEMA_SAID ;
7972 public static final String LE_SCHEMA_URL = SCHEMA_SERVER_URL + "/" + LE_SCHEMA_SAID ;
8073 public static final String QVI_SCHEMA_URL = SCHEMA_SERVER_URL + "/" + QVI_SCHEMA_SAID ;
8174
82- private static final String ISSUER_OOBI = System .getenv ().getOrDefault ("ISSUER_OOBI" , "http://keria:3902/oobi/EPHDURdr576cf2HHjzqA68uqnTse0Pi7eMoDkBvr1-jw/agent/EBvTnpvK02atW3EYBbd4CRaEhzSe5a0V7_xREHxaHviB" );
83-
84- private static final String LEI = System .getenv ().getOrDefault ("LEI" , "5493001KJTIIGC8Y1R12" );
75+ private static final String passcode = System .getenv ().getOrDefault ("PASSCODE" , "" );
76+ private static final String LEI = System .getenv ().getOrDefault ("LEI" , "" );
8577
8678 // Wallet specific constants
87- private static final String mnemonic = System .getenv ().getOrDefault ("MNEMONIC" , "test test test test test test test test test test test test test test test test test test test test test test test sauce " );
88- private static final String NETWORK_TYPE = System .getenv ().getOrDefault ("NETWORK" , "preview " );
79+ private static final String mnemonic = System .getenv ().getOrDefault ("MNEMONIC" , "" );
80+ private static final String NETWORK_TYPE = System .getenv ().getOrDefault ("NETWORK" , "mainnet " );
8981 private static final Network network = getNetwork ();
90- private static final String BLOCKFROST_PROJECT_ID = System .getenv ().getOrDefault ("BLOCKFROST_PROJECT_ID" , "dummy " );
82+ private static final String blockfrostProjectId = System .getenv ().getOrDefault ("BLOCKFROST_PROJECT_ID" , "" );
9183 private static final BackendService backendService = createBackendService ();
9284 private static final QuickTxBuilder QuickTxBuilder = new QuickTxBuilder (backendService );
9385
@@ -105,18 +97,26 @@ private static BackendService createBackendService() {
10597 case "preprod" -> "https://cardano-preprod.blockfrost.io/api/v0/" ;
10698 default -> "https://cardano-preview.blockfrost.io/api/v0/" ;
10799 };
108- return new BFBackendService (baseUrl , BLOCKFROST_PROJECT_ID );
100+ return new BFBackendService (baseUrl , blockfrostProjectId );
109101 }
110102
111103 public static void main (String [] args ) throws Exception {
112- // Validate required environment variables
113- if (IDENTIFIER_BRAN == null || IDENTIFIER_BRAN .isEmpty ()) {
114- System .err .println ("ERROR: IDENTIFIER_BRAN environment variable is required." );
115- System .exit (1 );
116- }
104+ Map <String , String > requiredEnvVars = Map .of (
105+ "PASSCODE" , passcode ,
106+ "LEI" , LEI ,
107+ "MNEMONIC" , mnemonic ,
108+ "BLOCKFROST_PROJECT_ID" , blockfrostProjectId
109+ );
110+
111+ requiredEnvVars .forEach ((name , value ) -> {
112+ if (value == null || value .isEmpty ()) {
113+ System .err .println ("ERROR: " + name + " environment variable is required." );
114+ System .exit (1 );
115+ }
116+ });
117117
118118 // --- SETUP CLIENT WITH EXISTING IDENTIFIER --- //
119- SignifyClient client = KeriUtils .connectClient (KERI_URL , KERI_BOOT_URL , IDENTIFIER_BRAN );
119+ SignifyClient client = KeriUtils .connectClient (KERI_URL , KERI_BOOT_URL , passcode );
120120 KeriUtils .Aid aid = KeriUtils .getExistingAid (client , IDENTIFIER_NAME );
121121
122122 if (aid == null ) {
@@ -129,53 +129,48 @@ public static void main(String[] args) throws Exception {
129129 System .out .println (" OOBI: " + aid .oobi ());
130130 System .out .println ();
131131
132- // Create registry if it doesn't exist
133132 RegistryResult registry = createRegistry (client , aid , REGISTRY_NAME );
134133
135- // Resolve schemas
136134 List <String > schemaUrls = List .of (QVI_SCHEMA_URL , LE_SCHEMA_URL , VLEI_CARDANO_METADATA_SIGNER_SCHEMA_URL );
137135 resolveSchemas (client , schemaUrls );
138-
139- // Add issuer contact
140- getOrCreateContact (client , "issuer" , ISSUER_OOBI );
141136
142137 // Check if credential was already issued
143138 List <Map <String , Object >> existingCredentials = findIssuedCredential (client , aid .prefix (), VLEI_CARDANO_METADATA_SIGNER_SCHEMA_SAID );
144- if (existingCredentials .size () > 0 ) {
145- // Ask user if they want to push existing credential to chain
146- System .out .print ("\n Do you want to push the existing credential to the blockchain? (yes/no): " );
147- String response = System .console () != null ? System .console ().readLine () : new java .util .Scanner (System .in ).nextLine ();
148-
149- if (response != null && (response .equalsIgnoreCase ("yes" ) || response .equalsIgnoreCase ("y" ))) {
150- // Get the credential ID from the first existing credential
151- Map <String , Object > firstCred = existingCredentials .get (0 );
152- Object sadObj = firstCred .get ("sad" );
153-
154- String existingCredId ;
155- if (sadObj instanceof Map ) {
156- existingCredId = (String ) ((Map <String , Object >) sadObj ).get ("d" );
157- } else {
158- existingCredId = (String ) sadObj ;
159- }
160-
161- // Retrieve the full credential
162- Optional <String > credential = client .credentials ().get (existingCredId );
163- if (credential .isPresent ()) {
164- List <Map <String , Object >> cesrData = CESRStreamUtil .parseCESRData (credential .get ());
165- String stripped = strip (cesrData );
166- // Build and submit transaction
167- buildTransaction (aid .prefix (), stripped .getBytes (), VLEI_CARDANO_METADATA_SIGNER_SCHEMA_SAID , LEI );
168- System .exit (1 );
169- } else {
170- System .err .println ("ERROR: Could not retrieve full credential data for ID: " + existingCredId );
171- System .exit (1 );
172- }
173- } else {
174- System .out .println ("Skipping blockchain push for existing credential." );
175- System .exit (1 );
176- }
177- } else {
139+
140+ if (existingCredentials .size () == 0 ) {
178141 System .out .println ("No existing credential found." );
142+ System .exit (1 );
143+ }
144+
145+ // Ask user if they want to push existing credential to chain
146+ System .out .print ("\n Do you want to push the existing credential to the blockchain? (yes/no): " );
147+ String response = System .console () != null ? System .console ().readLine () : new java .util .Scanner (System .in ).nextLine ();
148+
149+ if (response == null || (!response .equalsIgnoreCase ("yes" ) && !response .equalsIgnoreCase ("y" ))) {
150+ System .out .println ("Skipping blockchain push for existing credential." );
151+ System .exit (0 );
152+ }
153+
154+ // Get the credential ID from the first existing credential
155+ Map <String , Object > firstCred = existingCredentials .get (0 );
156+ Object sadObj = firstCred .get ("sad" );
157+
158+ String existingCredId ;
159+ if (sadObj instanceof Map ) {
160+ existingCredId = (String ) ((Map <String , Object >) sadObj ).get ("d" );
161+ } else {
162+ existingCredId = (String ) sadObj ;
163+ }
164+
165+ // Retrieve the full credential
166+ Optional <String > credential = client .credentials ().get (existingCredId );
167+ if (credential .isPresent ()) {
168+ List <Map <String , Object >> cesrData = CESRStreamUtil .parseCESRData (credential .get ());
169+ String stripped = strip (cesrData );
170+ // Build and submit transaction
171+ buildTransaction (aid .prefix (), stripped .getBytes (), VLEI_CARDANO_METADATA_SIGNER_SCHEMA_SAID , LEI );
172+ } else {
173+ System .err .println ("ERROR: Could not retrieve full credential data for ID: " + existingCredId );
179174 }
180175 }
181176
@@ -266,24 +261,6 @@ static void buildTransaction(String aid, byte[] credentialChain, String saidOfLe
266261 TxResult txResult = QuickTxBuilder .compose (tx )
267262 .withSigner (SignerProviders .signerFrom (account ))
268263 .feePayer (account .baseAddress ())
269- .postBalanceTx ((context , txn ) -> {
270- // Adjust fee AFTER balancing to account for metadata
271- BigInteger currentFee = txn .getBody ().getFee ();
272- BigInteger adjustedFee = new BigInteger ("390000" ); // Slightly more than required
273-
274- // Calculate the difference to adjust the change output
275- BigInteger feeDiff = adjustedFee .subtract (currentFee );
276-
277- // Update fee
278- txn .getBody ().setFee (adjustedFee );
279-
280- // Adjust the first output (change back to sender) to compensate
281- if (!txn .getBody ().getOutputs ().isEmpty ()) {
282- var output = txn .getBody ().getOutputs ().get (0 );
283- BigInteger currentAmount = output .getValue ().getCoin ();
284- output .getValue ().setCoin (currentAmount .subtract (feeDiff ));
285- }
286- })
287264 .completeAndWait ();
288265 System .out .println ("txResult: " + txResult );
289266 System .out .println ("Transaction submitted. Tx Hash: " + txResult .getTxHash ());
@@ -343,18 +320,6 @@ private static void resolveSchemas(SignifyClient client, List<String> schemaUrls
343320 }
344321 }
345322
346- public static void getOrCreateContact (SignifyClient client , String name , String oobi ) throws IOException , InterruptedException , LibsodiumException {
347- List <Contacting .Contact > list = Arrays .asList (client .contacts ().list (null , "alias" , "^" + name + "$" ));
348- if (!list .isEmpty ()) {
349- Contacting .Contact contact = list .getFirst ();
350- if (contact .getOobi ().equals (oobi )) {
351- return ;
352- }
353- }
354- Object op = client .oobis ().resolve (oobi , name );
355- Operation <Object > waitOp = client .operations ().wait (Operation .fromObject (op ));
356- }
357-
358323 private static List <Notification > waitForNotifications (String route ,
359324 SignifyClient client , KeriUtils .Aid aid ) throws IOException , InterruptedException {
360325 int waitTimeMs = 3000 ;
0 commit comments