66import com .hedera .hashgraph .sdk .TokenId ;
77import com .openelements .hiero .base .HieroException ;
88import com .openelements .hiero .base .data .Nft ;
9- import com .openelements .hiero .base .data .AccountInfo ;
10- import com .openelements .hiero .base .data .ExchangeRate ;
11- import com .openelements .hiero .base .data .ExchangeRates ;
12- import com .openelements .hiero .base .data .NetworkFee ;
13- import com .openelements .hiero .base .data .NetworkStake ;
14- import com .openelements .hiero .base .data .NetworkSupplies ;
15- import com .openelements .hiero .base .data .Nft ;
169import com .openelements .hiero .base .data .NftMetadata ;
1710import com .openelements .hiero .base .data .Page ;
1811import com .openelements .hiero .base .data .TransactionInfo ;
19- import com .openelements .hiero .base .mirrornode .MirrorNodeClient ;
2012import com .openelements .hiero .base .implementation .AbstractMirrorNodeClient ;
2113import com .openelements .hiero .base .implementation .MirrorNodeJsonConverter ;
2214import com .openelements .hiero .base .implementation .MirrorNodeRestClient ;
@@ -103,37 +95,6 @@ public Optional<TransactionInfo> queryTransaction(@NonNull final String transact
10395 return Optional .of (new TransactionInfo (transactionId ));
10496 }
10597
106- @ Override
107- public @ NonNull Optional <AccountInfo > queryAccount (@ NonNull AccountId accountId ) throws HieroException {
108- Objects .requireNonNull (accountId , "accountId must not be null" );
109- final JsonNode jsonNode = doGetCall ("/api/v1/accounts/" + accountId );
110- return jsonNodeToOptionalAccountINfo (jsonNode );
111- }
112-
113- @ Override
114- public @ NonNull Optional <ExchangeRates > queryExchangeRates () throws HieroException {
115- final JsonNode jsonNode = doGetCall ("/api/v1/network/exchangerate" );
116- return jsonNodeToOptionalExchangeRates (jsonNode );
117- }
118-
119- @ Override
120- public @ NonNull List <NetworkFee > queryNetworkFees () throws HieroException {
121- final JsonNode jsonNode = doGetCall ("/api/v1/network/fees" );
122- return jsonNodeToListNetworkFee (jsonNode );
123- }
124-
125- @ Override
126- public @ NonNull Optional <NetworkStake > queryNetworkStake () throws HieroException {
127- final JsonNode jsonNode = doGetCall ("/api/v1/network/stake" );
128- return jsonNodeToOptionalNetworkStake (jsonNode );
129- }
130-
131- @ Override
132- public @ NonNull Optional <NetworkSupplies > queryNetworkSupplies () throws HieroException {
133- final JsonNode jsonNode = doGetCall ("/api/v1/network/supply" );
134- return jsonNodeToOptionalNetworkSupplies (jsonNode );
135- }
136-
13798 @ Override
13899 public @ NonNull NftMetadata getNftMetadata (TokenId tokenId ) throws HieroException {
139100 throw new UnsupportedOperationException ("Not yet implemented" );
@@ -148,276 +109,4 @@ public Optional<TransactionInfo> queryTransaction(@NonNull final String transact
148109 public @ NonNull Page <NftMetadata > findAllNftTypes () {
149110 throw new UnsupportedOperationException ("Not yet implemented" );
150111 }
151-
152- private JsonNode doGetCall (String path , Map <String , ?> params ) throws HieroException {
153- return doGetCall (builder -> {
154- UriBuilder uriBuilder = builder .path (path );
155- for (Map .Entry <String , ?> entry : params .entrySet ()) {
156- uriBuilder = uriBuilder .queryParam (entry .getKey (), entry .getValue ());
157- }
158- return uriBuilder .build ();
159- });
160- }
161-
162- private JsonNode doGetCall (String path ) throws HieroException {
163- return doGetCall (builder -> builder .path (path ).build ());
164- }
165-
166- private JsonNode doGetCall (Function <UriBuilder , URI > uriFunction ) throws HieroException {
167- final ResponseEntity <String > responseEntity = restClient .get ()
168- .uri (uriBuilder -> uriFunction .apply (uriBuilder ))
169- .accept (MediaType .APPLICATION_JSON )
170- .retrieve ()
171- .onStatus (HttpStatusCode ::is4xxClientError , (request , response ) -> {
172- if (!HttpStatus .NOT_FOUND .equals (response .getStatusCode ())) {
173- throw new RuntimeException ("Client error: " + response .getStatusText ());
174- }
175- })
176- .toEntity (String .class );
177- final String body = responseEntity .getBody ();
178- try {
179- if (HttpStatus .NOT_FOUND .equals (responseEntity .getStatusCode ())) {
180- return objectMapper .readTree ("{}" );
181- }
182- return objectMapper .readTree (body );
183- } catch (JsonProcessingException e ) {
184- throw new HieroException ("Error parsing body as JSON: " + body , e );
185- }
186- }
187-
188- private List <Nft > jsonNodeToNftList (final JsonNode rootNode ) {
189- if (rootNode == null || !rootNode .fieldNames ().hasNext ()) {
190- return List .of ();
191- }
192- return StreamSupport .stream (
193- Spliterators .spliteratorUnknownSize (rootNode .get ("nfts" ).iterator (), Spliterator .ORDERED ),
194- false ).map (nftNode -> {
195- try {
196- return jsonNodeToNft (nftNode );
197- } catch (final Exception e ) {
198- throw new RuntimeException ("Error parsing NFT from JSON '" + nftNode + "'" , e );
199- }
200- }).toList ();
201- }
202-
203- private Optional <Nft > jsonNodeToOptionalNft (final JsonNode jsonNode ) throws HieroException {
204- if (jsonNode == null || !jsonNode .fieldNames ().hasNext ()) {
205- return Optional .empty ();
206- }
207- try {
208- return Optional .of (jsonNodeToNft (jsonNode ));
209- } catch (final Exception e ) {
210- throw new HieroException ("Error parsing NFT from JSON '" + jsonNode + "'" , e );
211- }
212- }
213-
214- private Nft jsonNodeToNft (final JsonNode jsonNode ) throws IOException {
215- try {
216- final TokenId parsedTokenId = TokenId .fromString (jsonNode .get ("token_id" ).asText ());
217- final AccountId account = AccountId .fromString (jsonNode .get ("account_id" ).asText ());
218- final long serial = jsonNode .get ("serial_number" ).asLong ();
219- final byte [] metadata = jsonNode .get ("metadata" ).binaryValue ();
220- return new Nft (parsedTokenId , serial , account , metadata );
221- } catch (final Exception e ) {
222- throw new IllegalArgumentException ("Error parsing NFT from JSON '" + jsonNode + "'" , e );
223- }
224- }
225-
226- private @ NonNull Optional <AccountInfo > jsonNodeToOptionalAccountINfo (JsonNode jsonNode ) throws HieroException {
227- if (jsonNode == null || !jsonNode .fieldNames ().hasNext ()) {
228- return Optional .empty ();
229- }
230- try {
231- return Optional .of (jsonNodeToAccountInfo (jsonNode ));
232- } catch (final Exception e ) {
233- throw new HieroException ("Error parsing AccountInfo from JSON '" + jsonNode + "'" , e );
234- }
235- }
236-
237- private AccountInfo jsonNodeToAccountInfo (JsonNode jsonNode ) {
238- try {
239- final AccountId accountId = AccountId .fromString (jsonNode .get ("account" ).asText ());
240- final String evmAddress = jsonNode .get ("evm_address" ).asText ();
241- final long ethereumNonce = jsonNode .get ("ethereum_nonce" ).asLong ();
242- final long pendingReward = jsonNode .get ("pending_reward" ).asLong ();
243- final long balance = jsonNode .get ("balance" ).get ("balance" ).asLong ();
244- return new AccountInfo (accountId , evmAddress , balance , ethereumNonce , pendingReward );
245- } catch (final Exception e ) {
246- throw new IllegalArgumentException ("Error parsing NFT from JSON '" + jsonNode + "'" , e );
247- }
248- }
249-
250- private @ NonNull Optional <ExchangeRates > jsonNodeToOptionalExchangeRates (JsonNode jsonNode ) throws HieroException {
251- if (jsonNode == null || !jsonNode .fieldNames ().hasNext ()) {
252- return Optional .empty ();
253- }
254- try {
255- return Optional .of (jsonNodeToExchangeRates (jsonNode ));
256- } catch (final Exception e ) {
257- throw new HieroException ("Error parsing ExchangeRates from JSON '" + jsonNode + "'" , e );
258- }
259- }
260-
261- private ExchangeRates jsonNodeToExchangeRates (JsonNode jsonNode ) {
262- try {
263- final int currentCentEquivalent = jsonNode .get ("current_rate" ).get ("cent_equivalent" ).asInt ();
264- final int currentHbarEquivalent = jsonNode .get ("current_rate" ).get ("hbar_equivalent" ).asInt ();
265- final Instant currentExpirationTime = Instant .ofEpochSecond (
266- jsonNode .get ("current_rate" ).get ("expiration_time" ).asLong ()
267- );
268-
269- final int nextCentEquivalent = jsonNode .get ("next_rate" ).get ("cent_equivalent" ).asInt ();
270- final int nextHbarEquivalent = jsonNode .get ("next_rate" ).get ("hbar_equivalent" ).asInt ();
271- final Instant nextExpirationTime = Instant .ofEpochSecond (
272- jsonNode .get ("next_rate" ).get ("expiration_time" ).asLong ()
273- );
274-
275- return new ExchangeRates (
276- new ExchangeRate (currentCentEquivalent , currentHbarEquivalent , currentExpirationTime ),
277- new ExchangeRate (nextCentEquivalent , nextHbarEquivalent , nextExpirationTime )
278- );
279- } catch (final Exception e ) {
280- throw new IllegalArgumentException ("Error parsing ExchangeRates from JSON '" + jsonNode + "'" , e );
281- }
282- }
283-
284- private List <NetworkFee > jsonNodeToListNetworkFee (JsonNode jsonNode ) throws HieroException {
285- if (jsonNode == null || !jsonNode .fieldNames ().hasNext () || !jsonNode .has ("fees" )) {
286- return List .of ();
287- }
288-
289- final JsonNode feesNode = jsonNode .get ("fees" );
290- if (!feesNode .isArray ()) {
291- throw new IllegalArgumentException ("Fees node is not an array: " + feesNode );
292- }
293-
294- try {
295- return StreamSupport
296- .stream (Spliterators .spliteratorUnknownSize (feesNode .iterator (), Spliterator .ORDERED ), false )
297- .map (this ::jsonNodeToNetworkFee )
298- .toList ();
299- } catch (final Exception e ) {
300- throw new HieroException ("Error parsing NetworkFees from JSON '" + jsonNode + "'" , e );
301- }
302- }
303-
304- private NetworkFee jsonNodeToNetworkFee (JsonNode jsonNode ) {
305- try {
306- final long gas = jsonNode .get ("gas" ).asLong ();
307- final String transactionType = jsonNode .get ("transaction_type" ).asText ();
308-
309- return new NetworkFee (gas , transactionType );
310- } catch (final Exception e ) {
311- throw new IllegalArgumentException ("Error parsing NetworkFee from JSON '" + jsonNode + "'" , e );
312- }
313- }
314-
315- private @ NonNull Optional <NetworkStake > jsonNodeToOptionalNetworkStake (JsonNode jsonNode ) throws HieroException {
316- if (jsonNode == null || !jsonNode .fieldNames ().hasNext ()) {
317- return Optional .empty ();
318- }
319- try {
320- return Optional .of (jsonNodeToNetworkStake (jsonNode ));
321- } catch (final Exception e ) {
322- throw new HieroException ("Error parsing NetworkStake from JSON '" + jsonNode + "'" , e );
323- }
324- }
325-
326- private NetworkStake jsonNodeToNetworkStake (JsonNode jsonNode ) {
327- try {
328- final long maxStakeReward = jsonNode .get ("max_stake_rewarded" ).asLong ();
329- final long maxStakeRewardPerHbar = jsonNode .get ("max_staking_reward_rate_per_hbar" ).asLong ();
330- final long maxTotalReward = jsonNode .get ("max_total_reward" ).asLong ();
331- final double nodeRewardFeeFraction = jsonNode .get ("node_reward_fee_fraction" ).asDouble ();
332- final long reservedStakingRewards = jsonNode .get ("reserved_staking_rewards" ).asLong ();
333- final long rewardBalanceThreshold = jsonNode .get ("reward_balance_threshold" ).asLong ();
334- final long stakeTotal = jsonNode .get ("stake_total" ).asLong ();
335- final long stakingPeriodDuration = jsonNode .get ("staking_period_duration" ).asLong ();
336- final long stakingPeriodsStored = jsonNode .get ("staking_periods_stored" ).asLong ();
337- final double stakingRewardFeeFraction = jsonNode .get ("staking_reward_fee_fraction" ).asDouble ();
338- final long stakingRewardRate = jsonNode .get ("staking_reward_rate" ).asLong ();
339- final long stakingStartThreshold = jsonNode .get ("staking_start_threshold" ).asLong ();
340- final long unreservedStakingRewardBalance = jsonNode .get ("unreserved_staking_reward_balance" ).asLong ();
341-
342- return new NetworkStake (
343- maxStakeReward ,
344- maxStakeRewardPerHbar ,
345- maxTotalReward ,
346- nodeRewardFeeFraction ,
347- reservedStakingRewards ,
348- rewardBalanceThreshold ,
349- stakeTotal ,
350- stakingPeriodDuration ,
351- stakingPeriodsStored ,
352- stakingRewardFeeFraction ,
353- stakingRewardRate ,
354- stakingStartThreshold ,
355- unreservedStakingRewardBalance
356- );
357- } catch (final Exception e ) {
358- throw new IllegalArgumentException ("Error parsing NetworkStake from JSON '" + jsonNode + "'" , e );
359- }
360- }
361-
362- private @ NonNull Optional <NetworkSupplies > jsonNodeToOptionalNetworkSupplies (JsonNode jsonNode )
363- throws HieroException {
364- if (jsonNode == null || !jsonNode .fieldNames ().hasNext ()) {
365- return Optional .empty ();
366- }
367- try {
368- return Optional .of (jsonNodeToNetworkSupplies (jsonNode ));
369- } catch (final Exception e ) {
370- throw new HieroException ("Error parsing NetworkSupplies from JSON '" + jsonNode + "'" , e );
371- }
372- }
373-
374- private NetworkSupplies jsonNodeToNetworkSupplies (JsonNode jsonNode ) {
375- try {
376- final String releasedSupply = jsonNode .get ("released_supply" ).asText ();
377- final String totalSupply = jsonNode .get ("total_supply" ).asText ();
378-
379- return new NetworkSupplies (releasedSupply , totalSupply );
380- } catch (final Exception e ) {
381- throw new IllegalArgumentException ("Error parsing NetworkSupplies from JSON '" + jsonNode + "'" , e );
382- }
383- }
384-
385- private List <Nft > getNfts (final JsonNode jsonNode ) {
386- if (!jsonNode .has ("nfts" )) {
387- return List .of ();
388- }
389- final JsonNode nftsNode = jsonNode .get ("nfts" );
390- if (!nftsNode .isArray ()) {
391- throw new IllegalArgumentException ("NFTs node is not an array: " + nftsNode );
392- }
393- return StreamSupport .stream (Spliterators .spliteratorUnknownSize (nftsNode .iterator (), Spliterator .ORDERED ),
394- false )
395- .map (nftNode -> {
396- try {
397- return jsonNodeToNft (nftNode );
398- } catch (final Exception e ) {
399- throw new RuntimeException ("Error parsing NFT from JSON '" + nftNode + "'" , e );
400- }
401- }).toList ();
402- }
403-
404- private List <TransactionInfo > extractTransactionInfoFromJsonNode (JsonNode jsonNode ) {
405- if (!jsonNode .has ("transactions" )) {
406- return List .of ();
407- }
408- final JsonNode transactionsNode = jsonNode .get ("transactions" );
409- if (!transactionsNode .isArray ()) {
410- throw new IllegalArgumentException ("Transactions node is not an array: " + transactionsNode );
411- }
412- return StreamSupport .stream (
413- Spliterators .spliteratorUnknownSize (transactionsNode .iterator (), Spliterator .ORDERED ), false )
414- .map (transactionNode -> {
415- try {
416- final String transactionId = transactionNode .get ("transaction_id" ).asText ();
417- return new TransactionInfo (transactionId );
418- } catch (final Exception e ) {
419- throw new RuntimeException ("Error parsing transaction from JSON '" + transactionNode + "'" , e );
420- }
421- }).toList ();
422- }
423112}
0 commit comments