Skip to main content
Create refined branded types with runtime validation using Effect’s Brand module. Use for new types based on primitives (string, number, bigint).
import { Wei, Gas, BlockNumber, ChainId } from 'voltaire-effect/primitives/Brand'

const gasLimit = Gas(21000n)           // Must be positive
const amount = Wei(1000000000000000000n) // Must be non-negative
const block = BlockNumber(19000000n)   // Must be non-negative
const chain = ChainId(1n)              // Must be positive

Why Brand vs Schema

Use Schema for existing Voltaire types (Address, Hash, Hex):
import * as Address from 'voltaire-effect/primitives/Address'
import * as S from 'effect/Schema'

const addr = S.decodeSync(Address.Hex)('0x...')
Use Brand for new types based on primitives:
import { Gas } from 'voltaire-effect/primitives/Brand'

const gas = Gas(21000n) // Validated positive bigint

Available Types

Numeric Brands

TypeBaseConstraint
PositiveIntnumberInteger > 0
NonNegativeIntnumberInteger >= 0
Weibigint>= 0
Gweibigint>= 0
Gasbigint> 0

Ethereum Brands

TypeBaseConstraint
BlockNumberbigint>= 0
ChainIdbigint> 0
Noncebigint>= 0

Nominal Brands (No Validation)

For already-validated values where you just want type distinction:
import { TxHashString, AddressString } from 'voltaire-effect/primitives/Brand'

// No runtime validation, just type branding
const hash = TxHashString('0xabc123...')
const addr = AddressString('0x742d35...')

Creating Custom Brands

import { Brand } from 'voltaire-effect/primitives/Brand'

// Refined type with validation
type PositiveEther = bigint & Brand.Brand<"PositiveEther">

const PositiveEther = Brand.refined<PositiveEther>(
  (n): n is Brand.Brand.Unbranded<PositiveEther> => n > 0n,
  (n) => Brand.error(`Expected positive ether, got ${n}`)
)

// Usage
const amount = PositiveEther(1n) // ok
const bad = PositiveEther(-1n)   // throws

Type Usage in Functions

import { Gas, Wei } from 'voltaire-effect/primitives/Brand'

function estimateCost(gasLimit: Gas, gasPrice: Wei): Wei {
  return Wei(BigInt(gasLimit) * BigInt(gasPrice))
}

// Type-safe - can't pass unbranded values
const cost = estimateCost(Gas(21000n), Wei(20000000000n))

See Also