# IoTeX Node.js SDK

A comprehensive npm package for querying the IoTeX blockchain using the native gRPC protocol. This SDK provides a TypeScript-first interface for blockchain queries, account management, and delegate information.

## Features

- **Native gRPC Support**: Direct connection to IoTeX nodes via gRPC (api.iotex.one:443)
- **Blockchain Queries**: Access chain metadata, blocks, epochs, and transaction receipts
- **Node Delegate Queries**: Query blockchain delegates, epochs, and consensus information
- **Voting Bucket Queries**: Query staking buckets with custom protobuf encoding/decoding
- **Account Queries**: Get balances, metadata, nonce, and action history
- **Account Management**: Create, import, export accounts with keystore encryption
- **HD Wallet Support**: Hierarchical Deterministic wallets with BIP44 derivation (m/44'/304'/...)
- **Address Conversion**: Seamless conversion between IoTeX and Ethereum address formats
- **TypeScript Native**: Full TypeScript support with comprehensive type definitions
- **Modern Stack**: Built with ethers v6, @grpc/grpc-js, and official IoTeX libraries

## Installation

```bash
npm install iotex-node-sdk
```

## Quick Start

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

// Create SDK instance for mainnet
const sdk = IoTeXSDK.mainnet();

// Connect to blockchain
await sdk.connect();

// Get chain metadata
const chainMeta = await sdk.blockchain.getChainMeta();
console.log(`Height: ${chainMeta.height}, Epoch: ${chainMeta.epoch.num}`);

// Get account balance
const balance = await sdk.account.getBalance('io1gh7xfrsnj6p5uqgjpk9xq6jg9na28aewgp7a9v');
console.log(`Balance: ${balance} IOTX`);

// Get current delegates
const delegates = await sdk.node.getDelegates();
console.log(`Total delegates: ${delegates.length}`);

// Get voting buckets
const buckets = await sdk.blockchain.getBucketList({
  voterAddress: 'io1jzdxuv7etyfvs7th7jwyspswr6y660zjd7lykg'
});
console.log(`Total buckets: ${buckets.length}`);

// Disconnect
sdk.disconnect();
```

## Network Configuration

### Mainnet
```typescript
const sdk = IoTeXSDK.mainnet();
// or
const sdk = new IoTeXSDK({ endpoint: 'api.iotex.one:443', secure: true });
```

### Testnet
```typescript
const sdk = IoTeXSDK.testnet();
// or
const sdk = new IoTeXSDK({ endpoint: 'api.testnet.iotex.one:443', secure: true });
```

### Local Node
```typescript
const sdk = IoTeXSDK.localhost();
// or
const sdk = new IoTeXSDK({ endpoint: 'localhost:14014', secure: false });
```

## Account Management

### Create New Account

```typescript
// Create account with password-protected keystore
const account = await sdk.account.create('password123');
console.log('Address:', account.address);
console.log('Private key:', account.privateKey);
```

### Import Account from Private Key

```typescript
const address = await sdk.account.importKey(
  'your-private-key-hex',
  'password123'
);
```

### Export Private Key

```typescript
const privateKey = await sdk.account.exportKey(
  'io1gh7xfrsnj6p5uqgjpk9xq6jg9na28aewgp7a9v',
  'password123'
);
```

### List Accounts

```typescript
const accounts = sdk.account.list();
for (const account of accounts) {
  console.log(account.address);
}
```

### Sign and Verify Messages

```typescript
// Sign message
const signature = await sdk.account.sign(
  'io1gh7xfrsnj6p5uqgjpk9xq6jg9na28aewgp7a9v',
  'password123',
  'Hello, IoTeX!'
);

// Verify signature
const isValid = sdk.account.verify(
  'Hello, IoTeX!',
  signature,
  'io1gh7xfrsnj6p5uqgjpk9xq6jg9na28aewgp7a9v'
);
```

## HD Wallet (Hierarchical Deterministic Wallet)

### Create HD Wallet

```typescript
// Create HD wallet with mnemonic
const mnemonic = await sdk.account.createHDWallet('password123', 'english');
console.log('Mnemonic:', mnemonic);
// Save this mnemonic securely!
```

### Import HD Wallet

```typescript
await sdk.account.importHDWallet(
  'your twelve word mnemonic phrase here',
  'password123'
);
```

### Derive Accounts

```typescript
// Derive account at path m/44'/304'/0'/0/0
const account1 = await sdk.account.deriveHDAccount('password123', 0, 0, 0);
console.log('Address:', account1.address);
console.log('Path:', account1.path);

// Derive account at path m/44'/304'/0'/0/1
const account2 = await sdk.account.deriveHDAccount('password123', 0, 0, 1);

// Derive account at path m/44'/304'/1'/0/0
const account3 = await sdk.account.deriveHDAccount('password123', 1, 0, 0);
```

## Address Conversion

```typescript
import { toEthAddress, toIoAddress } from 'iotex-node-sdk';

// Convert IoTeX to Ethereum format
const ethAddr = toEthAddress('io1hp6y4eqr90j7tmul4w2wa8pm7wx462hq0mg4tw');
// Returns: 0xb8744ae4032be5e5ef9fab94ee9c3bf38d5d2ae0

// Convert Ethereum to IoTeX format
const ioAddr = toIoAddress('0xb8744ae4032be5e5ef9fab94ee9c3bf38d5d2ae0');
// Returns: io1hp6y4eqr90j7tmul4w2wa8pm7wx462hq0mg4tw
```

## Blockchain Queries

### Get Chain Metadata

```typescript
const chainMeta = await sdk.blockchain.getChainMeta();
console.log('Height:', chainMeta.height.toString());
console.log('Epoch:', chainMeta.epoch.num.toString());
console.log('TPS:', chainMeta.tps);
```

### Get Block Information

```typescript
// Get block by height
const block = await sdk.blockchain.getBlock(1000000);

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

console.log('Block hash:', block.blockHash);
console.log('Timestamp:', block.timestamp);
console.log('Producer:', block.producerAddress);
```

### Get Epoch Metadata

```typescript
// Get current epoch
const currentEpoch = await sdk.blockchain.getEpochMeta();

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

console.log('Epoch:', currentEpoch.num.toString());
console.log('Height:', currentEpoch.height.toString());
```

### Get Voting Buckets

```typescript
// Get buckets by voter address
const buckets = await sdk.blockchain.getBucketList({
  voterAddress: 'io1jzdxuv7etyfvs7th7jwyspswr6y660zjd7lykg',
  offset: 0,
  limit: 100
});

// Get buckets by candidate name
const candidateBuckets = await sdk.blockchain.getBucketList({
  candidateName: 'iotexlab'
});

// Get all buckets (paginated)
const allBuckets = await sdk.blockchain.getBucketList({
  offset: 0,
  limit: 100
});

// Get specific bucket by index
const bucket = await sdk.blockchain.getBucket(32);

console.log('Bucket info:', {
  index: bucket.index,
  candidateAddress: bucket.candidateAddress,
  stakedAmount: bucket.stakedAmount,
  stakedDuration: bucket.stakedDuration,
  autoStake: bucket.autoStake,
  owner: bucket.owner
});
```

### Get Blockchain Version

```typescript
const version = await sdk.blockchain.getVersion();
console.log('Version:', version.packageVersion);
console.log('Commit:', version.packageCommitID);
```

## Node Delegate Queries

### Get Current Delegates

```typescript
// Get top 36 delegates with full candidate information
const delegates = await sdk.node.getDelegates();

for (const delegate of delegates) {
  console.log(`${delegate.rank}. ${delegate.name}`);
  console.log(`   Operator Address: ${delegate.operatorAddress || delegate.address}`);
  console.log(`   Owner Address: ${delegate.ownerAddress}`);
  console.log(`   Reward Address: ${delegate.rewardAddress}`);
  console.log(`   Votes: ${delegate.votes} IOTX`);
  console.log(`   Total Weighted Votes: ${delegate.totalWeightedVotes}`);
  console.log(`   Self-staking Tokens: ${delegate.selfStakingTokens}`);
  console.log(`   Production: ${delegate.production}`);
  console.log(`   Active: ${delegate.active}`);
}
```

### Get All Delegates

```typescript
// Get all delegates for current epoch (includes all registered candidates)
const allDelegates = await sdk.node.getDelegates({ all: true });

// Get delegates for specific epoch
const epoch1000Delegates = await sdk.node.getDelegates({
  epochNumber: 1000,
  all: true
});

// Access extended delegate fields
console.log('Owner:', allDelegates[0].ownerAddress);
console.log('Operator:', allDelegates[0].operatorAddress);
console.log('Reward:', allDelegates[0].rewardAddress);
console.log('Self-stake bucket index:', allDelegates[0].selfStakeBucketIdx);
console.log('ID:', allDelegates[0].id);
```

### Get Current Epoch

```typescript
const currentEpoch = await sdk.node.getCurrentEpoch();
console.log('Epoch:', currentEpoch.num.toString());
console.log('Height:', currentEpoch.height.toString());
```

## Account Information

### Get Account Balance

```typescript
const balance = await sdk.account.getBalance('io1jzdxuv7etyfvs7th7jwyspswr6y660zjd7lykg');
console.log(`Balance: ${balance} IOTX`);

// Also works with Ethereum addresses
const balance2 = await sdk.account.getBalance('0x909a6e33d95912c87977f49c48060e1e89ad3c52');
```

### Get Account Metadata

```typescript
const meta = await sdk.account.getMeta('io1jzdxuv7etyfvs7th7jwyspswr6y660zjd7lykg');
console.log('Address:', meta.address);
console.log('Balance:', meta.balance);
console.log('Nonce:', meta.nonce.toString());
console.log('Pending Nonce:', meta.pendingNonce.toString());
console.log('Number of Actions:', meta.numActions.toString());
```

### Get Account Nonce

```typescript
const nonce = await sdk.account.getNonce('io1jzdxuv7etyfvs7th7jwyspswr6y660zjd7lykg');
console.log('Current nonce:', nonce.toString());
```

## Utility Functions

### Amount Conversion

```typescript
import { iotxToRau, rauToIotx } from 'iotex-node-sdk';

// Convert IOTX to Rau (smallest unit)
const rau = iotxToRau('100');        // Returns: 100000000000000000000n
const iotx = rauToIotx(rau);         // Returns: "100"
```

### Validation

```typescript
import {
  isValidIoAddress,
  isValidEthAddress,
  isValidAmount,
  isValidCandidateName
} from 'iotex-node-sdk';

isValidIoAddress('io1hp6y4eqr90j7tmul4w2wa8pm7wx462hq0mg4tw');  // true
isValidEthAddress('0xb8744ae4032be5e5ef9fab94ee9c3bf38d5d2ae0'); // true
isValidAmount('100.5');                                          // true
isValidCandidateName('iotexlab');                                // true
```

## Error Handling

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

try {
  const balance = await sdk.account.getBalance('invalid-address');
} catch (error) {
  if (error instanceof IoTeXError) {
    console.error('Error code:', error.code);
    console.error('Message:', error.message);
    console.error('Details:', error.details);
  }
}
```

## Examples

See the `examples/` directory for complete working examples:

- `get-balance.ts` - Query account balances
- `get-delegates.ts` - Query blockchain delegates
- `create-account.ts` - Create and manage accounts
- `hdwallet.ts` - HD wallet operations
- `blockchain-info.ts` - Query blockchain information

Run an example:

```bash
npx ts-node examples/get-balance.ts
```

## Testing

```bash
# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm test -- --coverage
```

## Building

```bash
npm run build
```

## Architecture

```
iotex-node-sdk/
├── src/
│   ├── client/          # gRPC client and configuration
│   ├── account/         # Account management, keystore, HD wallet, crypto
│   ├── node/            # Node delegate queries
│   ├── stake/           # Staking operations (stake2)
│   ├── blockchain/      # Blockchain queries
│   ├── utils/           # Utilities (conversion, validation, errors)
│   └── index.ts         # Main SDK export
├── proto/               # Protobuf definitions from iotex-proto
├── examples/            # Usage examples
└── test/                # Unit tests
```

## Dependencies

### Core Dependencies
- **@grpc/grpc-js** ^1.12.0 - Modern gRPC for Node.js
- **@grpc/proto-loader** ^0.7.13 - Dynamic protobuf loading
- **@iotexproject/iotex-address-ts** ^1.0.2 - Official address conversion
- **ethers** ^6.13.0 - Ethereum-compatible cryptography
- **bip39** ^3.1.0 - Mnemonic generation/validation
- **hdkey** ^2.1.0 - HD wallet key derivation

## Comparison with ioctl

This SDK replicates the core functionality of the `ioctl` CLI tool:

| ioctl Command | SDK Method |
|---------------|------------|
| `ioctl account balance` | `sdk.account.getBalance()` |
| `ioctl account create` | `sdk.account.create()` |
| `ioctl account import` | `sdk.account.importKey()` |
| `ioctl hdwallet create` | `sdk.account.createHDWallet()` |
| `ioctl hdwallet derive` | `sdk.account.deriveHDAccount()` |
| `ioctl node delegate` | `sdk.node.getDelegates()` |
| `ioctl bc info` | `sdk.blockchain.getChainMeta()` |
| `ioctl bc block` | `sdk.blockchain.getBlock()` |

## 📚 Documentation

Complete documentation is available in the [docs/](./docs/) folder:

- **[DOCUMENTATION_INDEX.md](./docs/DOCUMENTATION_INDEX.md)** - Start here! Master index to all documentation
- **[GETTING_STARTED.md](./docs/GETTING_STARTED.md)** - Installation and first steps
- **[README_QUERIES.md](./docs/README_QUERIES.md)** - Query examples and patterns
- **[ACCOUNT_MANAGEMENT.md](./docs/ACCOUNT_MANAGEMENT.md)** - Account creation, keystore, HD wallet
- **[API_COMPLETE_REFERENCE.md](./docs/API_COMPLETE_REFERENCE.md)** - Exhaustive API documentation
- **[ADVANCED_QUERIES.md](./docs/ADVANCED_QUERIES.md)** - Advanced query patterns and error handling
- **[FEATURES_STATUS.md](./docs/FEATURES_STATUS.md)** - Feature implementation status

All features are fully documented with examples and best practices.

## Development Status

### Fully Implemented ✅
- gRPC client with TLS support
- Account management (create, import, export, sign)
- Account queries (balance, metadata, nonce)
- Keystore encryption/decryption
- HD wallet with BIP44 derivation
- Cryptographic operations (signing, verification, hashing)
- Address conversion (IoTeX ↔ Ethereum)
- Blockchain queries (chain meta, blocks, epochs)
- **Voting bucket queries** (custom protobuf encoding/decoding)
- Node delegate queries
- Utility functions (conversion, validation, errors)
- Comprehensive test suite (52 tests passing)

### Not Yet Implemented ❌
- Write operations (staking, transfers, contract calls)
- Smart contract interaction
- Action submission (requires protobuf serialization)
- Event streaming
- WebSocket support

## Roadmap

1. **Phase 1**: Complete protobuf action building for staking operations
2. **Phase 2**: Implement smart contract ABI encoding/decoding
3. **Phase 3**: Add WebSocket support for real-time events
4. **Phase 4**: Browser compatibility (using grpc-web)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT

## Links

- [IoTeX Official Website](https://iotex.io)
- [IoTeX Documentation](https://docs.iotex.io)
- [ioctl CLI Tool](https://github.com/iotexproject/iotex-core)
- [IoTeX Proto Definitions](https://github.com/iotexproject/iotex-proto)

## Support

For issues and questions:
- GitHub Issues: [Create an issue](https://github.com/your-repo/iotex-node-sdk/issues)
- IoTeX Discord: [Join the community](https://discord.gg/iotex)
