@hydra-sdk/core

The core package provides essential Cardano wallet functionality including HD wallet management, transaction signing, and network integration.

Installation

bash
npm install @hydra-sdk/core

Network Configuration

Network IDs

typescript
enum NETWORK_ID {
  TESTNET = 0,
  MAINNET = 1,
  PREPROD = 0 // Alias for testnet
}

// Usage
const wallet = new AppWallet({
  networkId: NETWORK_ID.MAINNET, // Production
  // networkId: NETWORK_ID.PREPROD, // Testing
  key: { type: 'mnemonic', words: mnemonic }
})

Custom Fetcher and Submitter

typescript
import { IFetcher, ISubmitter } from '@hydra-sdk/core'

// Custom fetcher implementation
const customFetcher: IFetcher = {
  fetchAddressUTxOs: async (address) => {
    // Custom UTxO fetching logic
    return await fetch(`/api/utxos/${address}`).then(r => r.json())
  },
  fetchTxInfo: async (txHash) => {
    // Custom transaction info fetching
    return await fetch(`/api/tx/${txHash}`).then(r => r.json())
  },
  fetchProtocolParameters: async () => {
    // Custom protocol parameters fetching
    return await fetch('/api/protocol-params').then(r => r.json())
  }
}

// Custom submitter implementation
const customSubmitter: ISubmitter = {
  submitTx: async (txCbor) => {
    // Custom transaction submission
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ cborHex: txCbor }),
      headers: { 'Content-Type': 'application/json' }
    })
    return response.json()
  }
}

// Use with wallet
const wallet = new AppWallet({
  networkId: NETWORK_ID.PREPROD,
  key: { type: 'mnemonic', words: mnemonic },
  fetcher: customFetcher,
  submitter: customSubmitter
})

Utility Functions

Serialization and Deserialization

typescript
import { 
  serializeTx, 
  deserializeTx,
  resolveTxHash 
} from '@hydra-sdk/core'

// Deserialize transaction
const tx = deserializeTx(txCborHex)
console.log('Transaction:', tx)

// Get transaction hash
const txHash = resolveTxHash(txCborHex)
console.log('Transaction hash:', txHash)

// Serialize transaction back to CBOR
const cborHex = serializeTx(tx)
console.log('CBOR hex:', cborHex)

Key Building Utilities

typescript
import { 
  buildBaseAddress,
  buildEnterpriseAddress,
  buildRewardAddress,
  buildKeys
} from '@hydra-sdk/core'

// Build addresses from keys
const networkId = 0
const paymentKey = '...' // payment public key
const stakeKey = '...'   // stake public key

const baseAddress = buildBaseAddress(networkId, paymentKey, stakeKey)
const enterpriseAddress = buildEnterpriseAddress(networkId, paymentKey)
const rewardAddress = buildRewardAddress(networkId, stakeKey)

console.log({
  baseAddress,
  enterpriseAddress,
  rewardAddress
})

Data Conversion

typescript
import { toBytes, fromBytes } from '@hydra-sdk/core'

// Convert hex string to bytes
const bytes = toBytes('48656c6c6f20576f726c64')
console.log('Bytes:', bytes)

// Convert bytes to hex string
const hexString = fromBytes(bytes)
console.log('Hex:', hexString)

Complete Examples

Create and Use Wallet

typescript
import { AppWallet, NETWORK_ID } from '@hydra-sdk/core'

async function createAndUseWallet() {
  // Generate new wallet
  const mnemonic = AppWallet.brew(256)
  console.log('Generated mnemonic:', mnemonic)

  // Create wallet instance
  const wallet = new AppWallet({
    networkId: NETWORK_ID.PREPROD,
    key: {
      type: 'mnemonic',
      words: mnemonic
    }
  })

  // Get account information
  const account = wallet.getAccount(0, 0)
  console.log('Wallet created!')
  console.log('Base Address:', account.baseAddressBech32)
  console.log('Enterprise Address:', account.enterpriseAddressBech32)
  console.log('Reward Address:', account.rewardAddressBech32)

  return wallet
}

Multi-Account Wallet

typescript
async function multiAccountWallet() {
  const wallet = new AppWallet({
    networkId: NETWORK_ID.PREPROD,
    key: {
      type: 'mnemonic',
      words: AppWallet.brew()
    }
  })

  // Generate multiple accounts
  const accounts = []
  for (let accountIndex = 0; accountIndex < 3; accountIndex++) {
    for (let addressIndex = 0; addressIndex < 5; addressIndex++) {
      const account = wallet.getAccount(accountIndex, addressIndex)
      accounts.push({
        accountIndex,
        addressIndex,
        address: account.baseAddressBech32
      })
    }
  }

  console.log('Generated accounts:', accounts)
  return accounts
}

Restore Wallet from Mnemonic

typescript
async function restoreWallet(mnemonicWords: string[]) {
  try {
    const wallet = new AppWallet({
      networkId: NETWORK_ID.PREPROD,
      key: {
        type: 'mnemonic',
        words: mnemonicWords
      }
    })

    const account = wallet.getAccount(0, 0)
    console.log('Wallet restored successfully!')
    console.log('Address:', account.baseAddressBech32)

    return wallet
  } catch (error) {
    console.error('Failed to restore wallet:', error)
    throw error
  }
}

// Usage
const mnemonic = [
  'abandon', 'abandon', 'abandon', 'abandon',
  'abandon', 'abandon', 'abandon', 'abandon',
  'abandon', 'abandon', 'abandon', 'about'
]
const restoredWallet = await restoreWallet(mnemonic)

Transaction Signing Example

typescript
import { TxBuilder } from '@hydra-sdk/transaction'

async function signTransaction() {
  const wallet = new AppWallet({
    networkId: NETWORK_ID.PREPROD,
    key: {
      type: 'mnemonic',
      words: AppWallet.brew()
    }
  })

  // Build transaction (using transaction builder)
  const txBuilder = new TxBuilder({
    fetcher: wallet.fetcher,
    submitter: wallet.submitter
  })

  const account = wallet.getAccount(0, 0)
  
  // Example: Build a simple payment transaction
  const tx = await txBuilder
    .txOut('addr_test1...', [{ unit: 'lovelace', quantity: '1000000' }])
    .changeAddress(account.baseAddressBech32)
    .complete()

  // Sign the transaction
  const signedTx = await wallet.signTx(
    tx.to_hex(),
    false, // complete signing
    0,     // account index
    0      // address index
  )

  console.log('Transaction signed:', signedTx)
  return signedTx
}

Wallet with Custom Network Provider

typescript
async function walletWithCustomProvider() {
  // Custom fetcher for Blockfrost
  const blockfrostFetcher: IFetcher = {
    fetchAddressUTxOs: async (address) => {
      const response = await fetch(
        `https://cardano-preprod.blockfrost.io/api/v0/addresses/${address}/utxos`,
        {
          headers: {
            'project_id': 'your_blockfrost_project_id'
          }
        }
      )
      return response.json()
    },
    
    fetchTxInfo: async (txHash) => {
      const response = await fetch(
        `https://cardano-preprod.blockfrost.io/api/v0/txs/${txHash}`,
        {
          headers: {
            'project_id': 'your_blockfrost_project_id'
          }
        }
      )
      return response.json()
    },
    
    fetchProtocolParameters: async () => {
      const response = await fetch(
        'https://cardano-preprod.blockfrost.io/api/v0/epochs/latest/parameters',
        {
          headers: {
            'project_id': 'your_blockfrost_project_id'
          }
        }
      )
      return response.json()
    }
  }

  // Custom submitter for Blockfrost
  const blockfrostSubmitter: ISubmitter = {
    submitTx: async (txCbor) => {
      const response = await fetch(
        'https://cardano-preprod.blockfrost.io/api/v0/tx/submit',
        {
          method: 'POST',
          headers: {
            'project_id': 'your_blockfrost_project_id',
            'Content-Type': 'application/cbor'
          },
          body: Buffer.from(txCbor, 'hex')
        }
      )
      
      if (!response.ok) {
        throw new Error(`Transaction submission failed: ${response.statusText}`)
      }
      
      return response.text() // Returns transaction hash
    }
  }

  const wallet = new AppWallet({
    networkId: NETWORK_ID.PREPROD,
    key: {
      type: 'mnemonic',
      words: AppWallet.brew()
    },
    fetcher: blockfrostFetcher,
    submitter: blockfrostSubmitter
  })

  return wallet
}

Key Management Utilities

typescript
async function keyManagementExample() {
  // Generate mnemonic
  const mnemonic = AppWallet.brew(256)
  console.log('Mnemonic:', mnemonic)

  // Convert mnemonic to private key
  const privateKeyHex = EmbeddedWallet.mnemonicToPrivateKeyHex(mnemonic)
  console.log('Private key (hex):', privateKeyHex)

  // Convert to bech32 format
  const privateKeyBech32 = EmbeddedWallet.privateKeyHexToBech32(privateKeyHex)
  console.log('Private key (bech32):', privateKeyBech32)

  // Create wallet from bech32 key
  const wallet = new AppWallet({
    networkId: NETWORK_ID.PREPROD,
    key: {
      type: 'root',
      bech32: privateKeyBech32
    }
  })

  const account = wallet.getAccount(0, 0)
  console.log('Address from bech32 key:', account.baseAddressBech32)
}

Error Handling

typescript
async function walletErrorHandling() {
  try {
    // Invalid mnemonic
    const wallet = new AppWallet({
      networkId: NETWORK_ID.PREPROD,
      key: {
        type: 'mnemonic',
        words: ['invalid', 'mnemonic', 'words']
      }
    })
  } catch (error) {
    console.error('Wallet creation failed:', error.message)
  }

  try {
    // Invalid transaction signing
    const wallet = new AppWallet({
      networkId: NETWORK_ID.PREPROD,
      key: {
        type: 'mnemonic',
        words: AppWallet.brew()
      }
    })

    const signedTx = await wallet.signTx(
      'invalid_cbor_hex',
      false,
      0,
      0
    )
  } catch (error) {
    console.error('Transaction signing failed:', error.message)
  }
}

Best Practices

  1. Secure Storage: Never store mnemonics or private keys in plain text
  2. Network Selection: Use PREPROD for testing, MAINNET for production
  3. Error Handling: Always wrap wallet operations in try-catch blocks
  4. Account Indexing: Use consistent account/address indexing patterns
  5. Key Derivation: Follow BIP44 standards for key derivation paths
  6. Transaction Validation: Validate transactions before signing
  7. Network Providers: Use reliable network providers for fetching and submission