Files
FrenoCorp/node_modules/ox/core/Blobs.ts
Michael Freno 7c684a42cc FRE-600: Fix code review blockers
- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 00:08:01 -04:00

944 lines
27 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as Bytes from './Bytes.js'
import * as Errors from './Errors.js'
import * as Hash from './Hash.js'
import * as Hex from './Hex.js'
import * as Kzg from './Kzg.js'
import * as Cursor from './internal/cursor.js'
import type { Compute, Mutable, OneOf, UnionCompute } from './internal/types.js'
/** Blob limit per transaction. */
const blobsPerTransaction = 6
/** The number of bytes in a BLS scalar field element. */
export const bytesPerFieldElement = 32
/** The number of field elements in a blob. */
export const fieldElementsPerBlob = 4096
/** The number of bytes in a blob. */
export const bytesPerBlob = bytesPerFieldElement * fieldElementsPerBlob
/** Blob bytes limit per transaction. */
export const maxBytesPerTransaction =
bytesPerBlob * blobsPerTransaction -
// terminator byte (0x80).
1 -
// zero byte (0x00) appended to each field element.
1 * fieldElementsPerBlob * blobsPerTransaction
/** Root type for a Blob. */
export type Blob<type extends Hex.Hex | Bytes.Bytes = Hex.Hex | Bytes.Bytes> =
type
/** A list of {@link ox#Blobs.Blob}. */
export type Blobs<type extends Hex.Hex | Bytes.Bytes = Hex.Hex | Bytes.Bytes> =
readonly Blob<type>[]
/** Type for a Blob Sidecar that contains a blob, as well as its KZG commitment and proof. */
export type BlobSidecar<
type extends Hex.Hex | Bytes.Bytes = Hex.Hex | Bytes.Bytes,
> = Compute<{
/** The blob associated with the transaction. */
blob: type
/** The KZG commitment corresponding to this blob. */
commitment: type
/** The KZG proof corresponding to this blob and commitment. */
proof: type
}>
/**
* Transform a list of Commitments to Blob Versioned Hashes.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, { kzg })
* const versionedHashes = Blobs.commitmentsToVersionedHashes(commitments) // [!code focus]
* // @log: ['0x...', '0x...']
* ```
*
* @example
* ### Configuring Return Type
*
* It is possible to configure the return type for the Versioned Hashes with the `as` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, { kzg })
* const versionedHashes = Blobs.commitmentsToVersionedHashes(commitments, {
* as: 'Bytes', // [!code focus]
* })
* // @log: [Uint8Array [ ... ], Uint8Array [ ... ]]
* ```
*
* @example
* ### Versioning Hashes
*
* It is possible to configure the version for the Versioned Hashes with the `version` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, { kzg })
* const versionedHashes = Blobs.commitmentsToVersionedHashes(commitments, {
* version: 2, // [!code focus]
* })
* ```
*
* @param commitments - A list of commitments.
* @param options - Options.
* @returns A list of Blob Versioned Hashes.
*/
export function commitmentsToVersionedHashes<
const commitments extends readonly Bytes.Bytes[] | readonly Hex.Hex[],
as extends 'Hex' | 'Bytes' =
| (commitments extends readonly Hex.Hex[] ? 'Hex' : never)
| (commitments extends readonly Bytes.Bytes[] ? 'Bytes' : never),
>(
commitments: commitments | readonly Bytes.Bytes[] | readonly Hex.Hex[],
options: commitmentsToVersionedHashes.Options<as> = {},
): commitmentsToVersionedHashes.ReturnType<as> {
const { version } = options
const as =
options.as ?? (typeof commitments[0] === 'string' ? 'Hex' : 'Bytes')
const hashes: Uint8Array[] | Hex.Hex[] = []
for (const commitment of commitments) {
hashes.push(
commitmentToVersionedHash(commitment, {
as,
version,
}) as never,
)
}
return hashes as never
}
export declare namespace commitmentsToVersionedHashes {
type Options<as extends 'Hex' | 'Bytes' | undefined = undefined> = {
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
/** Version to tag onto the hashes. */
version?: number | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? readonly Bytes.Bytes[] : never)
| (as extends 'Hex' ? readonly Hex.Hex[] : never)
type ErrorType = Errors.GlobalErrorType
}
/**
* Transform a Commitment to its Blob Versioned Hash.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const [commitment] = Blobs.toCommitments(blobs, { kzg })
* const versionedHash = Blobs.commitmentToVersionedHash(commitment) // [!code focus]
* ```
*
* @example
* ### Configuring Return Type
*
* It is possible to configure the return type for the Versioned Hash with the `as` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const [commitment] = Blobs.toCommitments(blobs, { kzg })
* const versionedHashes = Blobs.commitmentToVersionedHash(commitment, {
* as: 'Bytes', // [!code focus]
* })
* // @log: [Uint8Array [ ... ], Uint8Array [ ... ]]
* ```
*
* @example
* ### Versioning Hashes
*
* It is possible to configure the version for the Versioned Hash with the `version` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const [commitment] = Blobs.toCommitments(blobs, { kzg })
* const versionedHashes = Blobs.commitmentToVersionedHash(commitment, {
* version: 2, // [!code focus]
* })
* ```
*
* @param commitment - The commitment.
* @param options - Options.
* @returns The Blob Versioned Hash.
*/
export function commitmentToVersionedHash<
const commitment extends Hex.Hex | Bytes.Bytes,
as extends 'Hex' | 'Bytes' =
| (commitment extends Hex.Hex ? 'Hex' : never)
| (commitment extends Bytes.Bytes ? 'Bytes' : never),
>(
commitment: commitment | Hex.Hex | Bytes.Bytes,
options: commitmentToVersionedHash.Options<as> = {},
): commitmentToVersionedHash.ReturnType<as> {
const { version = 1 } = options
const as = options.as ?? (typeof commitment === 'string' ? 'Hex' : 'Bytes')
const versionedHash = Hash.sha256(commitment, { as: 'Bytes' })
versionedHash.set([version], 0)
return (
as === 'Bytes' ? versionedHash : Hex.fromBytes(versionedHash)
) as commitmentToVersionedHash.ReturnType<as>
}
export declare namespace commitmentToVersionedHash {
type Options<as extends 'Hex' | 'Bytes' | undefined = undefined> = {
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
/** Version to tag onto the hash. */
version?: number | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? Bytes.Bytes : never)
| (as extends 'Hex' ? Hex.Hex : never)
type ErrorType = Errors.GlobalErrorType
}
/**
* Transforms arbitrary data to {@link ox#Blobs.Blobs}.
*
* @example
* ```ts twoslash
* import { Blobs } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef')
* ```
*
* @example
* ### Creating Blobs from a String
*
* An example of creating Blobs from a string using {@link ox#Hex.(from:function)}:
*
* ```ts twoslash
* import { Blobs, Hex } from 'ox'
*
* const blobs = Blobs.from(Hex.fromString('Hello world!'))
* ```
*
* @example
* ### Configuring Return Type
*
* It is possible to configure the return type for the Blobs with the `as` option.
*
* ```ts twoslash
* import { Blobs } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef', { as: 'Bytes' })
* // ^?
*
*
* ```
*
* @param data - The data to convert to {@link ox#Blobs.Blobs}.
* @param options - Options.
* @returns The {@link ox#Blobs.Blobs}.
*/
export function from<
const data extends Hex.Hex | Bytes.Bytes,
as extends 'Hex' | 'Bytes' =
| (data extends Hex.Hex ? 'Hex' : never)
| (data extends Bytes.Bytes ? 'Bytes' : never),
>(
data: data | Hex.Hex | Bytes.Bytes,
options: from.Options<as> = {},
): from.ReturnType<as> {
const as = options.as ?? (typeof data === 'string' ? 'Hex' : 'Bytes')
const data_ = (
typeof data === 'string' ? Bytes.fromHex(data) : data
) as Bytes.Bytes
const size_ = Bytes.size(data_)
if (!size_) throw new EmptyBlobError()
if (size_ > maxBytesPerTransaction)
throw new BlobSizeTooLargeError({
maxSize: maxBytesPerTransaction,
size: size_,
})
const blobs = []
let active = true
let position = 0
while (active) {
const blob = Cursor.create(new Uint8Array(bytesPerBlob))
let size = 0
while (size < fieldElementsPerBlob) {
const bytes = data_.slice(position, position + (bytesPerFieldElement - 1))
// Push a zero byte so the field element doesn't overflow the BLS modulus.
blob.pushByte(0x00)
// Push the current segment of data bytes.
blob.pushBytes(bytes)
// If we detect that the current segment of data bytes is less than 31 bytes,
// we can stop processing and push a terminator byte to indicate the end of the blob.
if (bytes.length < 31) {
blob.pushByte(0x80)
active = false
break
}
size++
position += 31
}
blobs.push(blob)
}
return (
as === 'Bytes'
? blobs.map((x) => x.bytes)
: blobs.map((x) => Hex.fromBytes(x.bytes))
) as never
}
export declare namespace from {
type Options<as extends 'Hex' | 'Bytes' | undefined = undefined> = {
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? readonly Bytes.Bytes[] : never)
| (as extends 'Hex' ? readonly Hex.Hex[] : never)
type ErrorType =
| BlobSizeTooLargeError
| EmptyBlobError
| Bytes.fromHex.ErrorType
| Hex.fromBytes.ErrorType
| Cursor.create.ErrorType
| Bytes.size.ErrorType
| Errors.GlobalErrorType
}
/**
* Transforms a list of {@link ox#Blobs.BlobSidecars} to their Blob Versioned Hashes.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef')
* const sidecars = Blobs.toSidecars(blobs, { kzg })
* const versionedHashes = Blobs.sidecarsToVersionedHashes(sidecars) // [!code focus]
* ```
*
* @example
* ### Configuring Return Type
*
* It is possible to configure the return type for the Versioned Hashes with the `as` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const sidecars = Blobs.toSidecars(blobs, { kzg })
* const versionedHashes = Blobs.sidecarsToVersionedHashes(sidecars, {
* as: 'Bytes', // [!code focus]
* })
* // @log: [Uint8Array [ ... ], Uint8Array [ ... ]]
* ```
*
* @example
* ### Versioning Hashes
*
* It is possible to configure the version for the Versioned Hashes with the `version` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const sidecars = Blobs.toSidecars(blobs, { kzg })
* const versionedHashes = Blobs.sidecarsToVersionedHashes(sidecars, {
* version: 2, // [!code focus]
* })
* ```
*
* @param sidecars - The {@link ox#Blobs.BlobSidecars} to transform to Blob Versioned Hashes.
* @param options - Options.
* @returns The versioned hashes.
*/
export function sidecarsToVersionedHashes<
const sidecars extends BlobSidecars,
as extends 'Hex' | 'Bytes' =
| (sidecars extends BlobSidecars<Hex.Hex> ? 'Hex' : never)
| (sidecars extends BlobSidecars<Bytes.Bytes> ? 'Bytes' : never),
>(
sidecars: sidecars | BlobSidecars,
options: sidecarsToVersionedHashes.Options<as> = {},
): sidecarsToVersionedHashes.ReturnType<as> {
const { version } = options
const as =
options.as ?? (typeof sidecars[0]!.blob === 'string' ? 'Hex' : 'Bytes')
const hashes: Uint8Array[] | Hex.Hex[] = []
for (const { commitment } of sidecars) {
hashes.push(
commitmentToVersionedHash(commitment, {
as,
version,
}) as any,
)
}
return hashes as any
}
export declare namespace sidecarsToVersionedHashes {
type Options<as extends 'Hex' | 'Bytes' | undefined = undefined> = {
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
/** Version to tag onto the hashes. */
version?: number | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? readonly Bytes.Bytes[] : never)
| (as extends 'Hex' ? readonly Hex.Hex[] : never)
type ErrorType = commitmentToVersionedHash.ErrorType | Errors.GlobalErrorType
}
/**
* Transforms Ox-shaped {@link ox#Blobs.Blobs} into the originating data.
*
* @example
* ```ts twoslash
* import { Blobs, Hex } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef')
* const data = Blobs.to(blobs) // [!code focus]
* // @log: '0xdeadbeef'
* ```
*
* @example
* ### Configuring Return Type
*
* It is possible to configure the return type with second argument.
*
* ```ts twoslash
* import { Blobs } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef')
* const data = Blobs.to(blobs, 'Bytes')
* // @log: Uint8Array [ 13, 174, 190, 239 ]
* ```
*
* @param blobs - The {@link ox#Blobs.Blobs} to transform.
* @param to - The type to transform to.
* @returns The originating data.
*/
export function to<
const blobs extends Blobs<Hex.Hex> | Blobs<Bytes.Bytes>,
to extends 'Hex' | 'Bytes' =
| (blobs extends Blobs<Hex.Hex> ? 'Hex' : never)
| (blobs extends Blobs<Bytes.Bytes> ? 'Bytes' : never),
>(
blobs: blobs | Blobs<Hex.Hex> | Blobs<Bytes.Bytes>,
to?: to | 'Hex' | 'Bytes' | undefined,
): to.ReturnType<to> {
const to_ = to ?? (typeof blobs[0] === 'string' ? 'Hex' : 'Bytes')
const blobs_ = (
typeof blobs[0] === 'string'
? blobs.map((x) => Bytes.fromHex(x as Hex.Hex))
: blobs
) as Bytes.Bytes[]
const length = blobs_.reduce((length, blob) => length + blob.length, 0)
const data = Cursor.create(new Uint8Array(length))
let active = true
for (const blob of blobs_) {
const cursor = Cursor.create(blob)
while (active && cursor.position < blob.length) {
// First byte will be a zero 0x00 byte we can skip.
cursor.incrementPosition(1)
let consume = 31
if (blob.length - cursor.position < 31)
consume = blob.length - cursor.position
for (const _ in Array.from({ length: consume })) {
const byte = cursor.readByte()
const isTerminator =
byte === 0x80 && !cursor.inspectBytes(cursor.remaining).includes(0x80)
if (isTerminator) {
active = false
break
}
data.pushByte(byte)
}
}
}
const trimmedData = data.bytes.slice(0, data.position)
return (to_ === 'Hex' ? Hex.fromBytes(trimmedData) : trimmedData) as never
}
export declare namespace to {
type ReturnType<to extends 'Hex' | 'Bytes' = 'Hex'> =
| (to extends 'Bytes' ? Bytes.Bytes : never)
| (to extends 'Hex' ? Hex.Hex : never)
type ErrorType =
| Hex.fromBytes.ErrorType
| Bytes.fromHex.ErrorType
| Cursor.create.ErrorType
| Errors.GlobalErrorType
}
/**
* Transforms Ox-shaped {@link ox#Blobs.Blobs} into the originating data.
*
* @example
* ```ts twoslash
* import { Blobs, Hex } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef')
* const data = Blobs.toHex(blobs) // [!code focus]
* // @log: '0xdeadbeef'
* ```
*/
export function toHex(
blobs: Blobs<Hex.Hex> | Blobs<Bytes.Bytes>,
): toHex.ReturnType {
return to(blobs, 'Hex')
}
export declare namespace toHex {
type ReturnType = to.ReturnType<'Hex'>
type ErrorType = to.ErrorType | Errors.GlobalErrorType
}
/**
* Transforms Ox-shaped {@link ox#Blobs.Blobs} into the originating data.
*
* @example
* ```ts
* import { Blobs, Hex } from 'ox'
*
* const blobs = Blobs.from('0xdeadbeef')
* const data = Blobs.toBytes(blobs) // [!code focus]
* // @log: Uint8Array [ 13, 174, 190, 239 ]
* ```
*/
export function toBytes(
blobs: Blobs<Hex.Hex> | Blobs<Bytes.Bytes>,
): toBytes.ReturnType {
return to(blobs, 'Bytes')
}
/**
* Compute commitments from a list of {@link ox#Blobs.Blobs}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, { kzg }) // [!code focus]
* ```
*
* @example
* ### Configuring Return Type
*
* It is possible to configure the return type with the `as` option.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, {
* as: 'Bytes', // [!code focus]
* kzg,
* })
* // @log: [Uint8Array [ ... ], Uint8Array [ ... ]]
* ```
*
* @param blobs - The {@link ox#Blobs.Blobs} to transform to commitments.
* @param options - Options.
* @returns The commitments.
*/
export function toCommitments<
const blobs extends Blobs<Bytes.Bytes> | Blobs<Hex.Hex>,
as extends 'Hex' | 'Bytes' =
| (blobs extends Blobs<Hex.Hex> ? 'Hex' : never)
| (blobs extends Blobs<Bytes.Bytes> ? 'Bytes' : never),
>(
blobs: blobs | Blobs<Bytes.Bytes> | Blobs<Hex.Hex>,
options: toCommitments.Options<as>,
): toCommitments.ReturnType<as> {
const { kzg } = options
const as = options.as ?? (typeof blobs[0] === 'string' ? 'Hex' : 'Bytes')
const blobs_ = (
typeof blobs[0] === 'string'
? blobs.map((x) => Bytes.fromHex(x as any))
: blobs
) as Bytes.Bytes[]
const commitments: Bytes.Bytes[] = []
for (const blob of blobs_)
commitments.push(Uint8Array.from(kzg.blobToKzgCommitment(blob)))
return (
as === 'Bytes' ? commitments : commitments.map((x) => Hex.fromBytes(x))
) as never
}
export declare namespace toCommitments {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
/** KZG implementation. */
kzg: Pick<Kzg.Kzg, 'blobToKzgCommitment'>
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex'> = Compute<
| (as extends 'Bytes' ? readonly Bytes.Bytes[] : never)
| (as extends 'Hex' ? readonly Hex.Hex[] : never)
>
type ErrorType =
| Bytes.fromHex.ErrorType
| Hex.fromBytes.ErrorType
| Errors.GlobalErrorType
}
export declare namespace toBytes {
type ReturnType = to.ReturnType<'Bytes'>
type ErrorType = to.ErrorType | Errors.GlobalErrorType
}
/**
* Compute the proofs for a list of {@link ox#Blobs.Blobs} and their commitments.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'viem'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, { kzg })
* const proofs = Blobs.toProofs(blobs, { commitments, kzg }) // [!code focus]
* ```
*
* @param blobs - The {@link ox#Blobs.Blobs} to compute proofs for.
* @param options - Options.
* @returns The Blob proofs.
*/
export function toProofs<
const blobs extends readonly Bytes.Bytes[] | readonly Hex.Hex[],
const commitments extends readonly Bytes.Bytes[] | readonly Hex.Hex[],
as extends 'Hex' | 'Bytes' =
| (blobs extends readonly Hex.Hex[] ? 'Hex' : never)
| (blobs extends readonly Bytes.Bytes[] ? 'Bytes' : never),
>(
blobs: blobs | Blobs<Bytes.Bytes> | Blobs<Hex.Hex>,
options: toProofs.Options<blobs, commitments, as>,
): toProofs.ReturnType<as> {
const { kzg } = options
const as = options.as ?? (typeof blobs[0] === 'string' ? 'Hex' : 'Bytes')
const blobs_ = (
typeof blobs[0] === 'string'
? blobs.map((x) => Bytes.fromHex(x as any))
: blobs
) as Bytes.Bytes[]
const commitments = (
typeof options.commitments[0] === 'string'
? options.commitments.map((x) => Bytes.fromHex(x as any))
: options.commitments
) as Bytes.Bytes[]
const proofs: Bytes.Bytes[] = []
for (let i = 0; i < blobs_.length; i++) {
const blob = blobs_[i]!
const commitment = commitments[i]!
proofs.push(Uint8Array.from(kzg.computeBlobKzgProof(blob, commitment)))
}
return (
as === 'Bytes' ? proofs : proofs.map((x) => Hex.fromBytes(x))
) as never
}
export declare namespace toProofs {
type Options<
blobs extends Blobs<Bytes.Bytes> | Blobs<Hex.Hex> =
| Blobs<Bytes.Bytes>
| Blobs<Hex.Hex>,
commitments extends readonly Bytes.Bytes[] | readonly Hex.Hex[] =
| readonly Bytes.Bytes[]
| readonly Hex.Hex[],
as extends 'Hex' | 'Bytes' =
| (blobs extends Blobs<Hex.Hex> ? 'Hex' : never)
| (blobs extends Blobs<Bytes.Bytes> ? 'Bytes' : never),
> = {
/** Commitments for the blobs. */
commitments: (commitments | readonly Bytes.Bytes[] | readonly Hex.Hex[]) &
(commitments extends blobs
? {}
: `commitments must be the same type as blobs`)
/** KZG implementation. */
kzg: Pick<Kzg.Kzg, 'computeBlobKzgProof'>
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex' | 'Bytes'> =
| (as extends 'Bytes' ? readonly Bytes.Bytes[] : never)
| (as extends 'Hex' ? readonly Hex.Hex[] : never)
type ErrorType =
| Hex.fromBytes.ErrorType
| Bytes.fromHex.ErrorType
| Errors.GlobalErrorType
}
/**
* Transforms {@link ox#Blobs.Blobs} into a {@link ox#Blobs.BlobSidecars} array.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const sidecars = Blobs.toSidecars(blobs, { kzg }) // [!code focus]
* ```
*
* @example
* You can also provide your own commitments and proofs if you do not want `toSidecars`
* to compute them.
*
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const commitments = Blobs.toCommitments(blobs, { kzg })
* const proofs = Blobs.toProofs(blobs, { commitments, kzg })
*
* const sidecars = Blobs.toSidecars(blobs, { commitments, kzg, proofs }) // [!code focus]
* ```
*
* @param blobs - The {@link ox#Blobs.Blobs} to transform into {@link ox#Blobs.BlobSidecars}.
* @param options - Options.
* @returns The {@link ox#Blobs.BlobSidecars}.
*/
export function toSidecars<
const blobs extends Blobs<Hex.Hex> | Blobs<Bytes.Bytes>,
>(
blobs: blobs,
options: toSidecars.Options<blobs>,
): toSidecars.ReturnType<blobs> {
const { kzg } = options
const commitments = options.commitments ?? toCommitments(blobs, { kzg: kzg! })
const proofs =
options.proofs ??
toProofs(blobs, { commitments: commitments as any, kzg: kzg! })
const sidecars: Mutable<BlobSidecars> = []
for (let i = 0; i < blobs.length; i++)
sidecars.push({
blob: blobs[i]!,
commitment: commitments[i]!,
proof: proofs[i]!,
})
return sidecars as never
}
export declare namespace toSidecars {
type Options<
blobs extends Blobs<Hex.Hex> | Blobs<Bytes.Bytes> =
| Blobs<Hex.Hex>
| Blobs<Bytes.Bytes>,
> = {
kzg?: Kzg.Kzg | undefined
} & OneOf<
| {}
| {
/** Commitment for each blob. */
commitments: blobs | readonly Hex.Hex[] | readonly Bytes.Bytes[]
/** Proof for each blob. */
proofs: blobs | readonly Hex.Hex[] | readonly Bytes.Bytes[]
}
>
type ReturnType<blobs extends Blobs<Hex.Hex> | Blobs<Bytes.Bytes>> =
UnionCompute<
| (blobs extends Blobs<Hex.Hex> ? BlobSidecars<Hex.Hex> : never)
| (blobs extends Blobs<Bytes.Bytes> ? BlobSidecars<Bytes.Bytes> : never)
>
type ErrorType = Errors.GlobalErrorType
}
/**
* Compute Blob Versioned Hashes from a list of {@link ox#Blobs.Blobs}.
*
* @example
* ```ts twoslash
* // @noErrors
* import { Blobs } from 'ox'
* import { kzg } from './kzg'
*
* const blobs = Blobs.from('0xdeadbeef')
* const versionedHashes = Blobs.toVersionedHashes(blobs, { kzg }) // [!code focus]
* ```
*
* @param blobs - The {@link ox#Blobs.Blobs} to transform into Blob Versioned Hashes.
* @param options - Options.
* @returns The Blob Versioned Hashes.
*/
export function toVersionedHashes<
const blobs extends Blobs<Bytes.Bytes> | Blobs<Hex.Hex>,
as extends 'Hex' | 'Bytes' =
| (blobs extends Blobs<Hex.Hex> ? 'Hex' : never)
| (blobs extends Blobs<Bytes.Bytes> ? 'Bytes' : never),
>(
blobs: blobs | Blobs<Bytes.Bytes> | Blobs<Hex.Hex>,
options: toVersionedHashes.Options<as>,
): toVersionedHashes.ReturnType<as> {
const commitments = toCommitments(blobs, options)
return commitmentsToVersionedHashes(commitments, options)
}
export declare namespace toVersionedHashes {
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
/** KZG implementation. */
kzg: Pick<Kzg.Kzg, 'blobToKzgCommitment'>
/** Return type. */
as?: as | 'Hex' | 'Bytes' | undefined
}
type ReturnType<as extends 'Hex' | 'Bytes' = 'Hex'> = Compute<
| (as extends 'Bytes' ? readonly Bytes.Bytes[] : never)
| (as extends 'Hex' ? readonly Hex.Hex[] : never)
>
type ErrorType =
| toCommitments.ErrorType
| commitmentsToVersionedHashes.ErrorType
| Errors.GlobalErrorType
}
/** A list of {@link ox#Blobs.BlobSidecar}. */
export type BlobSidecars<
type extends Hex.Hex | Bytes.Bytes = Hex.Hex | Bytes.Bytes,
> = readonly Compute<BlobSidecar<type>>[]
/** Thrown when the blob size is too large. */
export class BlobSizeTooLargeError extends Errors.BaseError {
override readonly name = 'Blobs.BlobSizeTooLargeError'
constructor({ maxSize, size }: { maxSize: number; size: number }) {
super('Blob size is too large.', {
metaMessages: [`Max: ${maxSize} bytes`, `Given: ${size} bytes`],
})
}
}
/** Thrown when the blob is empty. */
export class EmptyBlobError extends Errors.BaseError {
override readonly name = 'Blobs.EmptyBlobError'
constructor() {
super('Blob data must not be empty.')
}
}
/** Thrown when the blob versioned hashes are empty. */
export class EmptyBlobVersionedHashesError extends Errors.BaseError {
override readonly name = 'Blobs.EmptyBlobVersionedHashesError'
constructor() {
super('Blob versioned hashes must not be empty.')
}
}
/** Thrown when the blob versioned hash size is invalid. */
export class InvalidVersionedHashSizeError extends Errors.BaseError {
override readonly name = 'Blobs.InvalidVersionedHashSizeError'
constructor({
hash,
size,
}: {
hash: Hex.Hex
size: number
}) {
super(`Versioned hash "${hash}" size is invalid.`, {
metaMessages: ['Expected: 32', `Received: ${size}`],
})
}
}
/** Thrown when the blob versioned hash version is invalid. */
export class InvalidVersionedHashVersionError extends Errors.BaseError {
override readonly name = 'Blobs.InvalidVersionedHashVersionError'
constructor({
hash,
version,
}: {
hash: Hex.Hex
version: number
}) {
super(`Versioned hash "${hash}" version is invalid.`, {
metaMessages: [
`Expected: ${Kzg.versionedHashVersion}`,
`Received: ${version}`,
],
})
}
}