# IoTeX SDK - Query Guide

## Overview

This SDK is **production-ready for all query operations**. You can use it right now to read data from the IoTeX blockchain without any additional implementation needed.

## ✅ Ready to Use - Query Operations

All query functionality is **100% complete and tested**:

### Account Queries
```typescript
// Get balance
const balance = await sdk.account.getBalance('io1...');

// Get full metadata
const meta = await sdk.account.getMeta('io1...');

// Get nonce
const nonce = await sdk.account.getNonce('io1...');

// Convert addresses
const ethAddr = sdk.account.toEthAddress('io1...');
const ioAddr = sdk.account.toIoAddress('0x...');
```

### Blockchain Queries
```typescript
// Get chain metadata
const chainMeta = await sdk.blockchain.getChainMeta();

// Get block
const block = await sdk.blockchain.getBlock(1000000);
const blockByHash = await sdk.blockchain.getBlock('hash');

// Get epoch
const epoch = await sdk.blockchain.getEpochMeta();
const epoch1000 = await sdk.blockchain.getEpochMeta(1000);

// Get version
const version = await sdk.blockchain.getVersion();

// Get receipt
const receipt = await sdk.blockchain.getReceipt('action-hash');

// Query actions
const actions = await sdk.blockchain.getActions({ byHash: 'hash' });
```

### Delegate Queries
```typescript
// Get current delegates (top 36) with full candidate information
const delegates = await sdk.node.getDelegates();
// Each delegate includes: address, name, votes (WEIGHTED), production, active status,
// plus ownerAddress, operatorAddress, rewardAddress, totalWeightedVotes,
// selfStakeBucketIdx, selfStakingTokens, and id

// Get all delegates (all registered candidates)
const allDelegates = await sdk.node.getDelegates({ all: true });

// Get delegates for epoch
const epochDelegates = await sdk.node.getDelegates({ epochNumber: 1000 });

// Access extended delegate information
console.log(`Owner: ${delegates[0].ownerAddress}`);
console.log(`Operator: ${delegates[0].operatorAddress}`);
console.log(`Reward address: ${delegates[0].rewardAddress}`);
console.log(`Self-stake: ${delegates[0].selfStakingTokens}`);

// Get current epoch
const currentEpoch = await sdk.node.getCurrentEpoch();
```

### Understanding Votes vs Staked Amount

**Important**: The `votes` field in delegate information represents **weighted votes**, not raw staked IOTX:

- **Weighted Votes** (`votes`): Staked IOTX × lock duration multiplier
- **Raw Staked IOTX**: Actual tokens staked (no multiplier)

To get total raw staked IOTX for a delegate:
```typescript
const buckets = await sdk.blockchain.getBucketList({
  candidateName: 'delegateName',
  offset: 0,
  limit: 10000
});
const totalStaked = buckets.reduce((sum, b) => sum + parseFloat(b.stakedAmount), 0);
```

## Quick Setup

```bash
cd /Users/simone/Source/GitHub/simonerom/ioctl/iotex-node-sdk
npm install
npm run build
```

## Run Query Demo

```bash
npm run example:quick-start
# or
npx ts-node examples/query-only-demo.ts
```

## Complete Query API

### 1. Account Module (`sdk.account`)

| Method | Description | Returns |
|--------|-------------|---------|
| `getBalance(address)` | Get account balance in IOTX | `Promise<string>` |
| `getMeta(address)` | Get full account metadata | `Promise<AccountMeta>` |
| `getNonce(address)` | Get pending nonce | `Promise<bigint>` |
| `toEthAddress(ioAddress)` | Convert to Ethereum format | `string` |
| `toIoAddress(ethAddress)` | Convert to IoTeX format | `string` |

### 2. Blockchain Module (`sdk.blockchain`)

| Method | Description | Returns |
|--------|-------------|---------|
| `getChainMeta()` | Get chain metadata | `Promise<ChainMeta>` |
| `getBlock(heightOrHash)` | Get block by height or hash | `Promise<Block>` |
| `getEpochMeta(epochNumber?)` | Get epoch metadata | `Promise<EpochMeta>` |
| `getVersion()` | Get blockchain version | `Promise<VersionInfo>` |
| `getReceipt(actionHash)` | Get transaction receipt | `Promise<any>` |
| `getActions(params)` | Query actions with filters | `Promise<any[]>` |

### 3. Node Module (`sdk.node`)

| Method | Description | Returns |
|--------|-------------|---------|
| `getDelegates(options?)` | Get delegates | `Promise<Delegate[]>` |
| `getCurrentEpoch()` | Get current epoch info | `Promise<EpochMeta>` |

### 4. Utility Functions

| Function | Description | Returns |
|----------|-------------|---------|
| `iotxToRau(iotx)` | Convert IOTX to Rau | `bigint` |
| `rauToIotx(rau)` | Convert Rau to IOTX | `string` |
| `isValidIoAddress(addr)` | Validate IoTeX address | `boolean` |
| `isValidEthAddress(addr)` | Validate Ethereum address | `boolean` |
| `isValidAddress(addr)` | Validate any address | `boolean` |

## Example: Simple Balance Checker

```typescript
import { IoTeXSDK } from 'iotex-node-sdk';

async function checkBalance(address: string) {
  const sdk = IoTeXSDK.mainnet();
  await sdk.connect();

  const balance = await sdk.account.getBalance(address);
  console.log(`${address}: ${balance} IOTX`);

  sdk.disconnect();
}

checkBalance('io1gh7xfrsnj6p5uqgjpk9xq6jg9na28aewgp7a9v');
```

## Example: Blockchain Monitor

```typescript
import { IoTeXSDK } from 'iotex-node-sdk';

async function monitor() {
  const sdk = IoTeXSDK.mainnet();
  await sdk.connect();

  setInterval(async () => {
    const chainMeta = await sdk.blockchain.getChainMeta();
    const block = await sdk.blockchain.getBlock(Number(chainMeta.height));

    console.log(`[${new Date().toISOString()}]`);
    console.log(`  Height: ${chainMeta.height}`);
    console.log(`  Epoch: ${chainMeta.epoch.num}`);
    console.log(`  TPS: ${chainMeta.tpsFloat.toFixed(2)}`);
    console.log(`  Latest block: ${block.blockHash.slice(0, 16)}...`);
    console.log(`  Producer: ${block.producerAddress}`);
    console.log();
  }, 10000); // Every 10 seconds
}

monitor();
```

## Example: Delegate Tracker

```typescript
import { IoTeXSDK } from 'iotex-node-sdk';

async function trackDelegates() {
  const sdk = IoTeXSDK.mainnet();
  await sdk.connect();

  const delegates = await sdk.node.getDelegates({ all: true });

  console.log(`Total Delegates: ${delegates.length}\n`);
  console.log('Top 20:');

  delegates.slice(0, 20).forEach(d => {
    const status = d.active ? 'active' : 'inactive';
    console.log(`${d.rank.toString().padStart(3)}. ${d.name.padEnd(20)} ${d.votes.padStart(20)} IOTX (${d.production} blocks, ${status})`);
  });

  // Show detailed info for top delegate
  const topDelegate = delegates[0];
  console.log('\nTop Delegate Details:');
  console.log('  Name:', topDelegate.name);
  console.log('  Operator Address:', topDelegate.operatorAddress);
  console.log('  Owner Address:', topDelegate.ownerAddress);
  console.log('  Reward Address:', topDelegate.rewardAddress);
  console.log('  Self-stake Tokens:', topDelegate.selfStakingTokens);
  console.log('  Total Weighted Votes:', topDelegate.totalWeightedVotes);

  sdk.disconnect();
}

trackDelegates();
```

## Performance

- **Connection**: Persistent gRPC connection (reuse SDK instance)
- **Parallel Queries**: Use `Promise.all()` for batch queries
- **Caching**: Consider caching chain metadata locally (updates every ~5 seconds)

```typescript
// ✅ Good - parallel queries
const [balance1, balance2, balance3] = await Promise.all([
  sdk.account.getBalance(addr1),
  sdk.account.getBalance(addr2),
  sdk.account.getBalance(addr3)
]);

// ❌ Bad - sequential queries
const balance1 = await sdk.account.getBalance(addr1);
const balance2 = await sdk.account.getBalance(addr2);
const balance3 = await sdk.account.getBalance(addr3);
```

## Error Handling

All query methods can throw `IoTeXError`:

```typescript
import { IoTeXError } from 'iotex-node-sdk';

try {
  const balance = await sdk.account.getBalance('invalid');
} catch (error) {
  if (error instanceof IoTeXError) {
    switch (error.code) {
      case 'INVALID_ADDRESS':
        console.error('Bad address format');
        break;
      case 'ACCOUNT_NOT_FOUND':
        console.error('Account does not exist');
        break;
      case 'CONNECTION_ERROR':
        console.error('Cannot connect to node');
        break;
      default:
        console.error(error.message);
    }
  }
}
```

## Networks

```typescript
// Mainnet
const sdk = IoTeXSDK.mainnet();

// Testnet
const sdk = IoTeXSDK.testnet();

// Custom
const sdk = new IoTeXSDK({
  endpoint: 'your-node:443',
  secure: true,
  timeout: 30000
});
```

## TypeScript Types

All return types are fully typed:

```typescript
import {
  ChainMeta,
  Block,
  EpochMeta,
  Delegate,
  AccountMeta
} from 'iotex-node-sdk';

const chainMeta: ChainMeta = await sdk.blockchain.getChainMeta();
// chainMeta.height is bigint
// chainMeta.tps is number
// chainMeta.epoch.num is bigint
```

## What's NOT Included

This SDK is **read-only**. It does NOT support:

- ❌ Creating accounts
- ❌ Signing transactions
- ❌ Sending actions (transfers, staking)
- ❌ Smart contract writes
- ❌ Keystore management

For write operations, use `ioctl` CLI or wait for the full SDK implementation.

## Testing Your Queries

```bash
# Run all query examples
npm run example:quick-start
npm run example:balance
npm run example:delegates
npm run example:blockchain

# Run query-only demo
npx ts-node examples/query-only-demo.ts

# Run integration tests
npm run test:integration
```

## Production Checklist

- [x] All query methods implemented
- [x] Error handling in place
- [x] TypeScript types defined
- [x] Examples working
- [x] Unit tests passing
- [x] Integration tests passing
- [x] Documentation complete

## Support

- **Examples**: See `examples/` directory
- **Full API**: See `README_QUERIES.md`
- **IoTeX Docs**: https://docs.iotex.io
- **Discord**: https://discord.gg/iotex

---

**Status**: ✅ **PRODUCTION READY FOR QUERIES**

All query functionality is complete, tested, and ready to use!
