Resources

Migration

Upgrade paths for Hydra SDK — bridge v1.x → v2.0, and the earlier v1.1.x utilities system.

@hydra-sdk/bridge v1.x → v2.0

@hydra-sdk/bridge 2.0 targets hydra-node 2.x. It is a breaking change, and bridge 1.x is end of life.

v2 is published under the next dist-tag — latest still resolves to 1.3.2.
pnpm add @hydra-sdk/bridge@next

Why it breaks

hydra-node v2 implements ADR-33 and removes the commit phase. A head now opens directly, so there is nothing to abort and no Committed step; funds enter an open head through incremental deposits instead.

What you have to change

v1.xv2.0
bridge.commands.abort()Removed — no commit phase to abort
bridge.commands.initSync()Resolves on HeadIsOpen, not HeadIsInitializing
HeadIsOpen handlersReads parties; utxo is gone — take the UTxO set from SnapshotConfirmed or querySnapshotUtxo()
HeadIsFinalized.utxoRenamed to finalizedUTxO
HydraHeadStatusNo Initializing / Final
HydraHeadInfoNow a union over `Idle
Greetings / ClientMessageNo seq / timestamp — they are sent untimed

Full details

The complete list, including the new APIs (safeClose(), submitL2Tx(), pendingDeposits(), recoverDeposit()) and the wire-format fixes found by testing against a live node, is in MIGRATION-v2.md.


Migration to v1.1.x (legacy)

This guide helps you upgrade from previous versions of Hydra SDK to v1.1.x, which introduces a new utilities system and improved developer experience.

What's Changed

New Utilities System

Version 1.1.0 introduces a completely revamped utilities system with organized namespaces:

Before (v1.0.x):

// Individual utility imports (if available)
import { someUtility } from '@hydra-sdk/core/utils/some-utility'

After (v1.1.x):

// Organized namespace imports
import { 
  ParserUtils,
  TimeUtils,
  DatumUtils,
  PolicyUtils,
  Serializer,
  Deserializer 
} from '@hydra-sdk/core'

Breaking Changes

1. Utility Function Organization

Before:

// Direct imports from utils (if they existed)
import { hexToBytes, bytesToHex } from '@hydra-sdk/core/utils'

After:

// Namespaced utility imports
import { ParserUtils } from '@hydra-sdk/core'

const hex = ParserUtils.bytesToHex(bytes)
const bytes = ParserUtils.hexToBytes(hex)

2. Time/Slot Utilities

Before:

// Manual slot calculations or external libraries
const currentSlot = calculateSlot(Date.now())

After:

import { TimeUtils, SLOT_CONFIG_NETWORK } from '@hydra-sdk/core'
const currentSlot = TimeUtils.unixTimeToEnclosingSlot(
    Date.now(), 
    SLOT_CONFIG_NETWORK.PREPROD
)
const futureSlot = TimeUtils.unixTimeToEnclosingSlot(
    Date.now() + 3600000, 
    SLOT_CONFIG_NETWORK.PREPROD
)

3. Datum Creation

Before:

// Manual WASM operations
import { CardanoWASM } from '@hydra-sdk/cardano-wasm'

const datum = CardanoWASM.PlutusData.new_integer(
  CardanoWASM.BigInt.from_str('42')
)

After:

import { DatumUtils } from '@hydra-sdk/core'

const datum = DatumUtils.mkInt(42)
const bytesDatum = DatumUtils.mkBytes('deadbeef')
const constrDatum = DatumUtils.mkConstr(0, [datum, bytesDatum])

Migration Steps

Step 1: Update Dependencies

# Update to latest version
npm update @hydra-sdk/core @hydra-sdk/bridge @hydra-sdk/transaction @hydra-sdk/cardano-wasm

# Or with specific version
npm install @hydra-sdk/core@^1.1.0 @hydra-sdk/cardano-wasm

Step 2: Update Imports

Replace individual utility imports with namespace imports:

// OLD - Remove these
import { someUtility } from '@hydra-sdk/core/utils/some-utility'
import { CardanoWASM } from '@hydra-sdk/cardano-wasm'

// NEW - Use these instead
import { 
  ParserUtils,
  TimeUtils,
  DatumUtils,
  PolicyUtils,
  Serializer,
  Deserializer,
  Resolver,
  Converter,
  BuildKeys,
  ProviderUtils,
  CostModels 
} from '@hydra-sdk/core'

Step 3: Replace Manual Operations

Data Conversion

// OLD
const hex = Buffer.from(bytes).toString('hex')
const bytes = Buffer.from(hex, 'hex')

// NEW
import { ParserUtils } from '@hydra-sdk/core'
const hex = ParserUtils.bytesToHex(bytes)
const bytes = ParserUtils.hexToBytes(hex)

Time Calculations

// OLD
const slot = Math.floor((Date.now() - SHELLEY_START) / SLOT_LENGTH) + SHELLEY_SLOT_START

// NEW
import { TimeUtils, SLOT_CONFIG_NETWORK } from '@hydra-sdk/core'
const slot = TimeUtils.unixTimeToEnclosingSlot(Date.now(), SLOT_CONFIG_NETWORK.PREPROD)

Datum Creation

// OLD - Complex WASM operations
import { CardanoWASM } from '@hydra-sdk/cardano-wasm'
const datum = CardanoWASM.PlutusData.new_constr_plutus_data(
  CardanoWASM.ConstrPlutusData.new(
    CardanoWASM.BigNum.from_str('0'),
    list
  )
)

// NEW - Simple utility functions
import { DatumUtils } from '@hydra-sdk/core'
const datum = DatumUtils.mkConstr(0, [field1, field2])

Step 4: Update Provider Usage

If you were using custom provider implementations:

// OLD - Custom provider setup
class MyProvider {
  async getUtxos(address) {
    // Custom implementation
  }
}

// NEW - Use built-in providers or extend base
import { ProviderUtils } from '@hydra-sdk/core'

const provider = new ProviderUtils.BlockfrostProvider({
  apiKey: 'your-blockfrost-api-key',
  network: 'preprod'
})

// Or extend a built-in provider to customize behavior
class MyProvider extends ProviderUtils.BlockfrostProvider {
  constructor() {
    super({ apiKey: 'your-blockfrost-api-key', network: 'preprod' })
  }

  // Inherited `.fetcher` / `.submitter` still work
  async getUtxos(address: string) {
    return this.fetcher.fetchAddressUTxOs(address)
  }
}

Common Migration Patterns

Pattern 1: Metadata Creation

Before:

const metadata = {
  721: {
    [policyId]: {
      [tokenName]: {
        name: Buffer.from(name).toString('hex'),
        image: Buffer.from(image).toString('hex')
      }
    }
  }
}

After:

import { ParserUtils, DatumUtils } from '@hydra-sdk/core'

const metadata = {
  721: {
    [policyId]: {
      [tokenName]: {
        name: ParserUtils.stringToHex(name),
        image: ParserUtils.stringToHex(image)
      }
    }
  }
}

// Or create as datum
const metadataDatum = DatumUtils.mkMap([
  [DatumUtils.mkBytes(ParserUtils.stringToHex("name")), 
   DatumUtils.mkBytes(ParserUtils.stringToHex(name))],
  [DatumUtils.mkBytes(ParserUtils.stringToHex("image")), 
   DatumUtils.mkBytes(ParserUtils.stringToHex(image))]
])

Pattern 2: Transaction Timing

Before:

// Manual slot calculation
const validFrom = getCurrentSlot()
const validUntil = validFrom + 7200 // 1 hour in slots

After:

import { TimeUtils, SLOT_CONFIG_NETWORK } from '@hydra-sdk/core'

const validFrom = TimeUtils.unixTimeToEnclosingSlot(Date.now(), SLOT_CONFIG_NETWORK.PREPROD)
const validUntil = TimeUtils.unixTimeToEnclosingSlot(Date.now() + 3600000, SLOT_CONFIG_NETWORK.PREPROD)

Pattern 3: Policy Script Creation

Before:

// Manual WASM operations for policy
import { CardanoWASM } from '@hydra-sdk/cardano-wasm'

const keyHash = CardanoWASM.Ed25519KeyHash.from_hex(publicKeyHash)
const scriptPubkey = CardanoWASM.ScriptPubkey.new(keyHash)
const policy = CardanoWASM.NativeScript.new_script_pubkey(scriptPubkey)

After:

import { PolicyUtils } from '@hydra-sdk/core'

const policy = PolicyUtils.buildPolicyScriptFromPubkey({
  type: 'sig',
  keyHash: publicKeyHash
})

// Or from address
const policy = PolicyUtils.buildMintingPolicyScriptFromAddress(address)

Testing Your Migration

1. Basic Functionality Test

import { 
  AppWallet, 
  NETWORK_ID,
  ParserUtils,
  TimeUtils,
  DatumUtils 
} from '@hydra-sdk/core'

// Test wallet creation (should work as before)
const wallet = new AppWallet({
  networkId: NETWORK_ID.PREPROD,
  key: { type: 'mnemonic', words: AppWallet.brew() }
})

// Test new utilities
const hex = ParserUtils.stringToHex('test')
const slot = TimeUtils.resolveSlotNo('preprod')
const datum = DatumUtils.mkInt(42)

console.log('Migration test passed:', {
  address: wallet.getAccount(0, 0).baseAddressBech32,
  hex,
  slot,
  datumHex: datum.to_hex()
})

2. Data Conversion Test

import { ParserUtils } from '@hydra-sdk/core'

const testData = [
  'Hello World',
  '🚀 Hydra SDK',
  'Special chars: åøæ'
]

testData.forEach(str => {
  const hex = ParserUtils.stringToHex(str)
  const back = Buffer.from(hex, 'hex').toString('utf8')
  
  console.assert(str === back, `Conversion failed for: ${str}`)
})

console.log('Data conversion tests passed')

3. Time Utilities Test

import { TimeUtils, SLOT_CONFIG_NETWORK } from '@hydra-sdk/core'

const networks = ['MAINNET', 'PREPROD', 'PREVIEW'] as const

networks.forEach(network => {
  const slot = TimeUtils.unixTimeToEnclosingSlot(Date.now(), SLOT_CONFIG_NETWORK[network])
  console.assert(typeof slot === 'number' && slot > 0, `Invalid slot for network: ${network}`)
})

console.log('Time utilities tests passed')

Troubleshooting

Common Issues

  1. Import Errors
    Error: Module not found: @hydra-sdk/core/utils/...
    

    Solution: Use namespace imports instead of deep imports.
  2. Type Errors with Utilities
    Error: Property 'stringToHex' does not exist on type...
    

    Solution: Import the correct namespace: ParserUtils.stringToHex
  3. Slot Calculation Issues
    Error: Invalid network parameter
    

    Solution: Use exact network strings: 'mainnet', 'preprod', or 'preview'

Getting Help

If you encounter issues during migration:

  1. Check the Utilities API Reference
  2. Review Working with Utilities Guide
  3. Look at Utilities Examples
  4. Join our community Discord for support

Benefits of v1.1.0

After migration, you'll enjoy:

  • Better Developer Experience: Organized, predictable utility functions
  • Type Safety: Comprehensive TypeScript definitions
  • Performance: Optimized utility implementations
  • Maintainability: Cleaner, more readable code
  • Future-Proof: Foundation for upcoming features

The migration effort pays off with significantly improved development experience and code quality.