npm package: @hydrawallet-sdk/transaction
Description: Hydra wallet
Latest version: 1.0.2
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

# @hydrawallet-sdk/transaction

Advanced transaction building library for Cardano DApps. This package provides a powerful and flexible transaction builder specifically designed for **Browser DApps** with full support for **Vite** and **Rollup**. Build complex Cardano transactions with ease, including smart contract interactions, minting, and multi-asset transfers.


[![Join us on Discord](https://img.shields.io/discord/1249288501383579738?color=5865F2&label=Join%20us%20on%20Discord&logo=discord&style=flat-square)](https://discord.gg/MaqrYbdKzM)

## 🎯 Purpose

**@hydrawallet-sdk/transaction** is the transaction building engine for browser-based Cardano DApps. Whether you're building DeFi protocols, NFT marketplaces, or complex smart contract applications, this library provides all the tools you need to construct, validate, and submit Cardano transactions.

## ✨ Key Features

- **🌐 Browser-Optimized**: Built specifically for browser DApps and web applications
- **⚡ Modern Build Tools**: Full compatibility with Vite, Rollup, and Webpack
- **🔧 Fluent API**: Intuitive method chaining for transaction building
- **🎯 Smart Contracts**: Complete Plutus script support (V1, V2, V3)
- **💎 Multi-Asset**: Native token and NFT transaction support
- **🏗️ Advanced Features**: Minting, burning, certificates, withdrawals
- **🔐 Security**: Built-in validation and error handling
- **📊 UTXO Management**: Intelligent coin selection algorithms
- **💰 Fee Calculation**: Automatic fee estimation and optimization

## 🛠️ Build Tool Integration

### Vite Configuration

```javascript
// vite.config.js
import { defineConfig } from 'vite'
import wasm from 'vite-plugin-wasm'
import topLevelAwait from 'vite-plugin-top-level-await'

export default defineConfig({
  plugins: [
    wasm(),
    topLevelAwait()
  ],
  optimizeDeps: {
    exclude: ['@hydrawallet-sdk/cardano-wasm']
  }
})
```

### Rollup Configuration

```javascript
// rollup.config.js
import wasm from '@rollup/plugin-wasm'

export default {
  plugins: [
    wasm({ maxFileSize: 0 })
  ],
  external: ['@hydrawallet-sdk/cardano-wasm']
}
```

## 📦 Installation

```bash
npm install @hydrawallet-sdk/transaction
# or
yarn add @hydrawallet-sdk/transaction
# or
pnpm add @hydrawallet-sdk/transaction
```

## 🚀 Quick Start

### Basic Transaction

```typescript
import { TxBuilder } from '@hydrawallet-sdk/transaction'
import { AppWallet, NETWORK_ID } from '@hydrawallet-sdk/core'

// Initialize wallet and transaction builder
const wallet = new AppWallet({
  networkId: NETWORK_ID.PREPROD,
  key: { type: 'mnemonic', words: 'your mnemonic here' }
})

const txBuilder = new TxBuilder({
  fetcher: wallet.fetcher,
  submitter: wallet.submitter
})

// Build a simple ADA transfer
const tx = await txBuilder
  .txOut('addr_test1...', [{ unit: 'lovelace', quantity: '1000000' }])
  .selectUtxosFrom(utxos)
  .changeAddress('addr_test1...')
  .complete()

console.log('Transaction built:', tx.to_hex())
```

### DApp Integration Example

```typescript
// DApp Transaction Service
class TransactionService {
  private txBuilder: TxBuilder

  constructor(wallet: AppWallet) {
    this.txBuilder = new TxBuilder({
      fetcher: wallet.fetcher,
      submitter: wallet.submitter,
      verbose: true // Enable logging for development
    })
  }

  async sendADA(
    fromAddress: string,
    toAddress: string,
    amount: string,
    utxos: UTxO[]
  ) {
    try {
      const tx = await this.txBuilder
        .txOut(toAddress, [{ unit: 'lovelace', quantity: amount }])
        .selectUtxosFrom(utxos)
        .changeAddress(fromAddress)
        .complete()

      return tx.to_hex()
    } catch (error) {
      console.error('Transaction failed:', error)
      throw error
    }
  }

  async sendNativeAsset(
    fromAddress: string,
    toAddress: string,
    policyId: string,
    assetName: string,
    quantity: string,
    utxos: UTxO[]
  ) {
    const assetUnit = policyId + assetName

    const tx = await this.txBuilder
      .txOut(toAddress, [
        { unit: 'lovelace', quantity: '1500000' }, // Min ADA
        { unit: assetUnit, quantity }
      ])
      .selectUtxosFrom(utxos)
      .changeAddress(fromAddress)
      .complete()

    return tx.to_hex()
  }
}
```

## 🏗️ Advanced Transaction Building

### Smart Contract Interaction

```typescript
// Interacting with Plutus scripts
class SmartContractService {
  private txBuilder: TxBuilder

  constructor(txBuilder: TxBuilder) {
    this.txBuilder = txBuilder
  }

  async unlockFromScript(
    scriptUtxo: UTxO,
    scriptCbor: string,
    datum: any,
    redeemer: any,
    collateralUtxos: UTxO[],
    changeAddress: string
  ) {
    const tx = await this.txBuilder
      // Add script input
      .txIn(
        scriptUtxo.input.txHash,
        scriptUtxo.input.outputIndex,
        scriptUtxo.output.amount,
        scriptUtxo.output.address
      )
      .txInScript(scriptCbor)
      .txInDatumValue(datum)
      .txInRedeemerValue(redeemer)
      .spendingPlutusScript('V2')
      
      // Add collateral
      .txInCollateral(
        collateralUtxos[0].input.txHash,
        collateralUtxos[0].input.outputIndex,
        collateralUtxos[0].output.amount,
        collateralUtxos[0].output.address
      )
      
      // Set change address
      .changeAddress(changeAddress)
      .complete()

    return tx.to_hex()
  }

  async lockToScript(
    scriptAddress: string,
    datum: any,
    amount: Asset[],
    utxos: UTxO[],
    changeAddress: string
  ) {
    const tx = await this.txBuilder
      .txOut(scriptAddress, amount)
      .txOutDatumHashValue(datum)
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()

    return tx.to_hex()
  }
}
```

### NFT Minting

```typescript
// NFT Minting Service
class NFTMintingService {
  private txBuilder: TxBuilder

  constructor(txBuilder: TxBuilder) {
    this.txBuilder = txBuilder
  }

  async mintNFT(
    policyId: string,
    assetName: string,
    metadata: any,
    mintingScript: string,
    redeemer: any,
    recipientAddress: string,
    utxos: UTxO[],
    changeAddress: string
  ) {
    const assetUnit = policyId + assetName

    const tx = await this.txBuilder
      // Mint the NFT
      .mint('1', policyId, assetName)
      .mintingScript(mintingScript)
      .mintRedeemerValue(redeemer)
      
      // Send to recipient
      .txOut(recipientAddress, [
        { unit: 'lovelace', quantity: '2000000' },
        { unit: assetUnit, quantity: '1' }
      ])
      
      // Add metadata
      .metadataValue('721', metadata)
      
      // Select UTxOs and set change
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()

    return tx.to_hex()
  }

  async burnNFT(
    policyId: string,
    assetName: string,
    burningScript: string,
    redeemer: any,
    utxos: UTxO[],
    changeAddress: string
  ) {
    const tx = await this.txBuilder
      // Burn the NFT (negative quantity)
      .mint('-1', policyId, assetName)
      .mintingScript(burningScript)
      .mintRedeemerValue(redeemer)
      
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()

    return tx.to_hex()
  }
}
```

### Multi-Asset Transactions

```typescript
// Multi-Asset Transaction Builder
class MultiAssetService {
  private txBuilder: TxBuilder

  constructor(txBuilder: TxBuilder) {
    this.txBuilder = txBuilder
  }

  async batchTransfer(
    transfers: Array<{
      address: string
      assets: Asset[]
    }>,
    utxos: UTxO[],
    changeAddress: string
  ) {
    let builder = this.txBuilder

    // Add all outputs
    transfers.forEach(transfer => {
      builder = builder.txOut(transfer.address, transfer.assets)
    })

    const tx = await builder
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()

    return tx.to_hex()
  }

  async swapAssets(
    fromAsset: Asset,
    toAsset: Asset,
    dexAddress: string,
    userAddress: string,
    utxos: UTxO[]
  ) {
    // Example DEX swap transaction
    const tx = await this.txBuilder
      // Send assets to DEX
      .txOut(dexAddress, [
        { unit: 'lovelace', quantity: '2000000' },
        fromAsset
      ])
      
      // Receive swapped assets
      .txOut(userAddress, [
        { unit: 'lovelace', quantity: '2000000' },
        toAsset
      ])
      
      .selectUtxosFrom(utxos)
      .changeAddress(userAddress)
      .complete()

    return tx.to_hex()
  }
}
```

## 🎯 React DApp Integration

```tsx
import React, { useState } from 'react'
import { TxBuilder } from '@hydrawallet-sdk/transaction'
import { AppWallet } from '@hydrawallet-sdk/core'

function TransactionBuilder({ wallet }: { wallet: AppWallet }) {
  const [txBuilder] = useState(() => new TxBuilder({
    fetcher: wallet.fetcher,
    submitter: wallet.submitter
  }))
  
  const [recipient, setRecipient] = useState('')
  const [amount, setAmount] = useState('')
  const [isBuilding, setIsBuilding] = useState(false)

  const buildTransaction = async () => {
    setIsBuilding(true)
    try {
      const account = wallet.getAccount(0, 0)
      const utxos = await wallet.getUtxos(account.address)

      const tx = await txBuilder
        .txOut(recipient, [{ unit: 'lovelace', quantity: amount }])
        .selectUtxosFrom(utxos)
        .changeAddress(account.address)
        .complete()

      console.log('Transaction built:', tx.to_hex())
      
      // Sign and submit
      const signedTx = await wallet.signTransaction(tx.to_hex())
      const txHash = await wallet.submitTransaction(signedTx)
      
      alert(`Transaction submitted: ${txHash}`)
    } catch (error) {
      console.error('Transaction failed:', error)
      alert('Transaction failed')
    } finally {
      setIsBuilding(false)
    }
  }

  return (
    <div className="transaction-builder">
      <h3>Send ADA</h3>
      <input
        type="text"
        placeholder="Recipient address"
        value={recipient}
        onChange={(e) => setRecipient(e.target.value)}
      />
      <input
        type="number"
        placeholder="Amount (lovelace)"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
      />
      <button 
        onClick={buildTransaction}
        disabled={isBuilding || !recipient || !amount}
      >
        {isBuilding ? 'Building...' : 'Send Transaction'}
      </button>
    </div>
  )
}
```

## 🎮 Vue DApp Integration

```vue
<template>
  <div class="transaction-builder">
    <h3>NFT Minting</h3>
    <form @submit.prevent="mintNFT">
      <input
        v-model="nftName"
        placeholder="NFT Name"
        required
      />
      <input
        v-model="nftDescription"
        placeholder="NFT Description"
        required
      />
      <input
        v-model="imageUrl"
        placeholder="Image URL"
        required
      />
      <button type="submit" :disabled="isMinting">
        {{ isMinting ? 'Minting...' : 'Mint NFT' }}
      </button>
    </form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { TxBuilder } from '@hydrawallet-sdk/transaction'
import { AppWallet } from '@hydrawallet-sdk/core'

const props = defineProps<{
  wallet: AppWallet
  policyId: string
  mintingScript: string
}>()

const nftName = ref('')
const nftDescription = ref('')
const imageUrl = ref('')
const isMinting = ref(false)

const txBuilder = new TxBuilder({
  fetcher: props.wallet.fetcher,
  submitter: props.wallet.submitter
})

const mintNFT = async () => {
  isMinting.value = true
  try {
    const account = props.wallet.getAccount(0, 0)
    const utxos = await props.wallet.getUtxos(account.address)
    
    const assetName = Buffer.from(nftName.value).toString('hex')
    const metadata = {
      [props.policyId]: {
        [nftName.value]: {
          name: nftName.value,
          description: nftDescription.value,
          image: imageUrl.value
        }
      }
    }

    const tx = await txBuilder
      .mint('1', props.policyId, assetName)
      .mintingScript(props.mintingScript)
      .txOut(account.address, [
        { unit: 'lovelace', quantity: '2000000' },
        { unit: props.policyId + assetName, quantity: '1' }
      ])
      .metadataValue('721', metadata)
      .selectUtxosFrom(utxos)
      .changeAddress(account.address)
      .complete()

    const signedTx = await props.wallet.signTransaction(tx.to_hex())
    const txHash = await props.wallet.submitTransaction(signedTx)
    
    alert(`NFT minted successfully: ${txHash}`)
  } catch (error) {
    console.error('Minting failed:', error)
    alert('Minting failed')
  } finally {
    isMinting.value = false
  }
}
</script>
```

## 🔧 Advanced Configuration

### Custom Protocol Parameters

```typescript
import { TxBuilder, DEFAULT_PROTOCOL_PARAMETERS } from '@hydrawallet-sdk/transaction'

const customParams = {
  ...DEFAULT_PROTOCOL_PARAMETERS,
  minFeeA: 44,
  minFeeB: 155381,
  maxTxSize: 16384,
  maxValSize: 5000
}

const txBuilder = new TxBuilder({
  params: customParams,
  verbose: true
})
```

### Coin Selection Strategies

```typescript
import { TxBuilder, COIN_SELECTION_STRATEGY } from '@hydrawallet-sdk/transaction'

// Different coin selection strategies
const strategies = [
  'LargestFirst',           // Select largest UTxOs first
  'RandomImprove',          // Random improvement algorithm
  'LargestFirstMultiAsset', // Optimized for multi-asset
  'RandomImproveMultiAsset' // Random improve for multi-asset
]

const tx = await txBuilder
  .txOut(address, assets)
  .selectUtxosFrom(utxos, 'LargestFirstMultiAsset')
  .changeAddress(changeAddress)
  .complete()
```

### Fee Estimation

```typescript
// Estimate transaction fees
class FeeEstimator {
  private txBuilder: TxBuilder

  constructor(txBuilder: TxBuilder) {
    this.txBuilder = txBuilder
  }

  async estimateFee(
    outputs: Array<{ address: string; assets: Asset[] }>,
    utxos: UTxO[],
    changeAddress: string
  ) {
    let builder = this.txBuilder

    outputs.forEach(output => {
      builder = builder.txOut(output.address, output.assets)
    })

    // Build transaction to calculate fees
    const tx = await builder
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()

    const fee = tx.body().fee().to_str()
    return fee
  }
}
```

## 📚 Complete API Reference

### TxBuilder Class

#### Constructor
```typescript
new TxBuilder(options?: TxBuilderOptions)

interface TxBuilderOptions {
  fetcher?: IFetcher
  submitter?: ISubmitter
  isHydra?: boolean
  params?: Partial<Protocol>
  verbose?: boolean
}
```

#### Transaction Outputs
```typescript
txOut(address: string, amount: Asset[]): TxBuilder
txOutDatumHashValue(datum: any): TxBuilder
txOutInlineDatumValue(datum: any): TxBuilder
txOutReferenceScript(script: string): TxBuilder
```

#### Transaction Inputs
```typescript
txIn(txHash: string, outputIndex: number, amount?: Asset[], address?: string): TxBuilder
txInScript(scriptCbor: string): TxBuilder
txInDatumValue(datum: any): TxBuilder
txInRedeemerValue(redeemer: any): TxBuilder
spendingPlutusScript(version: PlutusVersion): TxBuilder
```

#### Minting and Burning
```typescript
mint(quantity: string, policyId: string, assetName: string): TxBuilder
mintingScript(scriptCbor: string): TxBuilder
mintRedeemerValue(redeemer: any): TxBuilder
```

#### UTXO Selection
```typescript
selectUtxosFrom(utxos: UTxO[], strategy?: CoinSelectionStrategy): TxBuilder
changeAddress(address: string): TxBuilder
```

#### Metadata and Certificates
```typescript
metadataValue(label: string, metadata: any): TxBuilder
certificate(cert: Certificate): TxBuilder
withdrawal(rewardAddress: string, amount: string): TxBuilder
```

#### Collateral and Signing
```typescript
txInCollateral(txHash: string, outputIndex: number, amount: Asset[], address: string): TxBuilder
requiredSignerHash(pubKeyHash: string): TxBuilder
validityStartInterval(slot: number): TxBuilder
validityEndInterval(slot: number): TxBuilder
```

#### Building
```typescript
complete(): Promise<CardanoWASM.Transaction>
```

### Type Definitions

```typescript
interface Asset {
  unit: string
  quantity: string
}

interface UTxO {
  input: {
    txHash: string
    outputIndex: number
  }
  output: {
    address: string
    amount: Asset[]
    datum?: any
  }
}

interface TxOutput {
  address: string
  amount: Asset[]
  datum?: any
  scriptRef?: string
}

type PlutusVersion = 'V1' | 'V2' | 'V3'
type CoinSelectionStrategy = 'LargestFirst' | 'RandomImprove' | 'LargestFirstMultiAsset' | 'RandomImproveMultiAsset'
```

## 🧪 Testing

### Unit Testing

```typescript
import { TxBuilder } from '@hydrawallet-sdk/transaction'
import { describe, test, expect } from 'vitest'

describe('TxBuilder', () => {
  test('should build simple transaction', async () => {
    const txBuilder = new TxBuilder()
    
    const tx = await txBuilder
      .txOut('addr_test1...', [{ unit: 'lovelace', quantity: '1000000' }])
      .selectUtxosFrom(mockUtxos)
      .changeAddress('addr_test1...')
      .complete()

    expect(tx).toBeDefined()
    expect(tx.body().outputs().len()).toBe(2) // Output + change
  })

  test('should handle multi-asset transactions', async () => {
    const assets = [
      { unit: 'lovelace', quantity: '2000000' },
      { unit: 'policy123...asset456', quantity: '100' }
    ]

    const tx = await txBuilder
      .txOut('addr_test1...', assets)
      .selectUtxosFrom(mockUtxos)
      .changeAddress('addr_test1...')
      .complete()

    expect(tx.body().outputs().get(0).amount().multiasset()).toBeDefined()
  })
})
```

### Integration Testing

```typescript
describe('DApp Transaction Integration', () => {
  test('should handle complete transaction flow', async () => {
    const wallet = new AppWallet({ /* config */ })
    const txBuilder = new TxBuilder({
      fetcher: wallet.fetcher,
      submitter: wallet.submitter
    })

    const account = wallet.getAccount(0, 0)
    const utxos = await wallet.getUtxos(account.address)

    const tx = await txBuilder
      .txOut('addr_test1...', [{ unit: 'lovelace', quantity: '1000000' }])
      .selectUtxosFrom(utxos)
      .changeAddress(account.address)
      .complete()

    const signedTx = await wallet.signTransaction(tx.to_hex())
    expect(signedTx).toBeTruthy()
  })
})
```

## 🚀 Performance Optimization

### Batch Operations

```typescript
// Batch multiple operations for better performance
class BatchTransactionService {
  private txBuilder: TxBuilder

  constructor(txBuilder: TxBuilder) {
    this.txBuilder = txBuilder
  }

  async batchMint(
    mints: Array<{
      policyId: string
      assetName: string
      quantity: string
      recipient: string
    }>,
    mintingScript: string,
    utxos: UTxO[],
    changeAddress: string
  ) {
    let builder = this.txBuilder.mintingScript(mintingScript)

    // Add all mints
    mints.forEach(mint => {
      builder = builder
        .mint(mint.quantity, mint.policyId, mint.assetName)
        .txOut(mint.recipient, [
          { unit: 'lovelace', quantity: '2000000' },
          { unit: mint.policyId + mint.assetName, quantity: mint.quantity }
        ])
    })

    return await builder
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()
  }
}
```

## 🔒 Security Best Practices

### Input Validation

```typescript
class SecureTransactionBuilder {
  private txBuilder: TxBuilder

  constructor(txBuilder: TxBuilder) {
    this.txBuilder = txBuilder
  }

  validateAddress(address: string): boolean {
    try {
      // Use CardanoWASM to validate address
      return AppWallet.validateAddress(address)
    } catch {
      return false
    }
  }

  validateAmount(amount: string): boolean {
    const num = parseInt(amount)
    return num > 0 && num <= Number.MAX_SAFE_INTEGER
  }

  async safeBuildTransaction(
    recipient: string,
    amount: string,
    utxos: UTxO[],
    changeAddress: string
  ) {
    // Validate inputs
    if (!this.validateAddress(recipient)) {
      throw new Error('Invalid recipient address')
    }
    
    if (!this.validateAmount(amount)) {
      throw new Error('Invalid amount')
    }

    if (!this.validateAddress(changeAddress)) {
      throw new Error('Invalid change address')
    }

    // Build transaction
    return await this.txBuilder
      .txOut(recipient, [{ unit: 'lovelace', quantity: amount }])
      .selectUtxosFrom(utxos)
      .changeAddress(changeAddress)
      .complete()
  }
}
```

## 📄 License

MIT License - see [LICENSE](../../LICENSE) file for details.

## 🔗 Related Resources

- **Core Package**: [`@hydrawallet-sdk/core`](../hydra-wallet/README.md) - Core wallet functionality
- **WASM Package**: [`@hydrawallet-sdk/cardano-wasm`](../cardano-wasm/README.md) - Cardano WASM bindings
- **Documentation**: [Hydra Wallet SDK Docs](https://hydrawallet-sdk.dev)
- **Examples**: [Transaction Examples](../../examples/transactions/)
- **Community**: [Discord](https://discord.gg/hydrawallet)

---

**@hydrawallet-sdk/transaction** - Advanced transaction building for Cardano DApps with Vite & Rollup support