Api

Blockchain API

Read-only blockchain queries — blocks, fees, balances, allowances, raw broadcasts

The Blockchain API exposes Hydra App's BlockchainService — read-only methods to query on-chain data and a single broadcast method for fully-signed raw transactions.

JSON-RPC namespace: blockchain

Endpoints


Get Block Number

Get the current block number for a network.

Service: BlockchainServiceMethod: GetBlockNumber

Parameters:

NameTypeRequiredDescription
networkNetworkYESNetwork to query

Response:

FieldTypeDescription
block_numberuint64Current block number/height

Example Request:

TypeScript
const blockNumber = await hydraGrpcClient.getBlockNumber({
  network: { protocol: 1, id: '0a03cf40' }   // Bitcoin Signet
})
Rust
let request = tonic::Request::new(GetBlockNumberRequest {
    network: Some(Network {
        protocol: Protocol::Bitcoin as i32,
        id: "0a03cf40".to_string(),
    }),
});

let response = client.get_block_number(request).await?;
let block_number = response.into_inner().block_number;

Get Block Header

Get block header information for a specific block.

Service: BlockchainServiceMethod: GetBlockHeader

Parameters:

NameTypeRequiredDescription
networkNetworkYESNetwork to query
block_numberuint64YESBlock height to read

block_number is not optional. It is a plain uint64, so leaving it out sends 0 and you get the genesis block, not the tip. For the tip, call GetBlockNumber first and pass what it returns.

Response:

FieldTypeDescription
block_headerBlockHeaderBlock header data

BlockHeader Object:

FieldTypeDescription
numberuint64Block height
hashstringHex-encoded block hash
timestampTimestampWhen the block was produced
prev_hashstringHex-encoded hash of the previous block

Example Request:

TypeScript
const network = { protocol: 2, id: '11155111' }

// The tip: read its height first, then the header at that height.
const tip = await hydraGrpcClient.getBlockNumber({ network })
const latest = await hydraGrpcClient.getBlockHeader({ network, blockNumber: tip.blockNumber })

// A specific block.
const header = await hydraGrpcClient.getBlockHeader({ network, blockNumber: 1000000 })
Rust
let network = Network { protocol: Protocol::Evm as i32, id: "11155111".to_string() };

// The tip: read its height first, then the header at that height.
let tip = client.get_block_number(tonic::Request::new(GetBlockNumberRequest {
    network: Some(network.clone()),
})).await?.into_inner().block_number;

let request = tonic::Request::new(GetBlockHeaderRequest {
    network: Some(network),
    block_number: tip,
});

let block_header = client.get_block_header(request).await?.into_inner().block_header;

Get Transaction By Id

Returns the details of a specific on-chain transaction by its ID.

Method: GetTransactionById

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network
txidstringYESTransaction ID to query

Response:

FieldTypeDescription
transactionChainTransactionOn-chain transaction details

Example Request:

import { GetTransactionByIdRequest } from './proto/blockchain_pb'

const request = new GetTransactionByIdRequest()
request.setNetwork({ protocol: 1, id: '0a03cf40' })
request.setTxid('abc123def456...')

const response = await client.getTransactionById(request, {})
console.log('Transaction:', response.getTransaction()?.toObject())

Get Fee Estimates

Current fee estimates at three priority levels. Use these to build a FeeOption.custom, or to show the user what low / medium / high currently cost before picking one.

Method: GetFeeEstimates

Parameters:

NameTypeRequiredDescription
networkNetworkYESNetwork to get fees for

Response:

FieldTypeDescription
fee_estimateFeeEstimateThe three estimates

FeeEstimatelow, medium and high, each a ChainFee:

FieldTypeDescription
base_fee_per_unitU256StringThe network's current base fee per gas / weight unit
fee_rateFeeRatemax_fee_per_unit + priority_fee_per_unit — the pair you would put on a transaction
effective_fee_per_unitU256StringWhat a transaction at this level would actually pay per unit

The response is not three decimal strings. An earlier revision of this page showed { low, medium, high } as DecimalStrings; every level is a full ChainFee, and its numbers are U256Strings per unit — sat/vbyte on Bitcoin, wei per gas on EVM — not whole-asset amounts. See Fee structures.

Example Request:

const { feeEstimate } = await hydraGrpcClient.getFeeEstimates({
  network: { protocol: 1, id: '0a03cf40' }
})

for (const level of ['low', 'medium', 'high'] as const) {
  console.log(`${level}: ${feeEstimate[level].feeRate.maxFeePerUnit.value} sat/vB`)
}

Example Response:

{
  "feeEstimate": {
    "low": {
      "baseFeePerUnit": { "value": "1" },
      "feeRate": { "maxFeePerUnit": { "value": "2" }, "priorityFeePerUnit": { "value": "0" } },
      "effectiveFeePerUnit": { "value": "1" }
    },
    "medium": {
      "baseFeePerUnit": { "value": "1" },
      "feeRate": { "maxFeePerUnit": { "value": "5" }, "priorityFeePerUnit": { "value": "0" } },
      "effectiveFeePerUnit": { "value": "3" }
    },
    "high": {
      "baseFeePerUnit": { "value": "1" },
      "feeRate": { "maxFeePerUnit": { "value": "12" }, "priorityFeePerUnit": { "value": "0" } },
      "effectiveFeePerUnit": { "value": "8" }
    }
  }
}

This is the JSON-RPC wire shape: camelCase keys, and every U256String / DecimalString as a { "value": … } object. Over gRPC the field names are the proto's own snake_case. See Wire encoding.


Broadcast Raw Transaction

Broadcasts a fully signed raw transaction to the specified network. Use this when you have a pre-signed transaction in serialized form (e.g. produced offline or by an external signer).

Method: BroadcastRawTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network
raw_txbytesYESFully signed raw transaction bytes

Response:

FieldTypeDescription
txidstringResulting transaction ID

Example Request:

import { BroadcastRawTransactionRequest } from './proto/blockchain_pb'

const request = new BroadcastRawTransactionRequest()
request.setNetwork({ protocol: 1, id: '0a03cf40' })
request.setRawTx(Buffer.from('0200000001...', 'hex'))

const response = await client.broadcastRawTransaction(request, {})
console.log('Broadcast TXID:', response.getTxid())

Example Response:

{ "txid": "abc123def456..." }

Get Address Balance

Returns the native asset balance for an arbitrary address (not necessarily this wallet's).

Method: GetAddressBalance

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network
addressstringYESAddress to query

Response:

FieldTypeDescription
balanceDecimalStringNative asset balance

Example Request:

import { GetAddressBalanceRequest } from './proto/blockchain_pb'

const request = new GetAddressBalanceRequest()
request.setNetwork({ protocol: 2, id: '11155111' })
request.setAddress('0xabc...')

const response = await client.getAddressBalance(request, {})
console.log('Balance:', response.getBalance()?.getValue())

Example Response:

{ "balance": { "value": "1.234567" } }

Get Token Balance

Returns the token balance for the given token contract and address (EVM only).

Method: GetTokenBalance

Parameters:

NameTypeRequiredDescription
networkNetworkYESEVM network
token_idstringYESToken contract address
addressstringYESHolder address

Response:

FieldTypeDescription
balanceDecimalStringToken balance

Example Request:

import { GetTokenBalanceRequest } from './proto/blockchain_pb'

const request = new GetTokenBalanceRequest()
request.setNetwork({ protocol: 2, id: '11155111' })
request.setTokenId('erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') // USDC
request.setAddress('0xabc...')

const response = await client.getTokenBalance(request, {})
console.log('Token balance:', response.getBalance()?.getValue())

Example Response:

{ "balance": { "value": "1500" } }

Get Token Allowance

Returns the current token allowance granted by an owner to a spender on the specified network. EVM only.

Method: GetTokenAllowance

Parameters:

NameTypeRequiredDescription
networkNetworkYESEVM network
token_idstringYESToken contract address
ownerstringYESToken owner address
spenderstringYESApproved spender address

Response:

FieldTypeDescription
allowanceTokenAllowanceAllowance details (token type + amount + approval status)

Example Request:

import { GetTokenAllowanceRequest } from './proto/blockchain_pb'

const request = new GetTokenAllowanceRequest()
request.setNetwork({ protocol: 2, id: '11155111' })
request.setTokenId('erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')
request.setOwner('0xowner...')
request.setSpender('0xspender...')

const response = await client.getTokenAllowance(request, {})
console.log('Allowance:', response.getAllowance()?.toObject())

Get Token Permit Terms

Added 2026-09-11.

Returns what a token discloses before an owner signs a permit for it — the terms a TokenPermit carries. EVM and Tron only.

Reading the terms is how a caller learns whether a permit is available at all: a token that offers no signature-authorised allowance to this owner returns no terms, and the only way to set an allowance for it is an on-chain SetTokenAllowance.

Method: GetTokenPermitTerms

Parameters:

NameTypeRequiredDescription
networkNetworkYESEVM or Tron network
token_idstringYESThe token, e.g. erc20:0x…
ownerstringYESThe address that would sign the permit

Response:

FieldTypeDescription
termsbytes (optional)The terms, serialised by the network's protocol — exactly the bytes that go into TokenPermit.terms. Absent when the token offers no permit to this owner

The terms are owner-specific. They fold in the owner's current permit nonce, so terms read for one owner are not valid for another, and terms read before a permit is consumed are not valid after. Read them immediately before signing.

Example Request:

import { GetTokenPermitTermsRequest } from './proto/blockchain_pb'

const request = new GetTokenPermitTermsRequest()
request.setNetwork({ protocol: 2, id: '11155111' })
request.setTokenId('erc20:0x8cd0da3d001b013336918b8bc4e56d9dda1347e0')
request.setOwner('0xowner...')

const terms = (await client.getTokenPermitTerms(request, {})).getTerms_asU8()
if (!terms || terms.length === 0) {
  // No permit available — fall back to an on-chain approve.
}

Example Response:

{ "terms": "eyJkb21haW4iOnsibmFtZSI6IlVTRC..." }

bytes is base64 over JSON-RPC and raw bytes over gRPC. The full permit flow — estimate, sign, submit — is on the Client API.


Common Patterns

Monitor block confirmations

Rust
async fn wait_for_confirmations(
    client: &mut BlockchainServiceClient<Channel>,
    network: Network,
    tx_block: u64,
    required_confirmations: u64,
) -> Result<(), Box<dyn std::error::Error>> {
    loop {
        let current_block = client
            .get_block_number(GetBlockNumberRequest {
                network: Some(network.clone()),
            })
            .await?
            .into_inner()
            .block_number;

        let confirmations = current_block.saturating_sub(tx_block);

        if confirmations >= required_confirmations {
            return Ok(());
        }

        tokio::time::sleep(tokio::time::Duration::from_secs(15)).await;
    }
}

Get appropriate fee for urgency

Rust
async fn get_fee_for_urgency(
    client: &mut BlockchainServiceClient<Channel>,
    network: Network,
    urgent: bool,
) -> Result<String, Box<dyn std::error::Error>> {
    let fees = client
        .get_fee_estimates(GetFeeEstimatesRequest {
            network: Some(network),
        })
        .await?
        .into_inner();

    Ok(if urgent { fees.high } else { fees.medium })
}

Error Handling

Error CodeDescriptionSolution
INVALID_ARGUMENTInvalid network, address, or token idVerify all parameters. A token_id needs its standard prefix — erc20:0x…, not a bare address
NOT_FOUNDBlock or transaction not foundCheck the height / txid exists on this network
UNIMPLEMENTEDA token call on BitcoinGetTokenBalance / GetTokenAllowance / GetTokenPermitTerms exist only on EVM and Tron
UNAVAILABLEChain backend temporarily unavailableRetry with backoff

Best Practices

  1. Cache fee estimates. Refresh every 30–60 seconds, not once per transaction — the backing estimator does not move faster than that.
  2. Prefer the node's own view for your own transactions. These calls go to the chain; for a transaction this wallet sent, wallet.GetTransaction already carries the wallet-level status and confirmations.
  3. Pass token_id with its standard prefixerc20:0x…, trc20:T…. A bare contract address is rejected.
  4. Read permit terms immediately before signing. They encode the owner's current nonce — see Get Token Permit Terms.
  5. Allow for reorgs on short confirmation counts: a header at a height you read a moment ago may not be the header at that height now.

← Back to API Reference | Next: Signer API →


Copyright © 2025